【プログラミング】プロはどうやってコードを書いているか? 自分のコーディング手法を紹介してみる

f:id:orchid-bell:20181212001936j:plain

プログラム入門書の練習問題とは違い、実践的なプログラムになると考えなくてはいけないことが一気に増えます。

「まずはこれをこうして、この時はこうなって、でもこうしちゃうとこっちの値が変わっちゃうから、この条件の時は変えないようにして……うーん、わからん」みたいに頭がこんがらがる人は多いと思います。

今回はプロがどうやってプログラムを組み上げているのか、一例として私のコーディング手法を紹介したいと思います。

 

初心者にありがちなコードの組み方

私のコーディング手法の前にプログラミング初心者がやりがちなコーディングを考えてみたいと思います。

私が思う初心者っぽいコードと言えば、こんな感じのコードです。

public class AAA(){
  int array1[10];
  int array2[10];

  // 初期化処理
  public init(){
    // 配列1を1で初期化する
    for(int i=0;i<10;i++){
      array1[i] = 1;
    }
    // 配列2の初期化
      array2_init();
    }

    // 配列2を2で初期化する
    private array_init(){
      for(int i=0;i<10;i++){
        array2[i] = 2;
      }
    }
}

配列を初期化する処理ですが、1つ目の配列はinit()で直接やっているのに対し、2つ目の配列はプライベートメソッドを用意してその中でやっています。似たような処理なのにレベルが統一されてないですね。

こういうコードを書いてしまう人の多くは、以下のような流れでコードを組んでいると思います。

  1. 「このクラスには配列が必要だから、初期化メソッドで初期化しよう」
  2. 「あれ? もう一つ配列ないとうまく動かないな」
  3. 「もう一つ配列を追加しよう。初期化メソッドに忘れないように入れよう」
  4. 「あ、こっちの配列はループの終わりで毎回初期化しないとダメだ」
  5. 「メソッド化して再利用できるようにしておこう」→ array_init()の誕生

行き当たりばったり感がすごいですね。

これは小さいコードなので、コードの不自然さが際立って分かりやすいと思いますが、実際にはもっと長々とした思考過程を経てここにたどり着くので、不自然さに気づけなくなっていきます。仮に気づいたとしても修正の労力を考えるとげんなりしてしまって、「まあいっか」となりがちです。

ドミノをまっすぐに並べたつもりだけど、顔を上げてみたらグネグネ曲がっていた、なんて経験ありませんか? この考え方はそれに似ています。

ドミノをまっすぐ並べることに集中した結果、全体がまっすぐにならなかったように、コードを書く作業に集中すると、全体構成のチェックがおろそかになります。

その結果としてつじつまが合わない箇所が出てきて、整合性を取るためのフラグや定義値、計算式などが必要になってきて、全体の構成がさらに歪んでいく、という悪循環になりがちです。

 

設計がちゃんとしていれば大丈夫か?

このようになってしまうのは、「コードを書く前にちゃんと設計しない方が悪い」と思うでしょうか? 個人的にはその考えには半分だけ賛同です。

設計にもレベルがあり、大きくは基本設計と詳細設計に分かれます。

基本設計はシステムの全体構成を表す設計であるのに対し、詳細設計はプログラムに近いレベルの設計になります。

さらに詳細設計にもレベルがあり、クラス図のような機能レベルの設計、シーケンス図のような処理レベルの設計、さらにコードに近いレベルのフローチャートと徐々に細かくなっていきます。

「半分だけ賛同する」というのは、設計行為がフローチャートレベルまで行われているなら、コードが汚くなるのは設計が悪いと言っても良いと思うからです。

しかし、実際には納期や工数の兼ね合いからフローチャートレベルの設計書を書くことは少ないです。多くの開発現場ではクラス図レベルか、がんばってシーケンス図レベルで設計フェーズが終了し、そこから先はプログラミング工程となります。

細かく設計しないSEが悪いのか、意図を読み取れないプログラマーが悪いのかは意見が分かれるところだと思いますが、少なくともプログラミングする上での細かいレベルの設計余地が残っているのが現実です。

 

プロのコーディング手法

私のコードの組み方ですが、上述の設計余地があることを前提にコーディングしていきます。

上述の配列初期化の処理を例に解説します。

  1. 「このクラスには配列が必要だから、初期化メソッドで初期化しよう」

    public class AAA(){
      int array1[10];

      // 初期化処理
      public init(){
        // array1を初期化
      }

  2. 「あれ? もう一つ配列がないとうまく動かないな。もう一つ配列を追加しよう。初期化メソッドに忘れないように入れよう」

    public class AAA(){
      int array1[10];
      int array2[10];

      // 初期化処理
      public init(){
        // array1を初期化
        // array2を初期化
      }
    }

  3. 「あ、こっちの配列はループの終わりで毎回初期化しないとダメだ」

    public class AAA(){
      int array1[10];
      int array2[10];

      // 初期化処理
      public init(){
        // array1を初期化
        // array2を初期化
      }

      // array2の初期化メソッド
    }

  4. 「似たような初期化処理はまとめられそうだな」

    public class AAA(){
      int array1[10];
      int array2[10];

      // 初期化処理
      public void init(){
        // 初期化(array1, 1);
        // 初期化(array2, 2);
      }

      // 配列の初期化メソッド(配列, 初期値)(privateで用意)
    }

誤解しないのでいただきたいのですが、ブログ用に処理を省略したわけではありません。本当にこの記載通り、やることをコメントでただメモっていくだけです

最初にコードは書かず、こうしてざっくりと全体の流れを整理し、流れが決まったらコメントで記載した部分を実際のコードに置き換えていく作業をしています。

この手法のメリットは、コードを組まない分、行数があまり増えないので全体を俯瞰しやすく流れを整理しやすいことです。また、コメントなので言葉を変えるだけ処理が変更できるため、気軽に構成をいじくりまわせます。

 

これは適当な処理単位を適当なコメントで1行にまとめるという、抽象的思考の考え方を使っています。この考え方をさらに上流工程に向けて抽象化していくと、それは設計行為になっていきます。

コードレベルでこのように考えることが、プログラミングだけでなくシステム設計のための訓練にもなるのかなと思います。

 

まとめ

いかがでしたでしょうか?

コードを俯瞰してみるために、コメントで処理の流れを記述するという手法をご紹介してみました。

人によって思考回路は違うので私のやり方が合うかは分かりませんが、何かの参考になればうれしいです。