Help us understand the problem. What is going on with this article?

良いコードを書く技術(まとめ)

大学の図書館にて”良いコードを書く技術”という本があったので、
感想とともに自分の体験などを交えて偉そうに話していこうと思う。本の全ては扱っていません。
※また章の順番も一部変えています。


目次

 1章 良いコードとはなにか
 2章 良いコードを書くための5つの習慣
 3章 名前付け
 4章 スコープ
 5章 コードの分割
 6章 コードの集約化


まず良いコードとはなんだろうか?

例えば宿題で書くコードを例にしたら、課題だから答えがあって、求められているものをクリアすることを優先すると思う。そんなの誰だってそうなので当たり前だ。なのでコメントも殆ど書かないし。読んでもらう相手は先生なので分かってくれるだろうと思って書いている。
私も普段から気をつけたいと思っているが、注意すると良いポイントは読む相手のことを考えることだと思う。他の本を見ると難しいことが書いている。でも重要な事は読み手を意識することだと思う。
一ヶ月先の自分は他人!!

未来の自分に向けて読みやすいコードを書こう!!

では次を例にする
プログラムは適当だが、モードを選択してもらうためaを入力してもらう
その後客の名前を入力すると感謝メッセージを表示するというもの

sample.c
#include <stdio.h>

int main(){
  char c;
  c=getchar();
  char melon[100];

  if(c=='a'){
    printf("Input your name!: \n");
    scanf("%s",&melon);
    printf("Thank you!%s\n",melon);
  }else{
    ungetc(c,stdin);
    printf("input_a!!");
  }
  return 0;
}
sample2.c
#include <stdio.h>

int main(){
  char mode;
  mode=getchar();
  char customerName[100];
  //モードaを選択後、客の名前を入力
  if(mode=='a'){
    printf("Input your name!: \n");
    scanf("%s",&customerName);
    //お礼のメッセージを表示して終了
    printf("Thank you!%s\n",customerName);
  }else{
   //モードa以外だとaという入力を促す
    ungetc(mode,stdin);
    printf("input_a!!");
  }
  return 0;
}

第一章

さてどちらが良いコードだろう?読みやすいだろう?
最初の方といった人はよっぽど言語理解力がないのだろう。

というのはさて置き説明としては
まず変数名である。学校では変数名は好きなもので良いと教わるだろう。(教わったと仮定する。)だから普段から果物が好きな貴方は変数名にmelon,banana,appleとかと付けているのだろう

さて、これは正しいのか?答えは間違いなく失敗例である。お客様が使うシステムだったであった場合にmelonという変数名を他のプログラマが見たら一瞬で理解できないだろう。

変数名は多少長くても理解しやすいようにしたほうが絶対良い。
なぜ変数名をつけれるかを考えよう!
変数名の付け方はとてもむずかしいのでhogehogeとかにしてしまいがちだが、ちゃんと意味の理解できるものにしておけば将来自分のコードを見なおしたときにもかなり役に立つ。更には他人が見ても一目でどういうプログラムなのかひと目で分かるそういうものにして欲しい。

変数名は愛情!
sizeとかgetとかnumberという感じに変数名を無心に決めたとしよう。それでもよくよく考えると全く情報が伝わらないこともある。
いかに相手のことを愛することができるかということ!!
単にsizeでは何のサイズ?文字の個数?画像の個数?ファイルの大きさ?それが伝わらない。numberも同様ににint number;で宣言していたとしたらint型は整数が入るに決まっているし、よっぽど愛が変数名だ!
もっと計算機の表示するところの数字を表すならResultNumberとかにするとかもっと方法がある。
ResultNumberとnumberだと情報量が全くと言っていいほど違う。
変数名を上手につけることができ始めてからがプログラムと言っていい!!

第二章

良いコードを書くための5つの習慣

習慣その1 読む

コードを読んで読みまくれ!!
慣れない言語で本を見ながら調べながら書いていると、不必要な行や、変な書き方になってしまいがちです。Githubに公開されている自分の作っているものに似たプロジェクトを見てコードを読みましょう。

今はもうGithubでいいと思います。

あとはGithubのTrendを毎日見とくとかでしょうか。
※時代の流れに逆らった偏屈なプログラマになってはいけません!
https://github.com/trending

習慣その2 書く

とにかくコードを書きましょう

自分でツールを作ったり、普段からコードを書きまくると言いということが良いということが書かれている。語るよりも書くことが重要!(自分にもこれを言いたい・・・)

習慣その3 道具を磨く

使う道具は常に磨いておこう

メモ帳でコードを書くのとIDEで書くのとではかなりの差がある。
メモ帳を使いこなしてそれが一番短時間で書けるという場合はそれでもいいと思う。
エディタを洗練されたものを使うだけでも作業効率が格段に上がります。
別にvimやemacsを使うことだけが答えじゃないと思うので、日々の作業をどうすれば効率化できるかを考えてみるといいと思う。

習慣その4 知る

良い知識をつけよう

まずは原典(その技術の根幹本)とHow To本の二冊を入手する。
私はブラッディ・マンデイ世代でみゆっきとプログラミングを始めた理由と本が同じで世代も同じです。
その一番最初の本は猫でもわかるC言語プログラミングという本です。
作者の粂井康孝は僕と同じ北海道生まれです。(なんでも共通点を探してしまう。。。)
猫が好きらしくそこも同じなのでいいですね!サイトでも詳しくプログラミングを解説しているので訪問してください!
http://www.kumei.jp/c_lang/

話を元に戻すと私は猫でもわかるという本を読んでかなり分かりやすくて大体理解して進めたのですが、初心者に向けてのものでポインタのとこで挫折してしまいました。

それは当たり前なのです。ポインタという考え自体あなたにも私にも無かったからです。新しい知識を噛み砕いて覚えるということは不可能なのです。できたとしても曖昧にしか覚えられません。
まずはポインタとはどういう考え方なのか、理論なのかを知っていないといつまで経っても理解できないのです。番地で説明されても初心者には何故番地なのかということは意味分かりません。
記憶媒体の保存形式など前提となる知識を分かっていないとダメなのです。そのために原典は必要不可欠なのです。苦しんで覚えたことが結局血と肉となるのです。

習慣その5 聞く(教える)

アウトプットと人からのフィードバックでさらなる成長を

まずは隣の人に教えよう!!

記憶の定着度は以下のように言われている!

聞く(10%)
見る(15%)
聞く&見る(20%)
話し合う(40%)
体験する(80%)
教える(90%)

※出典: メラビアンの法則

みんなは聞く、見るだけで終わってはいないだろうか?
まず話し合ったり、教え合うことから始めましょう!

まずは本に書いていることとして

教えるためには120%理解していなければならず、抽象的な概念から具体的な概念まで一瞬で思いつくぐらいでなければなりません。(理想としてはね)
教える人がいないという状況もあると思うので、そのときは相手がいると想定して考えればいいですね。

コードレビューを受ける

書籍や記事の執筆では、荒削りな段階の現行を他人がチェックして、より良い記事にしていく、「校正作業」というすばらしいプロセスが用意されています。校正作業により「自分以外の誰か」に診てもらうことで良い原稿へと近づいていきます。
コードも同じです。公式・非公式を問わず、自分の書いたコードを自分以外の誰かにコードレビューしてもらうことで、自分では気づかなかったフィードバックがもらえます。コードレビューを通してコードが良くなるのはもちろんですが、自分やレビュアが気づきを得て成長できます。
コードを公開する場として最近注目を集めているのが、ソーシャルなソースコードリポジトリのGitHubです。GitHubで自分のコードを公開すると、他人がコメントやフォーク(コードを引用して分岐すること)を行うことができるので、ダイレクトな反応が得られます。公開されている他人のコードを自由に読むこともできるので、コールドリーディングの面からもお勧めです。
(著者 引用)

第三章 名前付け

実際に作者の本を読んで欲しいのですが、要点だけ書くと

1、長すぎず、短すぎず

2、意味の通じる名前に!かっこいいだけじゃダメ

3、一貫性がある

いい名前は、コード全体を通して一貫したポリシーで名前付けが行われている
・対称性を保つ

begin/end
write/read
writing/reading
right/left
open/close
on/off
onSuccess/onFailure

onSuccessとした場合はonFaildとかにしてしまうと 名詞/形容詞ということになるので対称性が保たれません。正しくはfaildではなく、failureになります。 名詞/名詞にしましょう。
または形容詞/形容詞というように
・単語の組み合わせ方を一貫させる
scoreAvg,scoreAverage,avgScoreなどを同時に使用しないこと
補足として
単語 + 略語とした場合は一貫してそのルールで
単語 + 単語にした場合は一貫してそのルールでということだと思う。

4、英語で付けられている

プログラミングに使われている名前は英語がほとんどなので英語を使って適切な名前をつけることで意図が誰にでも伝わる。
これは本当で、日本人だけならまだしも、プロジェクトは外国人が加わることはごく普通にあるので万人に共通した英語で書くといいと思います。
私はこれを勘違いして英語でコメントを書いていましたが、プログラムを書くよりも難しかった笑
本当はコメントも英語で書けばいいのでしょうけど、とりあえずは自分が分かるようにでいいと思うコメントは。
あとは誤訳にも注意することですね。英語には複数の意味を持っている単語が複数あるので、それは適切なのかどうかしっかり考えて付けましょう。
あとはプロジェクトにはイディオム(慣習)に従う。

5、変数名

最初の方でどちらのプログラムが分かりやすいかという例を示しました
それをこの章では具体的に述べられています。是非読んで欲しい。(作者じゃないのにここまで勧めるにはそれだけ価値がある理由があります。)

まず、基本は説明的な名前を付けること

手始めに
int n;
これでは意図が伝わりずらい。その変数は一体何を意味しているのかと考えるためにコードをたどる時間がもったいない
String[] languages - {"ja","en"};
これも同じくなんの言語なのかわかりづらい。
boolean flg = false;
これもなんのフラグなのかわからない。
UserAgent userAgent;
なんのユーザーエージェントなのでしょう?

これは以下に直したもの
int orderCount;
これはオーダー数ということが明確
String[] availableLanguages = {"ja","en"};
これも利用可能な言語だということが一目でわかる。
boolean exisitSameName;
これも同姓同名の名前が存在するかどうかを判定するためのフラグだということが明白である。
しかし、例外もある。
int n;というのは不適切と言っているが
forループなどで使用する場合は
for(orderCount=0;orderCount<0;orderCount++){};
などよりは
for(n=0;n<0;n++){}; のほうがすっきりして分かりやすい場合もある。

第四章 スコープ

スコープとは変数や関数の有効範囲のことです。
privateやpublicなどと書いているあれです。
C言語の場合main関数か自分で作った関数(ユーザ関数)などです。
よく私もJavaのプログラミングなんかをしているとエラーがでるのでめんどくさくてpublicにしがちですが、それは未来のエラーの原因になるので本当はprivateにしてそこから必要なところだけpublicにしたりするべきですね。
またローカル変数やグローバル変数でも、初心者は良くどこでも使えるからメンバ変数にしがちです。これは初期の教育上では仕方ないことですが、それで終わってしまった場合はその人は不幸なことにバグを作るダメなプログラマーになってしまうでしょう。
ちゃんとドロボーが入らないように家に鍵をするように必要なとこだけ空けとくことを心がけましょう。
何故かと言うと本にも書いているのですが、メンバ変数にするとどこでも使えるということはバグが発見された時はすべての該当する変数を変更しなくてはいけません。
そうしたことにならないようにスコープを意識すると良いプログラマーになれると思います。

スコープは簡単にいうと変数の有効範囲です!!

Calculator.java
class Calculator {
  public static int number = 0;
  public static void changeNumber(int _number) {
    number = _number;
  }
  public static void main(String args[]) {
    changeNumber(564);
  }
}

numberの有効範囲はどこまででしょう?

これは全部のところで値が変えられる弄り放題のガバガバ変数です。

Calcurator.java
class Calculator {
  private static int number = 0;
  private static void changeNumber(int _number) {
    number = _number;
  }
  public static void main(String args[]) {
    changeNumber(564);
  }
}

上のようにすると
changeNumber(564);
という部分はprivate、アクセス制御子によりCalculatorクラスの中だけでしか実行できないので、セキュアであります。
実行はできないということになります。

第五章 コードの分割

私の経験からいうとC言語を主に書いているので初心者の頃はmainメソッドしかないものだと思っていたのでmainメソッドにだーーーっと書いて100行以上書いていた時がありました。
それだといわゆるスパゲッティコード🍝になってしまいます。

熟練した人や書いた本人しかわからないもしくは、書いた本人ですら分からなくなってしまいます。

Javaであればオブジェクト指向に沿って書くなどしましょう。

第六章 コードの集約化

sample.java
public class StoreAction extends BaseAction {
  public void store(Account account) {
    if(account.getFirstName() == null || account.getFirstName().length()== 0) {
      return;
    }
    if(account.getlastName() == null || account.getLastName().length() == 0) {
      return;
    }
  }
}

これは文字列がからかどうかの判定のコードが二回出てきます。
これをisEmptyという別メソッドに抽出したのが次

sample2.java
public class Store extends BaseAction {
  public void store(Account account){
    if(isEmpty(account.getFirstName())){
      return;
    }
    if(isEmpty(account.getLastNAme())) {
      return;
    }
  }
  public boolean isEmpty(String str) { 
    return str == null || str.length() == 0;
  }
}

引き数の文字列が空文字かどうかを判定するisEmptyメソッドを追加したのでコードも大変見やすくなったと思います。
次のようにしてもよい

sample3.java
public void store(Account accout) {
  if(isEmpty(account.getFirstName) || isEmpty(account.getLastName()){
    return;
  }
}

etc...継承でまとめる。よく使うメソッド類はユーティリティクラスにまとめる。

あとがき

第六章以降は自分もあまり知らなくて難しい概念ばかりなので飛ばさせていただきました。
実際に良いコードを書く技術という本を読んでいただくと理解ができると思います。
本の紹介ということで記事を一部引用させていただきました。
プログラミングをしているけれど中々成長していないなと、私と同じような悩みのある方にこの記事を読んでいただけたら嬉しいです。

参考

良いコードを書く技術 -読みやすく保守しやすいプログラミング作法  
著者 縣俊貴
ISBN 978-4-7741-4596-9

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック
著者 Dustin Boswell
ISBN 978-4873115658

NoriakiOshita
機械学習やってます。 お仕事の依頼などは oshitanoriaki@gmail.com までお願いします。
http://whispon.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした