プログラミングの作業は、「私たちの奥深くに備わっている創造性の欲求を満たしてくれる」。また、「私たちが人間として共通に持っている感覚を楽しませてくれる」。そこには、5つの種類の喜びがある。
- ものを作る喜び。
- 他の人々にとって、便利なものを作る喜び。
- 連動する部品のものをパズルのように組み合わせる魅力。
- 常に学ぶ喜び。そして、繰り返しの仕事がない喜び。
- とても素直な媒体で仕事をする喜び。それは、純粋な思考物である。しかし、それでもなお、その媒体は、文字オブジェクトができない方法で、存在し、運動し、仕事をするのである。
プログラミングの作業には、特別な苦悩が本来的に備わっている。
- プログラミングをするうえで、完全性の要求に合わせることは、もっとも大変なことである。
- 他の人が方針を決めるため、自分自身がコントロールできないもの(特にプログラム)に頼らなくてはいけない。つまり、権限と責任が釣り合っていないのである。
- 創造性は、「つらい仕事をするというつまらない時間」と一緒ににやって来る。プログラミングも例外ではない。
- 終わりに近づくにつれて、プログラミング・プロジェクトは、ゆっくりとまとまる。
- 製品は、完成するまでの間、常に老朽化の危機に瀕している。紙に描かれた虎は、実際に使われることが望まれないかぎり、本物の虎には敵わない。
コードにはHow
テストコードにはWhat
コミットログにはWhy
コードコメントにはWhy not
-
怠惰
-
短気
-
傲慢
プラスで礼儀正しさと敬意
• コードが重複しまくっている
• 条件分岐の密林があちこちにある
• どこに何が書いてあるかわからない
• 変更した時にどこで何が起きるか推測できない
• やっていることは解読できるが、なぜ、そこでそ の処理が必要か意味がわからない
• パッケージ名/クラス名/メソッド名/変数名/コメン トが嘘だらけ
• でも動いてる
読みやすくて、理解しやすく、修正しやすいコード
- メモリ使用量やCPU使用料、I/O転送量が低いコードではない
- 少しでも高速に動作するコードではない
- トリッキーな手段を駆使してなるべく短くかかれたコードではない
良いコードにするには
- OCP 拡張に対して開いて、修正に対して閉じる
- スコープを小さくする
- 関数型のエッセンスを取り入れる
- 出力は戻り値
- 代入は一回だけ(同じ変数を使いまわさない)
- SRP クラスの役割はひとつだけ
- 直交性
- どのデータも1か所で定義しよう
- 1つの関数には1つのことだけをさせよう
- 時間がかかりすぎるなら、たぶん何か間違えている
- 最初に良い方法で実装しよう
- 慣例に従おう
-
簡潔さの罠 全てのコードをシンプルに保つのは実は不可能に近い。なぜならば、コードが扱うのは現実世界の問題であり、現実世界はとても複雑だから。よって、ソフトウェアが複雑になるのは避けられない問題で、これは認めなければならない。それでもシンプルにするとどこかにシワよせが来る。
-
複雑さ、簡潔さをどこに持たせるか 全てのコードをシンプルに保つのは難しいという話の通り、例えばRuby ではとても泥臭いことをやっている。しかし、そのおかげで、Ruby で記述されたプログラムを簡潔に保つことができるようになっている。
シンプルな言語でソフトウェアを作ればソフトが複雑になり、逆にソフトをシンプルに記述するためには言語がその複雑さを負う必要がある。
- 理想は水鳥のごとく Ruby を使ったコーディングでは、見える部分では優雅に見えるけど、見えない部分では泥臭いことをやっている。
これを「怠惰のための勤勉」とまつもとさんは表していた。手抜きをしては美しいコードを書くことは当然できない。でも、苦労を見せびらかす(表面に見えるようにする)のは粋じゃない。まさに水鳥。
「全てをシンプルにすること = 美しい」ということではない。Ruby が簡潔な表現ができると評価されるのは、Ruby 自身が複雑さを引き受けているからでもある。
-
思考の流れにあっているコード 「○○を~して、~して、~する」のように、人の思考は左から流れている。そのように表現されているコードは美しい。
-
外面の美しさ コード(= ソフトウェア)には外面的な美しさもある。ここでは、「人にフォーカスしたソフトウェアは美しい」という話がありました。人を考慮した優しいコードは美しい。
使うことで使っている人を進化させるようなソフトウェア
Excel の表を見ながら電卓叩いている人を見ると、上手く最適化されていない気がする(その人にとってExcel の習得コストが高い*1)。
マスターするのは大変だけど、マスターすると進化につながるようなソフトが美しい。まつもとさんは自分のマシンのローマ字のキー配列をいじるコードを書いた。最初3日間くらいはまともに文字が打てなかったけど、今はいくら大量に文字をうっても腱鞘炎にならない。(怠惰のための勤勉)
- 人への理解(外面の美)
- どのように書くと読みやすいのか
- どんな風に使えると人は嬉しいのか
- これが唯一の正解というものはない
- 機械への理解(内面の美)
- どんなアルゴリズムを使うといいのか
- 外面の美ほど価値観は変化しない
- ひどいコードは何やってるか分からない
- ひどいコードが何やってるか分かっても、なぜそうなってるのか、そこを変えるとどうなるか分からない
- ひどいコードは新たな変更に耐えられず書き直されることになる
- ひどいコードを書き直すには、ひどいコードがどおなっているか理解し、どこを変えるとどうなるのか理解する必要がある
- ひどいコードはたいていひどいテストコードが支えていて、テストコードがあったとしてもひどいコードと同様の問題があり、頼れるものが何もない
http://hitode909.hatenablog.com/entry/2016/02/08/140232
- 適切・統一的な名前がついている
- ひとつのことだけをやってる(SRP)
- イミュータブルである
- 使いまわされない(final)
- 必要かもしれないからってコードは必要ない(YAGNI)
- 継承よりも実装や委譲
- 処理の共通化じゃなくて意味の共通化
- 関係のあるクラスを近くに
http://bufferings.hatenablog.com/entry/2017/11/01/215751
http://qiita.com/tatesuke/items/36924274f043f37a391f
- 1つのメソッドにつきインデントは1段階までにすること
- else 句を使用しないこと
- すべてのプリミティブ型と文字列型をラップすること
- 1行につきドットは1つまでにすること
- 名前を省略しないこと
- すべてのエンティティを小さくすること
- 1つのクラスにつきインスタンス変数は2つまでにすること
- ファーストクラスコレクションを使用すること
- Getter, Setter, プロパティを使用しないこと
- 使われるローカル変数をすべてメソッドの最初に宣言する。
- ローカル変数の宣言時に空文字("")や新しいオブジェクト(new Xxx())で初期化する。その後にすぐ別の値をセットする。
- メソッドの戻り値がすべて成功・失敗を表す 0 か -1 になっている。
- 複数のデータをまとめて扱う際は毎回配列を使う。配列の上限数はありえなさそうな数を指定する(1000とか)。
- 基本データ型(stringやint)と配列だけでデータ構造を表現しようとする。
- 変数の命名規則にハンガリアン記法*2を使う。
- クラスのフィールド変数をグローバル変数のように利用する。
- 配列やリストを毎回forループで処理する(例: for (int i = 0; i < array.Length; i++))。
- クラスやクラスメンバの可視性を意識していない(privateメソッドがpublicになっている等)。
- 変更履歴をコード中にコメントとして残す (ADDやDELみたいなコメントがたくさん付いている)。
- 変数名やメソッド名を何かと略したがる。
http://blog.jnito.com/entry/20110218/1297983647
クソコードとは 読む人を怒りの渦に 叩きこむコードである
- 読めないコード – 変数名が暗号/制御フローが無駄に複雑/メソッド名と処理の 内容が合ってない etc...
- 要領の悪いコード – 言語レベルで用意されている機能を素直に使わない(例:Go を使っているのにゴルーチンを使わない) etc
- 意図がわからないコード – フレームワークのレールに従っていない
- コード補完
- シンタックスハイライト
- スタイルチェック
- スニペット
sed -i -e "s/t/ /g" *
sed -i -e "s/s*$//g" *
・ドメイン固有のString – PersonName, MailAddress, Telephone, …
・ドメイン固有のint/long/BigDecimal – Money, Quantity, Rate, …
・ドメイン固有のLocalDate – DueDate, ExpireDate, DateRange, … データの用途を明確にする
- 完全コンストラクタ – すべてのインスタンス変数は、生成時に設定
- 不変
- setter を書かない(状態を変えない)
- 値を変更する時は、別のオブジェクトを生成して返す
- 不変による「安定」
- ロジックの置き場所
- インスタンス変数を使った、判断・加工・計算
- 何もしないで素のデータを返すgetterはNG
ソフトウェアのライフタイムにおけるコストは,その 80% が保守に費やされる.
ソフトウェアの保守が最初から最後まで元の作成者によって行われることは,ほとんどない.
コーディング規約は,ソフトウェアの可読性を向上し、エンジニアが初めて目にするコードをすばやく完全に理解できるようにする.
このため、この規約は名前付けやスタイルを中心としており、次の項目が含まれています。
- ファイル名
- ファイルの構成
- インデント
- コメント
- 宣言
- 文
- 空白
- ネーミング規約
- プログラミングの慣例
- 1関数内の有効行数は、75行以内とする。
- 1関数内のネストの深さは、5以内とする。
- 1関数内のサイクロマチック数は、20以内とする。
- 1関数内の分岐条件数は、20以内とする。
- 1関数内のパラメータ数は、3以内とする。
- DEPLOY_ENV
- NODE_ENV
- DEPLOY_TYPE
- APP_ENV
- EXECUTION_MODE
- WORKING_ENV
- ENVIRONMENT
suffixを使うことにする
MINIMUM_APPLE_COUNT (replace with APPLE_COUNT_MINIMUM).
https://hilton.org.uk/presentations/naming-guidelines
"プログラマが知るべき97のこと":http://xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com/
http://www.ne.jp/asahi/hishidama/home/tech/lang/symbol.html
- ソフトウェアの名前
- バージョン
- 概要(Overview)
- 詳細(Descriptions、Features)
- インストール方法(Requirement、Installation)
- 簡単な使い方(Usage、Getting Started)
- 例(Examples)
- ヘルプ?(Help)
- 動作確認マシン(Testing Environments)
- 既知の不具合(Bugs)
- 注意事項(Notices/Notes)
- FAQ(FAQ,Troubleshooting)
- 更新履歴(Relese Notes)
- 謝辞(Acknowledgements、THANKS)
- 連絡先(Authors)
- ライセンス(LICENCE)
- ファイル構成
https://yakst.com/ja/posts/3859
https://gist.github.com/rowanmanning/77f31b2392dda1b58674#file-readme-md
- CONTRIBUTING.md
- CHANGELOG.md
- LICENSE.md
https://github.com/kmindi/special-files-in-repository-root/blob/master/README.md
- 命名規約が整然としていること
- 記号名の命名が適切であること
- モジュール分割が十分細かく行われていること
- ひとつの関数の行数が多過ぎないこと
- アクセス制御、同期、暗号等の専門技術を要するコードが局所化されていること
- アサートが記述されていること
- 関数の入力パラメータは適切か
- 長期的データのインテグリティが確保されているか
- 処理を行った結果長期的データのインテグリティが損なわれなかったか
- 返す結果が適切か
- 動的メモり割当・解放が組織立って行われていること
- malloc()呼び出し、free()呼び出しが局所化されていること
- 一定期間コンテキストを維持する機構で動的メモリの把握が行われること
- このコンテキストの消滅時にその機構で使われていた動的メモリもすべて解放されること
- ループが有限回数で停止すること
- 再起呼び出しが有限の深さで停止すること
- 外部から取り込むデータすべてに入力検査を施していること
rubyでは長くても改行しないみたい
pythonは80文字ルールがある
参考
https://google-styleguide.googlecode.com/svn/trunk/javaguide.html#s4.5-line-wrapping
(1)=以外のオペレータの前で改行
(2)=のあとで改行
(3)(のあとで改行
(4),のあとで改行
(1) ローカル変数を利用
(2)カンマで改行
(3)優先度の低い演算子の前で改行,
基本方針:できるだけ上の行に続きっぽい感じで残す
基本方針:+とかーとかはできるだけ前にする。カンマとかは後ろにする。
1735 if define != ifndef:
1736 error(filename, 0, 'build/header_guard', 5,
1737 '#ifndef and #define don't match, suggested CPP variable is: %s' %
1738 cppvar)
1739 return
優先順位は以下のとおり
"+-*/|&"->","->"("->".%->"
http://www.triemax.com/products/jalopy/manual/wrapping.html
要件のIF
仕様のIF
実装のIF
要件のIFは、システムの外に元々存在しているもので本来要件として抽出が可能なもの(まぁ大抵は設計中に知るんだけどね)
仕様のIFは、システム開発のいろんな都合で追加されるもの。これが一番うざい
実装のIFは、プログラム的な都合で追加されるもの。大抵はnullで落ちるのを防いだり、ライブラリに正当な値を渡したり・・って為のもの
http://d.hatena.ne.jp/makotan/20081107#p3
業務エラーでは、例外を利用してはいけない。
https://blogs.msdn.microsoft.com/nakama/2008/12/29/net-part-1/
参考
http://d.hatena.ne.jp/kmaebashi/20100114/p1
http://d.hatena.ne.jp/licheng/20130608/p1
http://blog.shin1x1.com/entry/application-throws-exception-or-not
https://qiita.com/koher/items/a7a12e7e18d2bb7d8c77
https://qiita.com/omochimetaru/items/c30f7a021fb9b8f0fa92
- 「何の」処理をしたのか
- 「いつ」処理したのか
- 「だれが」処理したのか
- 「どこへ」処理を委譲したのか
- 「どのように」処理を委譲したのか
- 「どれくらい時間が」かかったか
- タイムアウトしたか
- 何度目のリトライか
http://gihyo.jp/dev/serial/01/java-system-operation/0008
-
オブジェクト指向 部品として考える
-
インデント タブvsスペース タブからスペースの変換は用意
スペースからタブへの変換は困難
メリット
タブの方が情報圧縮されている
スペースの方がエントロピーが高い
- マルチプロセスとマルチスレッド(fork thread)
- マルチプロセス
- ○プロセス空間が独立しているので、グローバル変数や、スタティック変数を心配なく使用できる。
- ○個別にデバッグが容易。
- ○1プロセスに対する制限(同時オープンファイル数など)を気にせず、多数の処理が可能。
- ○子プロセスを殺したりしても全体に影響が出にくい。
- ○子プロセス処理で多量のメモリを確保しても、そのプロセスが終了すれば開放され、サーバ本体のサイズが大きくなりにくい。
- ×プロセス空間が多数必要になるので、メモリ消費量が多くなりがち。
- ×プロセスサイズが大きい場合、fork()自体に時間がかかる。
- ×UNIX以外のOSでサポートされていない場合が多い。
- ×排他制御・同期制御などを、プロセス間通信などを使い手間がかかる。
- ×子プロセス終了時に親プロセスはwait()などで終了ステータスを得ないとゾンビプロセスが残る。
- マルチスレッド
- ○1プロセス空間だけで並列処理するのでメモリを無駄に消費しない。
- ○スレッド生成自体はほとんど時間がかからない。
- ○UNIX以外のOSでもサポートされている場合が多い。
- ○スレッドの終了ステータスは特に待つ必要はない。
- ○排他処理などが提供されている
- ×1プロセス空間内での並列処理なので、グローバル変数やスタティック変数は危険。
- ×デバッグが行いにくい。
- ×1プロセスに対する制限(同時オープンファイル数など)により、処理数が限定される。
- ×スレッドの途中終了が難しい。
- ×スレッド内で動的に多量のメモリを確保すると、プロセスサイズが大きくなり、戻らない
単一責務性の違反指数(SRP)を計算するようにしています。
SRP=R+U+((L/100)-5)
R:修正リビジョンのユニーク数
U:修正ユーザのユニーク数
L:モジュールのライン数
この値が大きければ大きいほど単一の「大きな」モジュールが「何度も多くの人に」触られている状態であると言えます。これはコンポーネントの変更の多さに対してモジュールの分割が不十分であることを証明しているという判断によるものです。
この指標を各コンポーネント内のコードに適用し,降順に並べ替えると,「王様モジュール」のようになっているものを割り出せます。
http://gihyo.jp/dev/serial/01/perl-hackers-hub/000803
function get_SRP() {
local target_filepath=$1
echo $(( $(git --no-pager blame --line-porcelain $target_filepath | sed -n 's/^summary //p' | sort | uniq -c | sort -rn | wc -l) + $(git --no-pager blame --line-porcelain $target_filepath | sed -n 's/^author //p' | sort | uniq -c | sort -rn | wc -l) + ( $(cat $target_filepath | wc -l) / 100 - 5) )) $target_filepath
}
# SRPが酷い順(大きい順)に "SRP ファイル名" を標準出力
for file in `git ls-files | grep -E '.cc|.h|.c'`; do
get_SRP $file
done | sort -k1,1 -nr