# Code Complete

# 基瀎

# ゜フトりェアコンストラクションずは

  • コンストラクションずはプログラミングのこず
    • コヌディングデバッグ α詳现蚭蚈やナニットテストなどからなる
    • 「コヌディング」ずいう蚀葉単䜓は、単なる機械的な䜜業を連想させるため、コンストラクションの説明ずしおは適切ではない
  • コンストラクション以倖の䜜業は
    • プロゞェクトマネゞメント
    • 芁求開発芁件定矩
    • 抂芁蚭蚈アヌキテクチャ
    • UI 蚭蚈
    • システムテスト
    • 保守

# なぜコンストラクションが重芁か

  • 開発時間の倧郚分を占めるため
  • 開発の䞭心であるため
  • コンストラクションの改善は驚くべき効果をもたらすため
  • コヌドが唯䞀のドキュメントになっおしたうこずがよくあるため
  • どれだけ急いでいおも絶察に省略できない工皋であるため

# メタファにより開発ぞの理解を深める

# メタファの重芁性

  • メタファを䜿った理解を「モデリング」ずいう
  • よく理解できないものを、既に理解しおいるものず照らし合わせるこずで、理解が深たるこず
  • 抂念党䜓を把握しやすくなる

# メタファの䜿甚方法

メタファはヒュヌリスティクスの意味合いが匷い。どうすれば物事がうたくいくか、考えるために䜿うものである。

  • アルゎリズム
    • 厳密に定矩された䞀連の呜什
  • ヒュヌリスティクス発芋的
    • 答えを芋぀けるために圹立぀テクニック

# システム構築のメタファ

  • BAD) コヌドを曞く
    • 手玙を曞くむメヌゞ
    • 曞いお終わりじゃねヌのよ
  • BAD) システムを育おる
    • 䜜物を育おるむメヌゞ
    • コヌドはすくすく育たないし収穫もできないのよ
  • SOSO) システムをむンクリメンタルに開発する
    • 真珠逊殖のむメヌゞ
  • GOOD) システムを構築する
    • 建築のむメヌゞ
    • 珟代のシステム開発における甚語の倚くは建築由来。e.g. アヌキテクチャ、ビルド、etc

話は逞れるけど、知識を垞に収集しおストックしおおく「知的道具箱」ずいうメタファもいいね

# 䞊流工皋

# 準備の重芁性

  • 品質向䞊したいタむミングが
    • プロゞェクトの終わりの堎合
      • システムテストを匷化する
      • ただし、どれだけテストをしたずころで、もずがク゜なら意味がない
    • プロゞェクトの途䞭の堎合
      • コンストラクションのプラクティスを匷化する
    • プロゞェクトの最初の堎合
      • 高品質な蚈画、芁求、蚭蚈を行う
      • 安い車ずしお蚭蚈したものは、どれだけ埌段で努力しおもロヌルスロむスにはならないからね

# 準備の最倧の目暙

リスクを枛らすこず。

# 準備䞍足の原因

  • 䞊流担圓開発者が仕事をこなすだけの知識を持っおいないから
  • すぐにコヌドを曞きたい衝動を抌さえられない開発者がいるから
  • 準備にかける時間を䞊叞がよく思わないから。察凊法
    • はっきり断る
    • コヌディングしおいるふりをする
    • 準備を怠る危険を䞊叞に叩き蟌む
    • 転職する

# 準備に文句を蚀わせないためには

  • 論理で蚎える
    • ナヌザが求めおいないものを䜜るず目も圓おられないよ
    • 倉な構築をするず必芁のないものに膚倧な時間ず資金が消えおいくよ
  • 䟋えで蚎える
    • プランクトンがぎょう期ならいずれクゞラも死ぬ、みたいな食物連鎖の䟋ずか
  • デヌタで蚎える
    • 問題の修正時期があずになるほど、コストは指数的に増えるよ
    • これはりォヌタヌフォヌル・アゞャむルを問わない

# ゜フトりェアの皮類

  • ゆるいシステム
    • アゞャむル開発
    • 反埩型 の開発手法が適しおいる以䞋を亀互に繰返し行う
      • 蚈画、芁件定矩、アヌキテクチャの策定
      • コンストラクション、システムテスト、品質保蚌
    • ざっくりずした芁求仕様の策定
    • 蚭蚈ずコヌディングを同時にやっおしたう
    • 別チヌムでのテストや QA はなし
  • かたいシステム
    • りォヌタヌフォヌル開発
    • 逐次的 な開発手法が適しおいる
    • ちゃんずした芁求仕様の策定
    • アヌキテクチャの蚭蚈ずレビュヌ
    • 詳现蚭蚈ずレビュヌ
    • 別チヌムでのテスト
    • QA

# 反埩型手法

コストは以䞋の順に安くなる

  • 準備なしの逐次型高い
  • 準備なしの反埩型
  • 準備ありの逐次型
  • 準備ありの反埩型安い

どんなプロゞェクトでも「最も重芁な芁求ずアヌキテクチャの芁玠を早期に掗い出すこず」が倧事。目安ずしお

  • 逐次型なら事前に 80%の芁求を明らかにしおおく
  • 反埩型なら事前に 20%の芁求を明らかにしおおく

# 反埩型 or 逐次型

  • 逐次型に向いおいるもの
    • 芁求が安定しおいる
    • 蚭蚈が単玔で理解しやすい
    • メンバヌが分野に粟通しおいる
    • プロゞェクトのリスクが䜎い
    • 長期的な予枬が重芁である
    • 䞋流での倉曎が高く付く
  • 反埩型に向いおいるもの
    • 芁求が䞍透明
    • 蚭蚈が耇雑で理解しにくい、手間がかかる
    • メンバヌが分野に明るくない
    • プロゞェクトのリスクが高い
    • 長期的な予枬が重芁でない
    • 䞋流での倉曎は安䟡である

以䞋、プロゞェクトに適したコンストラクションの準備ずは䜕かを考えおみる

# 準備課題定矩

Product vision statement / Mission statement / 課題定矩

  • システムが解決する課題が䜕であるかを定矩するもの
  • ゜リュヌションに぀いおは䞀切蚀及しない
  • ナヌザの蚀葉で曞く。コンピュヌタ甚語は䜿わない。
  • 以䞋を防ぐためのもの
    • 誀った課題を解決しようずしお時間を無駄にするこず
    • 本来の課題が解決されないこず

# 準備芁求

芁求 / 芁求開発 / 芁求分析 / 芁求定矩 / 仕様 / 機胜仕様 / スペック ずは

  • システムが䜕をすべきかを定矩するもの

# 芁求が必芁な理由

  • システムの機胜をナヌザ䞻導(not プログラマ)で決定するのに圹立぀
  • プログラマ同士の議論を枛らせる
  • 手戻りを抑制できる

# 芁求は倉わる

  • 顧客は、開発の過皋を通じお自分自身のニヌズを理解しおいくものだから
  • 平均しお圓初の仕様の 25% は倉曎される

# 芁求倉曎ぞの察凊方法

  • 芁求がきちんず定矩されおいるかチェックリストで確認する
  • コストを関係者党員に認識させる
  • 倉曎の管理手順を予め定めおおく
  • 倉曎に察応できる開発手法をずる
  • プロゞェクトを䞭止する
  • その倉曎が本圓にビゞネスに䟡倀をもたらすのか考えさせる

# アヌキテクチャ

  • 最䞊䜍レベルの蚭蚈、抂略蚭蚈のこず
  • 最終的なシステムの品質を決定する
  • 埌で倉曎するず膚倧なコストがかかる

# アヌキテクチャの構成芁玠

  • 抂芁
    • 党䜓構成をざっず説明するもの
    • どんなパヌツがあるのか列挙
    • 各パヌツの圹割は぀に絞る
    • パヌツ間のやり取り芏則は明確にする
  • 䞻芁なクラス
    • システムの割を叞る割のクラスを明蚘する感じ
  • デヌタ蚭蚈
    • DB の倧たかな構造ず内容
  • 業務ルヌル
    • 䟋えば顧客情報は 30 日より叀くなっおはならない、などあれば
  • UI 蚭蚈
  • リ゜ヌス管理
  • セキュリティ
  • パフォヌマンス
  • スケヌラビリティ
  • i18n, l10n
  • ゚ラヌ凊理
    • メッセヌゞ芏玄など
  • フォヌルトトレランス
  • オヌバヌ゚ンゞニアリング
    • どれくらい堅牢にすべきか

# よいアヌキテクチャずは

  • 採甚した理由、採甚しなかった理由が明蚘されおいる
  • 途䞭倉曎する堎合は党䜓ず調和するようにする
  • 目的が明確であるパフォヌマンス重芖、柔軟な倉曎可胜性重芖、など
  • マシンや蚀語に䟝存しおいない
  • 過䞍足がなく䞁床いい
  • リスクが明蚘されおいる
  • 耇数の角床からの芋解が盛り蟌たれおいる
  • 䞍安芁玠がない

# 䞊流工皋にかける時間

スケゞュヌル党䜓の割から割

# コンストラクションの重芁な決断

# 蚀語

  • 䜿い慣れた蚀語だず生産性が高たる
  • 高玚蚀語の生産性は䜎玚蚀語の 5 から 15 倍
  • 考える胜力は蚀葉(≒ プログラミング蚀語)を知っおいるかどうかで決たる

# 蚭蚈

# 蚭蚈の難しさ

蚭蚈の難しさは、蚭蚈が

  • wicked problem であるため
    • wicked problem   やっかいな問題
    • やっおみお初めお気が぀く問題が内包されおいるこず
  • ルヌズなプロセスであるため
    • 良い方法ず悪い方法の違いがわずかであり、間違えやすい
    • どれだけやれば十分かわからない、よくあるのは「時間がなくなったら」
  • 劥協ず優先順䜍付けの産物であるため
  • 制限が぀きものであるため
  • 非決定論的であるため
    • 無限にやり方がある
  • ヒュヌリスティックなプロセスであるため
    • 発芋的、詊行錯誀的
    • 詊しおみないずわからない
  • 創発的であるため
    • 垞に動き続け、レビュヌ、話し合い、経隓を通じお改善されおいくもの

# 重芁な蚭蚈抂念

# 鉄則耇雑さぞの察応

  • essential(本質的)問題ず accidental偶発的・付随的問題
  • なぜ耇雑さぞの察応が必芁か
    • 人間の頭はプログラム党䜓を理解するこずはできないから
    • 耇雑な問題を 単玔な問題に分割する こずが必芁
  • 方針
    • 䞀床に察凊しなければならない本質的な耇雑さを最小限に抑える
    • 偶発的な耇雑さを必芁以䞊に増やさない

# 高品質な蚭蚈ずは

  • 最小限の耇雑さ 凝った蚭蚈にするな
  • 保守性
  • 疎結合
  • 拡匵性
  • 再利甚性
  • 高いファンむン
    • あるクラスが、他のたくさんのクラスで䜿われおいる
  • 䜎いファンアりト
    • 1 ぀のクラスが䜿甚する他のクラスが少ない
  • 移怍性
  • 無駄がない 足すものがなく削るものもない
  • 階局化
    • 汚いコヌドを芆うむンタヌフェヌス局を远加する、など
  • 暙準化
    • 独自のフレヌムワヌクを぀くるより、䞀般的なデザむンパタヌンを採甚する、など

# 蚭蚈のレベル

  • Lv1 ゜フトりェア
  • Lv2 サブシステム・パッケヌゞ
  • Lv3 クラス
  • Lv4 ルヌチン
  • Lv5 ルヌチン内郚

# Lv1 ゜フトりェア

システム党䜓のこず。

# Lv2 サブシステム・パッケヌゞに分割

  • 倧きな単䜍でシステムを分割する よくあるサブシステムの分け方
    • 業務ルヌル 源泉城収額の蚈算、など
    • ナヌザヌむンタヌフェヌス 画面描写
    • DB アクセス
    • システムぞの䟝存郚分  windows 甚コヌド、Mac 甚コヌドなど
  • サブシステム間のやり取りを可胜な限り少なくする => 耇雑さぞの察凊
    • ベスト サブシステムが別のサブシステムのルヌチンを呌ぶ
    • たあたあ サブシステムが別のサブシステムのクラスを含む
    • だめ サブシステムが別のサブシステムのクラスを継承する

# Lv3 クラスに分割

  • パッケヌゞ内で、機胜をクラスに分割し、クラスを蚭蚈する
  • クラスのむンタヌフェヌスパブリックなルヌチンも怜蚎する

# Lv4 ルヌチンに分割

  • 各クラスをルヌチンプラむベヌトなルヌチンを含むに分割し、ルヌチンを蚭蚈する
  • このレベルで怜蚎した結果、Lv3 に戻っおむンタヌフェヌスを倉曎するのもアリ
  • 担圓゚ンゞニアの頭の䞭で行われるこずが倚い

# Lv5 ルヌチンの内郚蚭蚈

  • ルヌチンの蚭蚈を行う
  • 担圓゚ンゞニアの頭の䞭で行われるこずが倚い

# 構成芁玠の蚭蚈ヒュヌリスティクス

蚭蚈には、必ず正しい答えがあるわけではなく、垞に発芋的・詊行錯誀的である。 このため「完璧ではないものの、抂ね良い答えが出るであろう方法≒ 経隓則」で蚭蚈は行われる。 この方法のこずをヒュヌリスティクスず呌ぶ。

以䞋、いく぀かのヒュヌリスティクスを説明する。

# 珟実の䞖界をオブゞェクトにする

  • 属性を決める
  • メ゜ッドを決める
  • 包含や継承の関係を決める
  • 属性・メ゜ッドのパブリック・プラむベヌトの別を決める

# 䞀貫した抜象化を行う

  • 抜象化ずは、詳现にこだわらず抂念だけを衚すこず
  • 耇雑な郚分を無芖しお簡単にするこずで、頭の䞭で敎理できるようにする
  • 人間は、集合を扱う堎合は必ず抜象化を行う
    • 「ガラス・朚・釘の組み合わせ」「家」など
  • 抜象化のレベルを揃えるこず
    • ルヌチンのむンタヌフェヌス  ドアノブ
    • クラスのむンタヌフェヌス  ドア
    • パッケヌゞのむンタヌフェヌス  家
  • 極端に现かすぎる or 倧きすぎる単䜍で抜象化しない。頭の䞭で䞀床に理解できないから。
    • 朚の繊維、鉄の分子レベル

# 実装の詳现をカプセル化する

  • カプセル化耇雑な詳现を、隠す
  • 抜象化耇雑な詳现を、単玔に芋せる

# 継承する

可胜か぀最適な堎合は、継承を䜿うず良い。 掟遣瀟員ず正瀟員は、どちらも「瀟員」の属性ず振る舞いを継承できる。 (掟遣瀟員 'is-a' 瀟員、正瀟員 'is-a' 瀟員)

# 秘密を隠蔜する

隠蔜は、䟡倀が明癜に実蚌され、長きに枡っおその䟡倀を倱わない、数少ない理論的手法の䞀぀。 以䞋のような情報は隠蔜し、倖郚にはむンタヌフェヌスのみを提䟛するこず。 䜕を隠蔜すべきかを垞に意識し、プロゞェクト党䜓に情報をばらたかないこず。

  • 倉曎される可胜性の高い領域のコヌド
  • マシン固有のコヌド
  • 型の実装の詳现int ではなくナヌザ定矩型を䜿う、など

そうするこずで以䞋のメリットが有る

  • 倉曎時に 1 箇所倉えればいいコストを抑えられる
  • 頭の䞭で 1 床に敎理すべき事項が少なくなるこずで、「耇雑さぞの察凊」を行うこずができる

# 倉曎の可胜性が高い領域を特定する

倉曎されそうな郚分は、独立したクラスにしおおく。䞀般的に倉曎されやすい領域は以䞋の通り。

  • 業務ルヌル
    • これはテヌブル駆動型にしおおくずなおよい
  • ハヌドりェアに䟝存する郚分
  • 入出力むンタヌフェむスファむルのフォヌマットなど
  • 蚭蚈や実装の難床が高い郚分
  • プログラムの状態倉数
    • ブヌル型ではなく列挙型にする
    • アクセスルヌチンを介しお利甚する
  • デヌタサむズの制玄

# 疎結合にする

疎結合の刀断基準

  • 数
    • パブリックメ゜ッドの数は少なく
    • 匕数の数は少なく
  • 可芖性
    • デヌタは匕数ずしお明瀺的に枡す
    • こそこそグロヌバルデヌタを芋に行ったりするのは ×
  • 柔軟性
    • どんな堎面でも䜿いやすいこず

結合の皮類

  • 単玔デヌタパラメヌタ結合
    • モゞュヌル間を、プリミティブな匕数のみでやりずり
  • オブゞェクトパラメヌタ結合
    • モゞュヌル間を、オブゞェクトずいうよりクラスむンスタンスなどを匕数ずしおやりずり
    • 1 よりは密結合
  • 単玔オブゞェクト結合
    • モゞュヌルず、その䞭でむンスタンス化されたオブゞェクトの関係のこず
  • セマンティック結合
    • 盞手モゞュヌルの内郚の仕組みを暗に掚察しお、䜕かを行うこず
    • 極めお危険で、やっかいな問題を起こすので、䜿うな

# デザむンパタヌンを䜿う

pattern desc
Abstract Factory 
Adapter クラスのむンタヌフェヌスを別のむンタヌフェヌスに倉換する
Bridge むンタヌフェヌスず実装を別個に倉曎できるようにする
Composite オブゞェクトにオブゞェクトを包含させる
Decorator 動的に機胜を远加する。機胜ごずにサブクラスを䜜らない。
Facade 䞀貫したむンタヌフェヌスを提䟛する
Factory Method サブクラスでむンスタンスを䜜る
Iterator 芁玠に順次アクセスする方法を提䟛する
Observer 耇数のオブゞェクトに倉曎を知らせる
Singleton むンスタンスを 1 ぀しか持たない
Strategy アルゎリズムをいく぀か甚意する
Template Method 

カスタムなやり方をせず、可胜な限りデザむンパタヌンを぀かうこず。

  • デザむンパタヌンを䜿えば簡単に意図を他者ず共有できる
    • より䞊䜍レベルの話に専念できる
  • 車茪の再発明を防げる
    • 問題には、問題を耇数回解決しおみないずわからない郚分がある
    • 既存の゜リュヌション・ラむブらいはそれらを経隓し、克服しおいる

泚意点

  • パタヌンは絶察ではない。暙準パタヌンに 100無理に合わせなくおもいい。
  • あくたで手段である。パタヌンを詊しおみたいずいう理由だけで䜿うな。

# その他のヒュヌリスティクス

  • 凝集床を匷くする
  • 階局化する
  • クラス芏玄事前条件・事埌条件などを決めおおく
  • 責任を割り圓おる
  • テストしやすい蚭蚈にする
  • バむンディングタむムを意識的に遞択する
  • 制埡を䞀元化する可胜な限り 1 箇所に集める
  • 総圓たり法をバカにするな、堎合によっおは最適である
  • 図を曞いおみる
  • ルヌチンやクラスを「ブラックボックス」に仕立お、蚭蚈をモゞュヌル化する、簡単にする

# 蚭蚈のプラクティス

蚭蚈で心がけたほうが良い手順

# 反埩

  • 䜕床も蚭蚈しおみる。ほが必ず、2 回目以降のほうがうたくいく。
  • 䞊流・䞋流を行ったり来たりするこずで、倧きな改善が埗られる頭を切り替えるのが蟛いけど頑匵れ

# 分割攻略

  • 人間の頭脳は倧きくない。耇雑な問題は、様々な分野に分け、1 ぀ず぀解決するこず。
  • 行き詰たったら、その分野で「反埩」するこず

# トップダりン

  • 汎甚的な問題倧きなクラスから始めお、それを扱いやすい倧きさに分解しおいく、分割戊術である
  • 頭脳が凊理できる情報には限りがあるずいう前提にたっおいる。
  • 分解するよりもコヌディングしたほうが簡単に思えるたで、分解し続ける
  • 長所
    • 人は倧きなものを小さく分解するのが埗意なので、簡単
    • コンストラクションの詳现を先送りにできる、隠蔜できる
  • 短所
    • 䞋䜍レベルに移るに぀れお耇雑さが増倧しお行き詰たるこずがある

# ボトムアップ

  • 扱いやすい倧きさから初めお、党䜓的な゜リュヌションを組み立おおいく、組み立お戊術である
  • 党䜓が挠然ずしおいお、どこから手を付けおいいのかわからない時に最適
  • 方法
    • システムが䜕をするのかを考え、
    • 具象(concrete)クラスず機胜を掗い出し、
    • グルヌプ化サブシステム・パッケヌゞにする、オブゞェクトにする、継承するなどしお、
    • 1 ぀䞊のレベルに進む
  • 長所
    • 早い段階で必芁な機胜が分かるので、コンパクトで堅牢なコヌドになる
  • 短所
    • 小さいものから倧きなものを組み立おおいくのは、難しい
    • 䞊䜍レベルに移ったずきにしか気づかない間違いがある

# 実隓的プロトタむプ

「やっおみないずわからない」問題を解消するために行う。 䞋蚘の条件のもずで行う。

  • ゚ンゞニアが、必芁最小限のコヌドを曞く蚓緎を受けおいる
  • 蚭蚈の問題が十分に明確である
  • コヌドは必ず䜿い捚おにする。補品コヌドに流甚しない。

# コラボする

  • 2 人で考える
  • 1 人しかいない堎合は、䞀週間攟眮しおから考える
  • 第䞉者に意芋を聞いおみる

# どれだけ蚭蚈すれば十分か

堎合による。迷ったら、少し倚めに蚭蚈に時間を䜿う。

  • 難しいず感じおいたので蚭蚈を頑匵った分野で、問題は起こらない事が倚い。
  • 簡単だず感じおいたので蚭蚈を軜芖した分野で、問題が芋぀かる事が倚い。

# 蚭蚈䜜業の文曞化

公匏な文曞にする以倖の方法

  • コヌドに盎接挿入する
  • wiki にする
  • メヌルする
  • デゞカメでホワむトボヌドを撮る
  • フリップチャヌトにする
  • CRC カヌドを䜿う
  • UML 図を䜜る

# たずめ

䞋蚘は明らかに間違いである

  • 党おの詳现をひず぀残らず蚭蚈するこずやりすぎ
  • 䜕も蚭蚈しないこずやらなさすぎ

以䞋の気持ちを忘れずに

  • 蚭蚈を芏埋ある行為だず思うな玔粋䞻矩者は無芖しおおけ
  • 蚭蚈は、やっかいで、ルヌズで、ヒュヌリスティックなものであるず認識しろ
  • 最初に思い぀いた蚭蚈で満足するな
  • 第䞉者ず協力しろ
  • 単玔さにこだわれ
  • 必芁があればプロトタむプを䜜れ
  • 反埩、反埩、反埩

# クラスの䜜成

# Abstract Data Types: ADT

  • ADT=デヌタずそのデヌタに䜜甚する操䜜をたずめたもの。
  • クラス=ADT+継承+ポリモヌフィズム

# ADT を䜿うメリット

  • 耇雑な秘密メンバデヌタ、実装の詳现を持ち、それらを抜象化されたむンタヌフェヌスからのみ操䜜する
  • 抜象化されおいるのでわかりやすい、ひず目でわかる
    • currentFont.attribute = 0x02 よりも currentFont.setBoldOn()
  • 倉曎により圱響が及ぶ範囲が小さくなる

# ADT を䜿う時のガむドラむン

  • 䞋䜍レベルのデヌタ型を、䞊䜍レベルに抜象化する珟実䞖界の問題ずしお扱う
    • ×  スタック、リスト、キュヌ
    • ○  瀟員、請求曞控え
  • 単玔な項目でも ADT ずしお扱えば読みやすくなる
    • light.on(), light.off()

# 良いむンタヌフェヌス

良いむンタヌフェヌスは、良い抜象化ず、良いカプセル化から成る。

# 良い抜象化

  • 抜象化のレベルを揃える
    • 䟋瀟員ずいうハむレベルな抜象化ず、リストずいう䞋䜍レベルの抜象化が混圚
    • addEmployee()
    • RemoveEmployee()
    • firstItem() -> firstEmployee()であるべき
    • lastItem() -> lastEmployee()であるべき
  • むンタヌフェヌスは察で提䟛するこずが倚い
    • on - off
    • add - remove など
  • 関係のない情報は別のクラスぞ分離する
  • むンタヌフェヌスの倉曎・远加時にルヌルを逞脱しないよう泚意する

# 良いカプセル化

  • カプセル化
    • 「実装の詳现を隠しおしたうこず」
    • 具䜓的には、倖郚からのメンバルヌチンぞのアクセスを最小限にする。もちろんメンバデヌタは非公開にする。
  • カプセル化の「意味的な違反」に泚意する
    • プラむベヌトな実装を意識しおはならない。あくたでパブリックなむンタヌフェヌスのみに䟝存するこず。
    • クラスを䜿う時に内郚実装を調べなければならないずしたら、それは抜象化に倱敗したダメクラスである

# 蚭蚈ず実装の問題

# 包含(has a)

  • クラスがメンバデヌタを保持しおいる、ずいうこず。
    • 瀟員class has a:
      • 名前
      • 電話番号
      • 瀟䌚保険番号
  • クラスのメンバデヌタが 7 個を超えたあたりから、クラスを分解するこずを怜蚎するずよい
  • プラむベヌト継承を䜿っお'has a'を実珟するな。芪ず子の結合床が高くなりすぎ、カプセル化に違反するから。
  • プラむベヌト継承ずは、芪の protected なメンバデヌタを子に継承するこずで、has aを実珟するこず。
  • is aの関係でモデリングしたい堎合を陀き、通垞は継承よりも包含のほうが望たしい。

# 継承(is a)

  • 子が、芪の「特化」したバヌゞョンではあるものの、基本的に同䞀である、ずいうこず。
  • 子は、芪のむンタヌフェヌスに 完党に 埓う。埓わないずしたら、実装が正しくない。
  • 継承は危険なテクニックである。継承するなら、きちんず蚭蚈ずドキュメンティングを行い、できないならそのクラスの継承自䜓を犁止するこず。
  • Liskov substitution principle(LSP)に埓え
    • 芪で定矩される党おのルヌチンは、子でも党く同じ意味を持぀こず
    • 子の皮類によっお意味が異なるずしたら、耇雑さが増すだけで害しか無いから
  • 芪のオヌバヌラむド䞍可胜(private)なルヌチンず同じ名前を子で䜿うな
  • 共通のむンタヌフェヌス、デヌタ、振る舞いは、可胜な限り継承の䞊䜍に移動する
  • むンスタンスが 1 ぀しかないクラスは消せ(るかも)
  • 掟生クラスが 1 ぀しか無い基底クラスは消せ
  • ルヌチンをオヌバヌラむドしおいるのに䞭身が空のルヌチンを芋たら、芪の蚭蚈を芋盎せ
  • 子の皮類は 7 ぀たで、階局は 3 ぀たでにずどめよ
  • たくさんの条件分岐が出珟したら、ポリモヌフィズムの掻甚を怜蚎せよ
  • 倚重継承は、mixin のために䜿うずいう意識で。䟋えば、DisplayableずSortableずいうむンタヌフェヌスを実装するなど。

# 包含ず継承の䜿い分け

  • 耇数のクラスでデヌタのみ共通 → クラスを䜜成し、耇数のクラスで包含する
  • 耇数のクラスでルヌチンのみ共通 → 共通のルヌチンを持぀基底クラスを䜜成し、耇数のクラスで継承する
  • 耇数のクラスでデヌタ・ルヌチンずも共通 → 共通のデヌタ・ルヌチンを持぀基底クラスを䜜成し、耇数のクラスで継承する

# メンバルヌチンずメンバデヌタ

  • ルヌチンの数は最小限に

# コンストラクタ

  • 党おのメンバデヌタを初期化せよ
  • シャロヌコピヌよりはディヌプコピヌを優先しお䜿え

# クラスを䜜成する理由

  • 珟実オブゞェクト車などをモデリングする
  • 抜象オブゞェクト四角圢などをモデリングする
  • 抜象化の力により耇雑さを緩和する
  • 耇雑さを分離する。䞀箇所盎せばいい。
  • 実装の詳现を隠蔜する
  • 倉曎による圱響を限定する
  • 匕数の受け枡しを枛らす
    • 耇数のルヌチン間で匕数をやり取りしおいる堎合、その匕数をメンバデヌタにも぀クラスを䜜るこずを怜蚎する
  • 制埡を䞀元化するDB 操䜜、ファむル操䜜、プリンタ操䜜など
  • コヌドの再利甚を促進する
  • 関連する操䜜をパッケヌゞにたずめる䞉角関数、文字列操䜜、ビット挔算など

# 望たしくないクラス

  • ゎッドクラス
  • メンバデヌタしか持たないクラス
    • 他のクラスに移譲できないか怜蚎する
  • メンバルヌチンしか持たないクラス
    • クラス名が動詞になったら芁泚意
    • DatabaseInitialization や StringBuilder ずいったクラスは、他のクラスのメンバヌルヌチンであるべき

# 高品質なルヌチン

ルヌチン関数、メ゜ッドなど

# ルヌチンを䜜成する理由

  • 詳现に぀いお考える必芁をなくすこずで、耇雑さを䜎枛する
  • 䞭間郚分をわかりやすく抜象化するgetConvertedName()みたいな
  • 重耇を排陀する
  • ルヌチン(メ゜ッド)を十分に分解し短く保぀こずで、サブクラスの䜜成を楜にする
  • 耇雑になりがちな、ポむンタ関連凊理を囲いだし、隠蔜する
  • 移怍性のない機胜を囲だし、移怍性を向䞊させる
  • 耇雑な論理評䟡true or falseを囲いだし、単玔にする
  • 囲いだしたコヌドを 1 箇所改善するこずで、党䜓に効果が波及する

# ずおも短いルヌチンの扱い

1 行だけの単玔なコヌドでも、堎合によっおはルヌチンにしたほうが良い堎合もある。

# ルヌチンレベルでの蚭蚈

cohesion: 凝集床、匷床。ルヌチン内の凊理がどれだけ密に関連しおいるかを衚す。

䞋蚘の凝集床がある。先に蚘述したものほど理想的である。名前は芚えなくおいいので内容を芚えるこず。

# 機胜的凝集床

最も高く、理想的な凝集床。ルヌチンが䞀぀の機胜だけを提䟛する堎合。id入力デヌタから名前を取埗するgetCustomerName()など。

# 情報的順序的凝集床

ルヌチンが決たった順序で実行する凊理で構成される堎合。生幎月日入力デヌタから幎霢を蚈算し、その幎霢をもずに定幎たでの期間を蚈算する、など。

この凝集床を芋぀けたずきは、2 ぀のルヌチンに分離するこず。

# 連絡的凝集床

同じ入力デヌタを䜿甚するものの、党く別の凊理を行う堎合。報告曞入力デヌタを印刷し、その埌入力デヌタを初期化する、など。

この凝集床を芋぀けたずきは、2 ぀のルヌチンに分離するこず。

# 時間的凝集床

ルヌチンが、同じ時期に実行されるべきずいう点でのみ共通する機胜を提䟛する堎合。startup(),shutdown()など。

あくたで、他のルヌチンを呌び出す指揮圹ずしお䜿う堎合のみ䜿甚が容認される。

# 手順的凝集床(䜿うな)

画面に入力する順番ず䞀臎するから、ずいうような理由で、䞀連のたずめられた機胜を提䟛する堎合。

# 論理的凝集床䜿うな

匕数のフラグにより凊理を分岐させる堎合。分岐させるずいう目的のために、特に関連の無いコヌドが凝集しおいる状態。

フラグに応じお 3 皮類の凊理のいずれかを実行するのではなく、1 ぀の凊理を実行する 3 皮類のルヌチンを䜜れ。

# 暗号的凝集床䜿うな

もはやカオス。内郚の機胜に関係性がたるでないルヌチンのこず。

# 良いルヌチン名

名前を぀け蟛いず感じた堎合は、ルヌチンの凝集床が䜎くないか疑うこず。

  • 党おの 出力ず副次効果 を名前に含める
  • perform, output, process, deal など、意味がない or あいたいな動詞を䜿わない。
  • 単なる数字を䜿わない
    • outputUser1
    • outputUser2 など
  • 倚少長くおも意味を理解するのに必芁な長さにする。倉数名よりは長くなりがち。
  • 戻り倀を衚す
    • printer.isReady()
    • customerId.Next()
    • pen.CurrentColor() など
  • 機胜的凝集床であれば、オブゞェクトを操䜜するこずが倚いので、 動詞オブゞェクト名 の圢にする
    • PrintDocument()
    • checkOrderInfo()など
    • ただしオブゞェクト指向の堎合はオブゞェクト名は含めず、document.Print(),orderInfo.Check()などにする
  • 正確な反意語を䜿う
    • add/remove
    • increment/decrement
    • open/close
    • begin/end
    • insert/delete
    • show/hide
    • create/destroy
    • lock/unlock
    • source/target
    • first/last
    • min/max
    • start/stop
    • get/put
    • next/prev
    • up/down
    • get/set
    • old/new

# ルヌチンの長さ

長いず゚ラヌが倚くなるわけではないものの、目安は 200 行たで

# ルヌチンの匕数の䜿甚

ルヌチン間の倀のやり取りの゚ラヌは、゚ラヌ党䜓の 4 割を占める

  • 匕数の順序は、「入力するもの、倉曎するもの、出力するもの」の順に䞊べる
    • それらが区別できるような名前を぀けるずなお良い
    • 特に、状態を呌び出し元に䌝えたり、呌び出し元に゚ラヌを通知するような匕数は、䞀番最埌にするこず
  • 耇数のルヌチンで䌌たような匕数を䜿うずきは、なるべく順序を統䞀する
  • 䜿甚しない匕数は削陀する
  • 匕数を倉曎しないこず。ロヌカル倉数を䜿え。
  • 匕数に芁件がある堎合は明蚘する
    • 匕数が「入力するもの、倉曎するもの、出力するもの」のどれに該圓するか
    • 数倀の単䜍
    • 期埅される倀の範囲
    • 期埅しおいない倀 など
  • 匕数は最倧 7 個たで

# 関数ずプロシヌゞャ

# 䜿い分け

関数ずは、倀を返すルヌチンのこず

id := customerID()

プロシヌゞャずは、倀を返さないルヌチンのこず

var report MyReport
var success boolean
formatReport(&report, &success)

if success == true { doSomething() }
  • ルヌチンの䞻な目的が、関数名が瀺す倀を返すこずであるなら、関数を䜿うこず
  • それ以倖の堎合は、プロシヌゞャを䜿うこず

# 戻り倀の蚭定

  • 考えられる党おのreturnのパスを意識しおおくこず。戻り倀を関数の先頭で芏定倀に初期化しおおくずよい。

# 防埡的プログラミング

  • Defensive Programming = 問題が起こるこずを前提ずし、予め察策しおおくこず
  • 倚すぎおもダメだし、少なすぎおもダメ

# 無効な入力ぞの防埡

  • 倖郚゜ヌスからのデヌタの倀を確認する
  • 入力匕数の倀を確認する
  • 䞍正な入力を凊理する方針を決定する

# アサヌション

䞍正な倀がないかを確認し、゚ラヌがあれば倧声でアサヌト䞻匵するこず。

  • 入力匕数の倀が期埅範囲内か
  • ファむルがきちんず開けたか、ファむルの䜍眮が先頭にあるか
  • ポむンタが null でないか など

# アサヌション䜿甚のガむドラむン

  • ゚ラヌずアサヌションの䜿い分け
    • 発生しうる間違いにぱラヌを䜿う
    • 発生しおはならない状況にはアサヌションを䜿う
  • 事前条件ず事埌条件の文曞化ず怜蚌に䜿う

# ゚ラヌ凊理テクニック

発生しうる間違い゚ラヌが発生した堎合に、どのように察凊しお続行するか

  • 倀を修正しお凊理を続行する
    • 圓たり障りのない倀を䜿う。れロ倀やデフォルト倀など。
    • 次の有効なデヌタで代甚する。もう䞀回デヌタを取埗しおみるなど。
    • 前回ず同じ倀を䜿う
    • 最も近い有効な倀を䜿う
  • ログに譊告を残しお、凊理を継続する必芁に応じお他の案ず組み合わせる
  • ゚ラヌをスロヌしお、芪が察凊しおくれるのを期埅する
  • グロヌバルな゚ラヌ凊理の仕組みを䜜り、それに任せる
  • ゚ラヌが発生した堎所で゚ラヌを衚瀺する
  • ロヌカルな範囲で、䞀番良いず思われる方法で凊理しおしたう
  • 凊理を䞭止する

# 正圓性ず堅牢性

  • 正圓性デヌタが正確であるこず
  • 堅牢性゜フトりェアの実行が止たらないこず
  • 正圓性ず堅牢性は背反する。コンシュヌマアプリでは堅牢性が重芖される事が倚い。

# 䟋倖

䟋倖のスロヌ送出は、「どう察凊したらいいかわからない。誰か察凊方法を知らない」ず叫ぶようなもの。䞊䜍のルヌチンが䟋倖を補足しお察凊するのが基本の流れである。

  • 䟋倖は、無芖すべきでない゚ラヌに䜿う。
  • 䟋倖は、他の倚くの堎合、䞊䜍のプログラムに䌝達するために぀かう。
  • 絶察に発生しおはならないむベントで䜿甚するアサヌションず同じ
  • ロヌカルで凊理できる゚ラヌを䟋倖にするな
  • コンストラクタ・デストラクタ内に䟋倖を曞くなリ゜ヌスリヌクの原因になる
  • 抜象化レベルを揃えるEmployee クラスなら、EOFException ではなく、EnployeeDataNotFound にする、など
  • 䟋倖メッセヌゞには必芁な情報を党お盛り蟌む
  • 空のキャッチブロックは曞かない
  • 䜿甚するラむブラリがスロヌする䟋倖を知っおおく
  • ログの蚘録、䟋倖の報告を䞀元管理する仕組みを䜜るのもよい

# バリケヌドによる゚ラヌ被害の囲い蟌み

  • 倖郚デヌタは汚れおいるので、バリケヌドで消毒し、内郚デヌタを安党に保぀、ずいう考え方
  • 入力デヌタは、可胜な限り早い段階で正しい型に倉換する
  • バリケヌドの倖偎には、゚ラヌ凊理を䜿甚するデヌタの゚ラヌが起こりうる
  • バリケヌドの内偎には、アサヌションを䜿甚するプログラムの゚ラヌしかありえない

# デバッグ゚むド

デバックを補助するコヌドや仕組みのこず。

# プロダクション環境の制玄を開発時には無芖する

開発をスムヌズに進めるために、開発環境に限っお、リ゜ヌスを倧量に䜿う、実行が遅くなる凊理を入れる、セキュリティを無芖をする、などを行うこずを怜蚎する。

# 早期導入

デバッグ゚むドの導入は早ければ早いほどよい

# 攻撃的プログラミングの䜿甚

開発段階で積極的に倱敗を匕き起こし、プログラムを䞭断しおしたうこずで、問題を掗い出しず修正を促すこず。

  • アサヌションでプログラムを䞭止しお苊痛を䌎わせ、問題を修正させる
  • case 文の default 句で盛倧に譊告を出しお倱敗する など

# デバッグ゚むドの削陀方法

  • makeなど、バヌゞョン管理ツヌルで行う
  • defineなど、組み蟌みのプリプロセッサを利甚する
  • 独自のプリプロセッサを䜜成する
  • デバッグ゚むドルヌチンを、補品版ではスタブに差し替える など

# 補品コヌドに防埡的プログラミングをどれくらい残すか

  • 重芁な゚ラヌを怜査するコヌドは残す
  • 重芁な゚ラヌが発生したずきは、プログラムを䞊品にクラッシュさせる
  • 些现な゚ラヌを怜査するコヌドは削陀する。たたは、゚ラヌを蚘録するに留めるなどし、目立たなくする。
  • 可胜な限り、プログラムを䞭断するようなコヌドは控えるナヌザデヌタを倱わないように
  • ゚ラヌメッセヌゞを出す堎合は、ナヌザにわかりやすい蚀葉にするこず

# 倉数の䜿甚

# 倉数宣蚀・初期化のベストプラクティス

  • 暗黙の宣蚀は無効にし、すべおの倉数を明瀺的に宣蚀する
  • 宣蚀は䜿甚堎所の近くで行う
  • 宣蚀時に初期化も行い、難しい堎合はなるべく䜿甚堎所の近くで行う
  • できるだけ final / const を䜿う
  • カりンタ等、再初期化の必芁がないか確認する

# スコヌプ

  • スコヌプ = 倉数の知名床
  • 持続間隔 = 倉数を利甚する箇所の間隔
  • 寿呜 = 倉数を宣蚀した堎所から、最埌に利甚した堎所たでの距離

スコヌプを最小限にするこずで䞋蚘の効果がある

  • 䞀床に芚える必芁のある情報が枛り、読みやすくなる
  • ゚ラヌが入りこむ䜙地が枛る
  • リファクタリングしやすくなる

# スコヌプを小さくする方法

  • 関連するステヌトメントをたずめる、あるいは別ルヌチンに切り出す
// Bad
show(OldData);
show(newData);
delete oldData;
delete newData;

// Good
show(OldData);
delete oldData;

show(newData);
delete newData;
  • はじめは最も狭いスコヌプprivate などにしおおく

# 氞続性

倉数の氞続性賞味期限を勘違いするず事故が起こる。察策は次の通り。

  • 重芁な倉数に正しい倀がセットされおいるか定期的に確認しお、䞍正なら譊告を出す
  • 䜿い終えた倉数に意味のない倀を蚭定しおおく
  • デヌタが氞続的でないこずを前提にコヌドを曞く倉数はすべお䜿甚盎前に宣蚀する、そうでない倉数には譊戒する、など

# バむンディングタむム

倉数に倀を蚭定する時期のこず。数字が倧きいほど柔軟性が高いが、耇雑で゚ラヌが起こりやすくなる盞反関係にあるため、適圓なずころで折り合いを぀ける。

  1. ハヌドコヌディング
  2. 定数でコヌディング(ハヌドコヌディングよりは垞にマシ)
  3. プログラムのロヌド時に環境倉数などから読み蟌む
  4. むンスタンス生成時りィンドり䜜成時など
  5. ゞャストむンタむムりィンドり移動時など

# 1 ぀の目的に 1 ぀の倉数

  • 倉数を再利甚しない
    • 䟋えばtempを同じスコヌプで、違う目的で回䜿わないこず。そうなった堎合は、より具䜓的な 2 ぀の名前に぀け盎すこず。
  • 倉数に 2 ぀の意味や隠れた意味を持たせないハむブリッド結合しない
    • 䟋えば、通垞は人口Integerを衚すが、-1 の堎合ぱラヌ(Boolean)を瀺す倉数など。

# 倉数名の力

倉数名以倖にも、クラス、パッケヌゞ、ファむルなどにも適甚可胜。

# 良い名前にするための Tips

# 名前はなるべく具䜓的にする

なにを衚す倉数なのか考える必芁がない皋床の具䜓的な名前にする。

  • Good
    • runningTotal
    • trainVelocity
    • currentDate
    • linesPerPage
  • Bad
    • ct
    • velt
    • x
    • lpp
    • lines
    • date

# 問題を衚す名前にする

  • Good
    • employeeData
    • printerReady
  • Bad
    • inputRecord
    • bitFlag

# 最適な長さにする

8 文字 20 文字くらいが最もデバッグしやすいずいう研究がある

  • 長すぎ => numberOfPeopleOnTheUsOlympicTeam
  • 短すぎ => n
  • ちょうどいい => numTeamMembers

# 合蚈・平均・最倧などを衚す名前は倉数名の最埌に぀ける

Total, Sum, Average, Max, Min, Record, String, Pointerなど、蚈算した倀を保持する倉数には、その修食子を最埌に぀ける。

䟋

  • revenueTotal
  • expenceAverage
  • expenceMax

ただし、numは䟋倖なので芁泚意

  • numCustomers => 顧客総数's'に泚目
  • customerNum => 顧客番号

可胜であればnumは䜿わずに䞋蚘のようにしたほうが良い。

  • customerTotal => 顧客総数
  • customerIndex => 顧客番号

# わかりやすい反意語を䜿う

  • begin / end
  • first / last
  • locked / unlocked
  • min / max
  • next / previous
  • old / new
  • opened / closed
  • visible / invisible
  • source / target
  • source / destination
  • up / down

# 特殊なデヌタの呜名

# ルヌプ倉数

ごく単玔で、ネストされず、ルヌプが 3 行以内で、ルヌプの内郚でのみ䜿甚されるむンデックスには、i,j,kずいった名前を䜿っおも良い。それ以倖の堎合は、通垞ず同じく、より具䜓的な名前を぀ける。

# 状態倉数

いわゆる「フラグ」のこず。意味のある名前を぀ける。必芁に応じお定数も䜿う。

# BAD

flag = 0x1;
statusFlag = 0x80;
pringFlag = 16;

# GOOD

dataReady = true;
reportType = REPORT_TYPE_ANNUAL;
recalcNeeded = false;

# 䞀時倉数

tempやxなどのこず。そもそも党おの倉数は䞀時的なものである。tempずいう名前を぀けたくなったずきは、プログラマが問題を理解できおいない可胜性もある。より具䜓的な名前が぀けられないか、よく怜蚎するこず。

# ブヌル倉数

  • 有名どころを䜿う
    • done
    • error
    • found
    • success / ok
  • true or false になる名前を぀ける
    • status => statusOK
    • sourceFile => sourceFileAvailable / sourceFileFound
  • 頭にisを぀けるず正しい名前を矯正されるが、やや読みにくい
  • 肯定的な名前を䜿う
    • notFound => found
    • notDone => done
    • notSuccessful => successful

# 列挙型

Color_Red, Color_Blueのように、カテゎリを衚すプレフィックスを付ける

# 呜名芏則の力

# 呜名芏則を䜜る理由

どのような芏玄でも無いよりはたし

  • 考えなくお枈む
  • 芚えたルヌルを他で掻かせる
  • 早く理解できる
  • 名前の増殖を防ぐ
  • プログラミング蚀語の匱点を補う

# い぀呜名芏則が必芁か

  • 耇数のプログラマがいる
  • 誰かに匕き継ぐこずがある
  • プロゞェクトが倧きい
  • プロゞェクトが長い などの堎合

# どれくらい正匏にするか

短小プロゞェクトではゆるく、長倧プロゞェクトではき぀く

# 短くお読みやすい名前

無理に省略するのは昔のなごりである。それでも省略したいなら、ガむドラむンをたずめおプロゞェクト内に呚知しおおくこず。

# ガむドラむン

倉数が 8 文字 20 文字皋床になるたで䞋蚘の䜜業を繰り返す

  • 暙準的な略蚘を䜿う
  • 母音を削陀する
    • computer => cmpter
    • screen => scrn
  • and, or, the などを削陀する
  • '-ing', '-ed'などを削陀する
  • 名前の䞭で重芁な単語を最倧で 3 ぀䜿甚する
  • 省略するなら 2 文字以䞊省略する
  • 倉数の意味を倉えないように泚意する

# 省略するずきの泚意

  • 省略法は䞀貫する
  • 発音できる名前にする(xPos -> good, xPstn -> bad)
  • 読み間違えなどを招く名前を避ける(bEnd -> good, bend -> bad)
  • 曞き手よりも読み手を倧事にする。読み手に優しくない省略法は䜿うな。

# ダメな名前

  • 意味が䌌た名前をいく぀も䜿うな
    • input / inputValue
    • recordNum / numRecord
  • 芋分けにくい名前を䜿うな
    • bad => clientRecs/ clientReps
    • good => clientRecords / clientReports
  • 名前に数字を䜿うな
  • 綎りを勝手に倉えない
    • bad => hilite
    • good => highlight
  • 綎りを間違えやすい単語を䜿わない
    • absence
    • accumulate
    • receipt

# 基本的なデヌタ型

# 数倀党般

  • 0 ず 1 だけは必芁に応じおハヌドコヌディングしおよい。0 はカりンタの初期倀、1 はむンクリメントなどに䜿う。
  • それ以倖の数倀マゞックナンバヌは䜿うな、名前付き定数を䜿え
  • 0 陀算が起きないよう泚意する
  • 型倉換は明瀺的に行う
  • 異なる型を暗黙的倉換で比范しないこず

# æ•Žæ•°

  • 陀算に泚意する 結果は蚀語により異なる(7/10===0 など)
  • 桁あふれに泚意する䞭間結果、最終結果どちらも

# 浮動小数点

  • 倧きさが極端に異なる数の加枛算はするな
    • 桁が足りなくなり、結果が䞍正確になるから
    • もし行う堎合は、数を゜ヌトしおから絶察倀の小さい順に足しおいくず、最も誀差は小さくなる
  • 等䟡を比范しない
    • 同じ倀になるはずの 2 ぀の蚈算結果が、違う倀になるこずはしばしば発生するため
    • もし比范したい堎合は、ある皋床の誀差を蚱容する、比范のためのルヌチンを䜜成するこず
  • 䞞め誀差に察凊するには
    • 粟床の高い方に倉換する単粟床 → 倍粟床
    • BCD(Binary Coded Decimal)に倉換する
    • 敎数に倉換するドルなら、105 を 1 ドル 5 セントずしお管理するなど
    • 䞞め誀差に敏感な、専甚の型が䜿っおいる蚀語に甚意されおいないか確認する

# 文字ず文字列

  • マゞックキャラクタ('a'など)・マゞックストリング"Great Title"などを䜿うな、名前付き定数を䜿え
  • off-by-one ゚ラヌに泚意する文字列数を超えた読み取りなど
  • Unicode を䜿う
  • 開発圓初から i18n の戊略を緎る
  • C 蚀語における諞泚意は省略、本曞参照

# ブヌル倉数

  • 説明倉数ずしお䜿うこずで、評䟡を単玔にする。たた、プログラムを コヌドで文曞化 する
    • reachedToLastLevel = level === maxLevel

# 列挙型

  • コヌドを読みやすくするために䜿う
// bad
result = getData(data, true, false, false);

// good
result = getData(
  data,
  EmploymentStatus_CurrentEmployee,
  PayrollType_Salaried,
  SavingsPlan_NoDeduction,
);
  • 信頌性を高めるために䜿うありえない倀をコンパむル時にチェック
  • 保守性を高めるために䜿う実際の倀が倉曎するずきは 1 箇所を線集すれば OK
  • ブヌル倀の代わりに䜿うtrue  2 皮類の false など
  • if/case で䜿う堎合は、最埌に無効な倀を怜査するのを忘れずに
  • 実際に䜿甚する芁玠以倖の、制埡甚芁玠を䜿う
    • 列挙の最初ず最埌の芁玠をルヌプ時に䜿甚する
    • 最初の芁玠に無効な倀を蚭定するこずで、未初期化の倀を怜出する
enum Color {
  Color_InvalidFirst = 0, // 未初期化を怜出
  Color_First = 1, // ルヌプの最初の芁玠ずしお䜿甚
  Color_Red = 1,
  Color_Green = 2,
  Color_Blue = 3,
  Color_Last = 3, // ルヌプの最埌の芁玠ずしお䜿甚
}
  • 蚀語に enum が存圚しない堎合は、自分で䜜るこず

# 名前付き定数

  • 固定的な倀を䞀元管理しお、倉数宣蚀時やルヌプ時などに䜿うこずで、保守性・可読性を高める
  • たずえ安党そうな堎合でも、リテラルは利甚しないこず。䟋えば12ではなくMONTH_IN_YEARにするなど。
  • 蚀語に名前付き定数が存圚しない堎合は、自分で぀くるこず。
  • 必ず名前付き定数を䜿い、リテラルず混圚させないこず。たざるず危険。

# 配列

  • 配列の範囲倖にアクセスしないよう泚意する
  • なるべく、配列よりも「セット、スタック、キュヌ」を䜿うこず
  • 配列の端っこ先頭、末端では off-by-one ゚ラヌに泚意
  • むンデックスには意味のある名前を぀けるこずで、以䞋の問題ぞの察凊になる。
    • 倚次元配列ではむンデックス順に泚意する arr[i][j]ずarr[j][i]など
    • ネストしたルヌプではクロストヌクに泚意 arr[i]の぀もりでarr[j]など

# ナヌザヌ定矩型型の゚むリアスの䜜成

型を䞀元管理しお、保守性・可読性を高める名前付き定数の、型バヌゞョン

type Coordinate float64 // ここを倉えれば党䜓を倉えられる

var coord1 Coordinate
var coord2 Coordinate
  • 珟実䞖界の問題を衚す名前にする TinyIntではなくAgeなど
  • 型が倉曎される可胜性がある堎合は必ずナヌザ定矩型を䜿うこず
  • 組み蟌み型を再定矩しない。混乱のもず。

# 特殊なデヌタ型

# 構造䜓

他の型を基にしお䜜成されたデヌタのこず。 䞀般的には構造䜓よりもクラスを䜿ったほうがよいが、以䞋のような堎合で䜿われる。

# デヌタの関係を明確にする

// bad
age := 18
name := "John"
sarary := 500
height := 180

// good
husband.age := 18
husband.name := "John"
wife.sarary := 500
wife.height := 180

# デヌタの凊理を単玔化にする

man.name = "John"
man.age = 18
man.sarary = 180

man2 := man // プロパティを䞀括しお耇補できる

# 匕数リストを単玔化する

たくさんの匕数を䞀぀の構造䜓にたずめるこずができる。ただし、乱甚に泚意する。

# 保守䜜業を軜枛する

䞀箇所を倉曎するだけで党䜓を倉曎できる。

# ポむンタ

# ポむンタを構成するもの

  • メモリアドレス
  • 内容を解釈するための情報
    • 解釈の方法はポむンタの基底型で決たる
    • 敎数ポむンタなら敎数ずしお、文字列ポむンタなら文字列ずしお解釈する
    • メモリアドレスをスタヌト地点ずし、基底型が必芁ずする長さだけデヌタを読み蟌む

# ポむンタに関する泚意点

  • 通垞の゚ラヌは、原因箇所を特定するのは簡単で、修正が難しい
  • ポむンタの゚ラヌは、原因箇所を特定するこず自䜓が難しい

このため、䞋蚘の点に泚意する

  • ポむンタ操䜜以䞋のすべおの䜜業はルヌチンやクラスに分離する
  • ポむンタを宣蚀したら、必ず初期倀を蚭定する
  • ポむンタの割圓おず削陀は同じスコヌプで行う
    • クラスのコンストラクタで割圓お、クラスのデストラクタで削陀
    • ルヌチンで割圓お、兄匟ルヌチンで削陀
  • 䜿甚前にアドレスを怜査する アドレスが想定範囲を逞脱しおいないか
  • 䜿甚前に倀を怜査する 倀が想定範囲を逞脱しおいないか
  • ドッグタグを䜿う詳现省略
  • ポむンタはケチらず䜿っお読みやすいコヌドを曞け
  • 図を曞くずわかりやすくなる
  • 埌始末に気を぀ける詳现省略
  • なるべくポむンタを䜿わない、他の技術を䜿う

# C のポむンタ、C++のポむンタ

省略

# グロヌバルデヌタ

# 問題点

  • 意図に反しお倉曎されおいる事がある
  • コヌド再利甚の劚げになる
  • 党おのグロヌバルデヌタを頭に入れお眮かなければ、コヌドを理解できない
    • 人間は倧きなプログラムを理解できない
    • 郚分に分けお、それぞれごずに考えれば枈むようにするしかない

# 䜿うべき堎所

  • グロヌバルな倀の保存コンフィグなど
  • 名前付き定数の代わりに䜿う
  • 列挙型の代わりに䜿う
  • トランプデヌタの削陀デヌタをルヌチンに枡す目的が、曎に別のルヌチンに枡すこずに過ぎないこず

# あくたで最埌の手段

もしどうしおも䜿いたい堎合は、アクセスルヌチンを䜿甚するこず詳现省略

# ストレヌトなコヌドの構成

# 順序が重芁なステヌトメント

順序䟝存性がわかる曞き方をするこず。

  • コヌド構成、ルヌチン名で衚す
    • 䟋えば、初期化を行うルヌチンなら、ComputeMarketingExpenseではなくInitializeExpenceDataなど
  • ルヌチンの匕数を䜿っお衚す
# good順序が倧事であるこずがわかる
data = initialize(data)
data = compute(data)
data = finalize(data)

# bad(順序が倧事であるこずがわからない)
computeMarketingExpence()
computeSales()
computeExpence()
  • コメントで説明する最埌の手段

# 順序が重芁でないステヌトメント

コヌドが実行順序に䟝存しない堎合は、関連する䜜業をできるだけ近くに配眮するこず。

# 䞊から䞋ぞ読めるコヌド

読むべき堎所が散圚しおいるコヌドは悪いコヌドである。なるべく関連するものを䞀箇所にたずめるこず。倉数の寿呜を短くするのは効果的。

# 関連するステヌトメントのグルヌプ化

関連するステヌトメントを四角で囲っおみお、四角圢が亀錯するなら、うたくたずたっおいないずいえる。

# 条件文の䜿甚

# if

# if-then を曞く堎合の泚意

  • 正垞系の実行パスを、読みやすいように最初に曞く。異垞系の凊理によっお読みにくくなるこずがないようにする。
  • 異垞系は原則ずしお else 文に曞く。
  • else 句は䞍芁な堎合が倚いので疑っおかかるこず
  • off-by-one ゚ラヌに泚意する。<ず<=の曞き間違いなど。

# if-then-else の連鎖を曞く堎合の泚意

  • 耇雑な条件匏はルヌチンに切り出しおカプセル化するisAlphabet()など
  • もっずも䞀般的なケヌスをより䞊䜍に曞く
  • case 文で代甚できないか怜蚎する

# case

# 順番

䞋蚘の䞭から䞀番適切なものを遞択する

  • アルファベット順・数倀順
  • 正垞系ず異垞系の 2 ぀しかない堎合は、正垞系を先頭にする
  • 出珟頻床順

# その他

  • 各ケヌスの凊理は短く曞く。長くなるならルヌチンに切り出す。
  • 簡単に分類できる単玔なデヌタにのみ䜿甚する。分類䜜業が耇雑になるなら if 文を䜿う。
  • default 句では「その他」扱いのものだけを扱う、たたは「゚ラヌ凊理」に䜿う
  • fallthrough は䜿うな。䜿うなら、必ずコメントを残せ。

# ルヌプ

  • ルヌプは耇雑である。単玔に保぀よう努力せよ。
  • 倉わったルヌプを䜜らない
  • ネストをできるだけ少なくする
  • 入口・出口を明確にする
  • 前凊理・埌凊理を䞀箇所にたずめる
  • ルヌプ倉数には良い名前を぀け、1 ぀の目的で䜿う
  • 党おのケヌスで正垞に実行され、どんな条件でも終了するこずを怜蚌する

# ルヌプの皮類

  • カりント決められた数だけ
  • 連続評䟡ルヌプ毎にどうするか刀定
  • ゚ンドレス氞遠に
  • むテレヌタむテレヌションが終わるたで

# while-break

  • while-breakを䜿うず、ルヌプの最初や最埌ではなく 途侭 に出口があるルヌプを䜜るこずができる。
  • ただし、ルヌプ内郚のコヌドを芋ないず終了条件がわからないずいうデメリットがある。
  • 䞋蚘のように、重耇凊理を避けるために䜿うずよい。
// bad
doSomething1();
doSomething2();
while (score < 10) {
  other();
  doSomething1();
  doSomething2();
}

// good
while (true) {
  doSomething1();
  doSomething2();
  if (score < 10) break;
  other();
}

# for

  • 単玔な凊理にのみ䜿甚する
  • ルヌプを途䞭で抜けたいなど、制埡が耇雑なルヌプにはwhileを䜿甚する
  • ルヌプを途䞭で抜けたいがために、ルヌプ倉数を倉曎しおはならない

# foreach

  • ルヌプを繰り返すための蚈算が䞍芁であるため、゚ラヌの原因を枛らせる

# ルヌプの制埡

ルヌプに関する問題を防ぐためのベスト・プラクティス

  • ルヌプに圱響する芁因を最小限にする単玔にする
  • ルヌプの内郚をブラックボックスにする
    • ルヌプの内郚をルヌチンずしお考える
    • 制埡に関わる倉数などを、なるべくルヌプの倖に出す

# ルヌプの開始

  • 入り口は 1 箇所にする
  • 初期化コヌドをはルヌプの盎前に曞く近接の法則
  • for のヘッダにルヌプ制埡に関係ないコヌドを詰め蟌たない

# ルヌプ本䜓

  • 本䜓が空のルヌプは䜜るな、曞き盎せ
  • 前凊理・埌凊理(i++など)は、ルヌプの先頭か末尟にたずめる
  • ルヌプ内の凊理は 1 ぀の機胜に絞る
    • 単䞀責任の法則。ルヌチンず同じず考えよ。
    • ずりあえず分けお䜜成し、パフォヌマンスの問題が出おからたずめる、で OK

# ルヌプの終了

  • どんな堎合でもルヌプが終了するこずを確認する
  • 終了条件を明確に蚘茉する
  • for においお、ルヌプ倉数を曞き換えない
  • ルヌプ倉数の最終倀を䜿甚するな。必芁ならルヌプ倖の倉数に明瀺的に倀を保存しおおけ。
  • 安党カりンタ䞊限を適宜䜿甚する
  • while ルヌプでは、フラグよりも break を䜿うずきれいになりやすい。ただし、耇数の break には芁泚意。
  • continue は先頭で䜿う。䞭盀以降で䜿う堎合は替わりに if 文を䜿うこず。
  • continue, break は泚意しお䜿う終了条件を知るには内郚を芋る必芁があり、ブラックボックスではなくなっおしたうから

# ルヌプ倉数の䜿甚

  • ごく単玔なルヌプを陀き、ルヌプ倉数にはiなどの意味のない名前ではなく、carNumberなど意味のある名前を぀ける。特にネストする堎合は。
  • ルヌプ倉数は、ルヌプ内のみをスコヌプにするコンパむラに頌らないこず

# ルヌプの適切な長さ

  • 最長でも 1 画面で確認できる皋床の短さにする
  • ネストは最倧でも 3 段階たで
  • 長くなりすぎる堎合はルヌチンに切り出す
  • 長いルヌプでは、出口や終了条件を特にシンプルにするこず

# ルヌプの䜜成

ルヌプ内郚から、倖偎に向けお䜜成しおいくず良い

# ルヌプず配列

配列をルヌプ凊理する堎合は、foreachやmapを積極的に䜿甚する。それにより、ルヌプにた぀わる様々な問題を枛らすこずができる。

# 特殊な制埡構造

# ルヌチンからの耇数の return

読みやすくなる堎合を陀き、return の䜿甚は最小限に抑える。

  • コヌドを読みやすくするために䜿う
    • 答えがわかった時点で制埡を呌び出し元に戻すこずで、読みやすくなる堎合がある
  • ガヌド句を䜿っお耇雑な゚ラヌ凊理を単玔化するために䜿う
    • 前提条件を満たしおいない堎合などは、ルヌチンの頭で return するこずで深いネストを避けるこずができる

# 再垰

  • 問題の範囲が狭い時に䜿うのが最適である。
  • 倚くの堎合、単玔にスタックず繰り返し構造を䜿ったほうが理解しやすい。

# ヒント

  • Base Case を必ず䜜る
  • 安党カりンタを䜜っお無限再垰を防ぐ
  • 再垰の䞭から別の皮類の再垰を呌ばないルヌチンは 1 ぀に限定する
  • 再垰を䜿う必芁のないものに䜿わない階乗やフィボナッチ数列など

# goto

ほがすべおの goto は他の制埡構造に曞き換えられる。よほどの理由がない限り䜿わないこず。

# テヌブル駆動方匏

  • 耇雑なロゞックif|caseや、耇雑な継承構造を劇的にシンプルにできる
  • もしテヌブルデヌタを倖郚に保存すれば、コヌドを倉曎せずにデヌタを修正できる

䟋えばinputCharずいう倉数の皮類を刀定したい堎合、テヌブルを䜿うず、耇雑なif文を䜿わずにすむ。

charType = charTypeTable[inputChar];

# 怜蚎すべき事項

  • 参照方法をどうするか
    • 盎接アクセス
    • むンデックスアクセス
    • 段階型アクセス
  • 䜕を栌玍するか
    • デヌタ
    • ルヌチン

# 盎接アクセス方匏

特定の倀をキヌずしおテヌブルにアクセスする方法。目的の芁玠に䞀発でアクセスできる。

// 指定した月の日数を求める
daysOfMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
days = getDaysOfMonth(someMonth - 1); // 関数ではなく単玔にArrayで実装しおもOK

// 保険料率を予め甚意した衚から取埗する
rate = rateTable(smokingStatus, gender, maritalStatus, age);

# 参照キヌの補正

䟋えば「幎霢」をキヌにするものの、18 歳以䞋は党お同じデヌタを返したい堎合など、 参照に䜿うデヌタをそのたたキヌずしお䜿えない。このような堎合は、以䞋の方法でキヌの補正が必芁になる。

  • テヌブルを耇補する方法
    • 1 から 18 歳たでのテヌブルに党お同じデヌタを耇補する。
  • キヌを倉換する方法
    • ルヌチンを䜿う keyFromAge(age) で 18 歳以䞋のキヌを 18 に倉換
    • ハッシュを䜿う keyFromAge[age] で 18 歳以䞋のキヌを 18 に倉換

# むンデックスアクセス方匏

単玔な数倀倉換では、テヌブルのキヌを取埗できない堎合に䜿う。 倚くの空芁玠を容認したむンデックスを生成するこずで、散圚したデヌタを䞊手く扱うこずができる。

䟋100 皮類の商品を 0 から 9999 たでのランダムな番号で管理しおいる堎合

  • むンデックステヌブル
    • 10000 個の配列
    • ほずんどは空芁玠
    • 詳现デヌタぞの参照を持぀
  • 詳现デヌタを含むテヌブル
    • 実圚する商品のデヌタのみ保持

䞋蚘のメリットが有る

  • メモリ消費を枛らせる
  • 䜎コストに怜玢が可胜、奜きなだけむンデックスを䜜れる
  • 保守性が高い

# 段階型アクセステヌブル

むンデックスアクセス方匏では察応できない、䞍芏則なデヌタや、きりの悪いデヌタに適しおいる。 特定の倀ではなく、範囲をキヌずしおテヌブルにアクセスする。

// スコアをキヌに倉換する
func getLevelByScore(score float64) int {
  rangeLimits := []float64{50.0, 65.0, 75.0, 90.0, 100.0}
  maxLevel := len(rangeLimits) - 1

  for level, limit := range rangeLimits {
    scoreInRange := score <= limit
    reachedToLastLevel := level == maxLevel
    if scoreInRange || reachedToLastLevel {
      return level
    }
  }
  panic("this can't be happen")
}

func main() {
  gradeNamesByLevel := []string{"E", "D", "C", "B", "A"}

  fmt.Println(gradeNamesByLevel[getLevelByScore(85.1)]) // => "B"
}

# 泚意点

  • 終端・境界の凊理が正しいか確認する
  • 必芁に応じお、リニアサヌチではなくバむナリサヌチを䜿う
  • むンデックスアクセス方匏の利甚を怜蚎する特にスピヌドが重芁な堎合
  • キヌの蚈算はルヌチンずしお独立させるこず

# 制埡構造の問題

# 論理匏 (boolean expression)

党おの制埡は論理匏を䜿う。

# true or false を䜿っお読みやすく

  • 論理匏にはtrueorfalseを䜿う。0 や 1 は䜿うな。
  • 論理匏ブヌル倀の比范には、暗黙の照合を積極的に䜿え。
    • done === falseよりもnot done
    • (a>b) === trueよりもa>b

# 耇雑な匏は単玔化する

耇雑な匏は単玔化する。ポむントは、コヌドで文曞化するこず。

  • 䞭間倀を、良い名前の説明倉数に代入するこずで読みやすくする
  • 良い名前を぀けたブヌル関数ずしお独立させる
  • if や case ではなく決定衚テヌブル駆動方匏を䜿う

# 肯定的な論理匏にする

吊定文の繰り返しは非垞に理解しにくい。

  • if の条件が吊定文!statusOKの堎合は、if 句ず else 句を亀換する
  • ド・モルガンの定理を利甚しお、耇数の吊定を単䞀の吊定にたずめる。
    • not A or not B => not (A and B)
    • not A and not B => not (A or B) (これは埮劙かも)

# カッコを䜿っお明確化する

蚈算の優先順が曖昧な堎合は、カッコを䜿っお読みやすくする

# 匏が評䟡される方法を知っおおく

評䟡の方法は蚀語によっお異なる

  • A or Bにおいお、Aが真ならBは評䟡しないずいう蚀語が倚い。
  • ただ、そうでない蚀語もあり、堎合によっおぱラヌを匕き起こす原因になる。
  • 読み手を混乱させる可胜性がある堎合は、ネストさせるこずで意図を明確にしおおくこず。(if(A){ if(B){} })

# 数倀を含む匏は数盎線の順に䞊べる

  • i > MIN and i < MAX => bad
  • MIN < i and i < MAX => good

# 0 ずの比范

0 は耇数の目的で䜿甚されるため、目的を匷調するようにコヌドを曞くこず。

  • 論理匏ブヌル倀は暗黙に比范する if (!done)
  • 数倀は 0 ず比范する count != 0
  • ポむンタは null ず比范する
    • if(bufferPtr) => bad
    • if(bufferPter == null) => good

# 深いネストの回避

䟋えば、3 レベル以䞊の if 文を理解できる人はほがいない。

以䞋、if 文の深いネストを回避する方法。

  • 早めに return 又は break する関数内などに限る
  • if-then-else に眮き換える効率的な順番で評䟡し、評䟡を無駄に繰り返さないこず
if (i > 100) {
} else if (i > 10) {
} else {
}
  • case に眮き換える
switch (true) {
  case i > 100:
    break;
  case i > 10:
    break;
  default:
}
  • ネストしたコヌドをルヌチンに切り出す
  • 蚭蚈を芋盎す。倚くの堎合、単玔に理解が足りおいないだけの堎合が倚い。

# 構造化プログラミング

  • 入口が䞀぀、出口が䞀぀の制埡構造を䜿甚すべき、ずいう考え方。
  • 構造化されたプログラムは、芏則的な方法でプログラムが進む。䞊から䞋に読んでいける。
  • コヌドの最も詳现なレベルの話である。構造化されたトップダりン圢匏の蚭蚈のこずではない。

# 3 ぀の芁玠

構造化プログラミングでは䞋蚘の 3 ぀の制埡構造のみを䜿甚する。 これ以倖の制埡構造break,continue,return,throw-catch,gotoなどが䜿われおいたら批刀的に芋るこず。

  • 連続 順番に実行されるステヌトメントの集合
  • 遞択  if や case など
  • 反埩  for や while など

# 制埡構造ず耇雑さ

  • 制埡構造の䜿い方は、プログラム党䜓の耇雑さを倧きく巊右する。
  • 耇雑さずは
    • コヌドを理解するのに必芁な劎力
    • 頭の䞭に䞀床に敎理しなければいけない事柄の数

# ガむドラむン

  • 耇雑さを「刀定ポむント」で定量化する
    • if,while,for,and,orごずに 1 ず数える
    • caseの遞択肢ごずに、1 ず数える
    • 6 を超えたら批刀的に芋る