質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

5回答

3558閲覧

できるだけ同じ処理は関数化したほうが良いと言いますが、間に非共通のソースがある場合も関数化しますか?

退会済みユーザー

退会済みユーザー

総合スコア0

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

6クリップ

投稿2018/02/18 02:41

できるだけ同じ処理は関数化したほうが良いと言いますが、間に非共通のソースがある場合も関数化しますか?

例えば下記のような場合は2つ共通の部分のみ関数化して2つの関数を呼ばないといけないですよね。
共通
非共通
共通
非共通
共通

逆にややこしくて管理しにくいように感じるのですが、これでも無理に関数化すべきなのでしょうか?

また、そうだったとしても共通のソースが5行以上であればまだわかるのですが、3行以内の場合はどうでしょうか?
それくらいなら全く同じ処理でもさすがにコピペしますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ぶっちゃけTPOです。
コードは、機械が逐次処理をしていく命令文の羅列であると同時に、人間が読んで修正するべき文章です。
この後者の部分は意識してください。

質問文の共通、非共通と並んでいる箇所ですが、
文章として読んだ時にそれが最も自然でシンプルなあるべき姿なのでしょうか?
もしYesと言い切れるのなら変える必要はありません。

ですが……そのコードは自然でシンプルなのですか?本当に?何を根拠に言ってるの?
こういう風に詰められるとだんだん不安になってきますね。

どうすれば良いかの勘所はリーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニックという書籍を読めば身につきます。
どんなにロジカル人のコードでもこれを読んでない人のコードは品質がバラツキます。
この書籍を読んだ人のコードはとても読みやすく、共通部品を取り出すとはなんなのかが分かりますので、長いエンジニア人生で一番役に立つ書籍となるだろうと言っても過言ではありません。
ただし序盤はともかく終盤は難解ですので、まずは読める範囲までで良いので繰り返し読んでくださいね。


さて、上記前提を元に今回の質問文を更に掘り下げていきます。

質問文を見返すと、「共通・非共通・共通・非共通・共通」となってますね。
1行1行の処理に着目しすぎのように思えます。

オブジェクト指向プログラミングで解決出来そうなので、
少しチュートリアル的なモノを次の章で記載します。


まず、オブジェクト指向に限らず、プログラミングに於いては以下の流れを守ってください。

  1. 入力(必要な情報の収集) + 加工(入力値を処理しやすくする)
  2. 処理
  3. 出力(結果を画面なりファイルなりへ書き出す)

この一連の流れは全てが終わるまで、絶対に次へ行かないでください。
質問文のコードが「共通・非共通・共通・非共通・共通」の流れになってしまうのは、
殆どのケースに於いて1→3の流れを守れずに小出しにしているからです。

また「少しの情報を受け取って処理することを繰り返す」のも、
「全ての情報を受け取ってまとめて処理する」のも全体的な処理時間は変わりません。
例外が出たらその時はその時で悩んでください。


次にコードに対して大まかな名前を付けてください。
まずゴール(あるべき姿)はなんですか?そのまま名称にして、クラス名や関数名として利用できます。

達成条件も箇条書きにしてください。
これらの達成条件も個別に関数名やクラスのメソッド名等に使えます。
また、達成条件は「どんなケースでも達成しなければならないのでしょうか?」
「スイッチをONにした時だけ達成出来れば良いのですか?」なども予め考えて置くと捗ります。


ここでやってオブジェクト指向プログラミングのターンです。

情報の収集・加工が済んだら処理に必要なデータを、クラスに投げ込んでインスタンスを作ってください。
別の処理を挟みたいなら、オプショナルな条件のメソッドを用意してONにするようにしてください。
全てのデータを投げ込み終わったら、作ったインスタンスのstartメソッドを叩いて結果を待ちましょう。


この流れで統一するようにすれば、
何をまとめられそうか、何をまとめるのが無理そうかが一目で区別出来るようになってきます。

最初は何千行もの神クラスを作り込んだりして酷いコードになると思います。
オブジェクト指向プログラミングの腕が上がってくれば、比例して読みやすく抽象化された素晴らしいコードが書けるようになるはずです。

例えばDIコンテナという、ある程度の情報を格納しておいたインスタンスをプロパティとして保存するテクニックがあります。
これ使えればかっこいいプログラミングが出来るようになりますよ。
ファイルの出力先を覚えこませたロガーとか、MySQLのサーバーに接続済みのコネクションとか…

DIコンテナを駆使すれば移譲するという手が使えるようになるので、
計算を実行するクラスがMySQLサーバーに接続しにいって、ログファイルを決め打ちのパスに書き出し始めるといった
「私って○○の目的で作られたなのに、別のおまじないばかり…なにやってんだろ?」というケースを回避出来るようになります。


オブジェクト指向で良い本は思いつきませんでした。
色んなサイトを見たりコードを書いた後にオブジェクト指向と10年戦ってわかったこと - Qiitaの記事を読んでください。
記事のカプセル化の項目に「正しい名前をつけることが大切」と語られていますが、オブジェクト指向プログラミングをする上で、リーダブルコードの知識は確実に活きます。

少し長くなりましたが以上です。何かしら役に立てば幸いです。

投稿2018/02/18 04:50

編集2018/02/18 05:20
miyabi-sun

総合スコア21400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/18 09:18

ありがとうございます。 やはり2行程度のソースもなんでも関数化して共通にすればよいという考えではないのですね。 むしろ他に影響を与えたりしてわかりにくくなる恐れがあるので、まとまった5行以上で間に共通化できないものがないときのみ共通化するくらいがよさそうですね。 ちょっと難しくてなかなか理解できそうになりですが
miyabi-sun

2018/02/18 09:39

例え1行だとしても外出しするべき場面と言うのもあります。 「その処理に名前が付けられるのか」ということです 例えば`y = x + 5`というコードがあったとしましょう。 見りゃ分かるじゃん5を足してるんだよね? ……そうではなく、何故こんな事をしなければならなかったのかにスポットを当てて考えてください。 例えばの理由として、このシステムでは沢山の入力値を処理して記憶していくが、たまに不具合でいきなり大きな数字が飛んでくるので一定以上の値が飛んできたらノイズとして弾きたいという意図が隠れているケースがあります。 だったら変数名はyではなくlimitやmaxみたいな一目でこれ以上の値はダメと分かる名前にしないといけないよね?とか、maxOfみたいな関数を作って何時でも+5された限界値の数値を取り出せるようにしておけばいいよね? …といった風に分かりやすくする為にどうすれば良いか考える事ができます。
miyabi-sun

2018/02/18 09:47

世の中には後で読みやすくする為に、 ガチの英文として読めるように書いていこうと試行錯誤している人も居たりします。 How to write a code like English(英文のようにプログラミングをする方法) http://futurismo.biz/archives/2326 関数の切り出し方ってのは実際にやって慣れるしかない部分もあります。 まずは色々関数やサブルーチンを作ってみて、 後から読み返して読みやすい!って思えるコードを模索してみてください。
退会済みユーザー

退会済みユーザー

2018/02/18 12:19

こういったものは、名前が全てって感じありますよね。 いつもネーミングで時間とられちゃいます。 実感するには、リファクタリングを何回か重ねてみるしか無い気もしますし、伝えるの難しいですね^^;
guest

0

文脈的に少し外れた内容かもしれませんが・・・
DRY(Don't Repeat Yourself)でヒットするいくつかのページを眺めてみることも有用な気がしました。例えば

qiita: あなたはDRY原則を誤認している?

POSTD: DRYと不当な抽象化によるコストについて

など、「どんなとき良くて、どんなとき良くないか」について考えさせられます。

前者の記事は「コードの重複じゃなく設計の重複を避けるのが本質」とか「共通化により結合度が不当に高くなる危険がある」という点が有用と感じました。後者の記事は「共通化によるコストと共通化しないことによるコストを天秤にかけて選択しよう」みたいなことが書いてありますが

  • その判断をなるべく的確にしたいところだがそれは単純ではなさそう
  • でもそういう点を意識しておくことは有用なはず

みたいなことを思いました。きっと経験あるプログラマーの方は「より明確な自分自信のポリシー」をお持ちではないかと思います。

残念ながらナンチャッテアマチュアプログラマーの自分は普段から間違った判断をしまくりな気がします。ともすれば共通化をやりすぎてしまうのです。その是非は設計中は気づけないことが多いのですが時間が経ってから見直すと気づくことがままあります。変に共通化しすぎて全然わかりやすくない(変更がやりにくい)と感じることもあれば、適度に分かり易くなっていると感じることもあります。

投稿2018/02/18 03:40

編集2018/02/18 03:41
KSwordOfHaste

総合スコア18404

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/18 09:18

ありがとうございます。 やはり2行程度のソースもなんでも関数化して共通にすればよいという考えではないのですね。 むしろ他に影響を与えたりしてわかりにくくなる恐れがあるので、まとまった5行以上で間に共通化できないものがないときのみ共通化するくらいがよさそうですね。
KSwordOfHaste

2018/02/18 09:43

行数の多寡や違う部分がどういうパターンかなどは判断の要因にはなるでしょうが、それらは要因の一部だと思います。たった3行のちょっと違う内容を含む処理でも「特定の処理群を一定のルールに従わせたい」といった目的があるなら共通化する意味はあるでしょうし、内容が同一の10行の処理があったとしても一致は「たまたま」であって、共通化すると不必要な制約を設計に混入する(つまり改悪になる)こともあるだろうと思います。 miyabi-sunさんが最初におっしゃっているように「TPOによる」という言葉が一番しっくりきそうです。
guest

0

共通部分の処理内容によります。
個人的にはテスト/デバックしやすいかどうかで分けることが多いかと。
関数化して重複行を減らすという観点も良いのですが、
コードの可読性やテスト容易性も重要だと個人的に思ってます。

投稿2018/02/19 22:02

umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/20 10:01

関数化して重複行を減らす事が最優先では全くなくむしろよみずらくなるなら関数化しない方がいいのですね
guest

0

ベストアンサー

具体的なソースを見て判断すべき問題ですがほとんどの場合は、
分離できスッキリ書くことができます。

とは言え処理が同じ場合よりも、意味合いが同じ場合に共通化をする必要があります。(意味合いが同じ場合おのずと同じ処理になることが多い程度に考えた方が良いです。)逆に意味合いが遠いので、共通化する必要がない場合もあります。

場合によっては関数を引数に持たせることで対応は可能ですが、何らかのクラスの導入をすれば解決できる場合がほどんどです。

非共通の処理は共通の処理の前処理か後処理の場合がほどんどです。(”処理”多すぎ・・・)
その場合は、非共通の処理をしているのは、サブクラスとして定義した方が良いかもしれません。

もし、前処理でも後処理でもない場合は、移動か可能か別のメソッドで処理すべきものである可能性が高いです。

投稿2018/02/18 11:49

iwamoto_takaaki

総合スコア2884

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/19 02:48

ありがとうございます。 やはり前半か後半すべてが共通の場合でかつ同じ意味合いの場合のみ関数ないしはクラスかするという事ですね。 間だけ共通だったり共通部分が飛び飛びだったり、処理が共通だが意味合いが違う場合は、共通化しない方が良いのですね。 ところで初心者なので意味合いが同じという部分がよくわからないのですが、ソースは全く同じでも意味合いが違うとはどんな場合なのでしょうか?
iwamoto_takaaki

2018/02/19 04:07

> やはり前半か後半すべてが共通の場合でかつ同じ意味合いの場合のみ関数ないしはクラスかするという事ですね。 違います。意味合いが同じなら、処理が違っても構いません。 例を使って説明すると  処理1(共通  処理1の後処理(非共通  処理2(共通  処理3の前処理(非共通  処理3 となっている場合で考えます。 親クラスの呼び出しは処理1・処理2・処理3をそれぞれメソッドとして登録し、呼び出すように記述します。 派生クラスの処理1には親クラスの共通処理と独自の後処理が記述してあります。派生クラスに処理3には独自の前処理と親クラスの共通処理を記述します。さらには、親クラスの処理を呼び出さずまったく独自の処理を記述することも可能です。 こうすると、派生クラスは非共通の処理を差し込む事ができます。このような方法はオブジェクト指向でよく使われるテクニックなので、よく判らなければデザインパターン関連の学習をするとよいかもしれません。 具体的なコードを示してもらえればもう少しわかりやすく説明できるとおもいます。 > ところで初心者なので意味合いが同じという部分がよくわからないのですが、ソースは全く同じでも意味合いが違うとはどんな場合なのでしょうか? KSwordOfHasteさんが貼ったリンク、”あなたはDRY原則を誤認している?”に分かりやすい例があります。
退会済みユーザー

退会済みユーザー

2018/02/19 04:13

わかりました。まずそちらの記事を見てからご返信します。
guest

0

具体的にどうするのかは場合によって違うと思いますが、ラムダ式でうまくいくかもしれません。

投稿2018/02/18 02:48

Zuishin

総合スコア28673

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問