読んだ本
「プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則」
特に印象に残ったこと
KISS
Keep It Simple, Stupid.
シンプルにしておけ、愚か者よ。
または、
Keep It Short and Simple.
簡潔かつ単純にしておけ。
どういうこと?
コードをシンプルに保つ
どうすれば?
新しく覚えた技術を使いたい、将来の必要に備えたい、勝手に要件を加えてしまうなど、コードに余計なことをしない
YAGNI
You Aren't Going to Need It
それはきっと必要にならない
どういうこと?
コードは必要最低限に。
どうすれば?
汎用性よりも、単純性を考えて、
汎用性のもたらす再利用性や拡張性よりも、まず「使えること」に価値を置くようにする。
PIE
Program Intenly and Expressively
意図を表現してプログラミングせよ
どういうこと?
コードの表現を工夫して、「このソフトウェアはどう動くものなのか」ということをコードの読み手にストレートに伝わるように、コードを書く。
どうすれば?
コードを書くときは、「書きやすさ」より「読みやすさ」を重視する。
コメントがなくても読めるような、わかりやすいコードを書くのが理想。
ただし、コードはどこまで行ってもWhat(何をしているか)とHow(どのようにやっているか)しか表現できない。
Why(なぜそれをしているか)を表現するにはコメントを使用する必要がある。
SLAP
Single Level of Abstraction Principle.
抽象化レベルの統一
どういうこと?
コードのレベルを合わせる。
コードを書くとき、高いレベルの抽象化概念(高水準)と低いレベルの抽象化概念(低水準)を分離するようにする。
抽象レベルが揃うと、結果的に、コードは優れた書籍のようになる。
最高水準から中間水準の処理が「書籍の目次」となり、最低水準の処理が、「書籍の本文内容」のようになる
イメージ
function 高水準() { // レベル1の目次
中水準1();
中水準2();
}
function 中水準1() { // レベル2の目次-1
低水準1();
}
function 低水準1() { // 本文内容
// 処理
}
function 中水準2() { // レベル2の目次-2
低水準2();
}
function 低水準2() { // 本文内容
// 処理
}
どうすれば?
関数を構造化する。
関数を構化すると、各関数は自身より1段低いレベルの関数を呼び出す処理が中心となる。このような他の関数を呼び出すコードで構成された関数を「複合関数」と呼ぶ。
複合関数では、処理のレベルが不揃いになるためさまざまな抽象レベルの関数は呼ばない。
function 複合関数() {
処理1();
処理2();
}
function 処理1() {
// 処理
}
function 処理2() {
// 処理
}
OCP
Open-Closed Principle
オープン・クローズドの原則
または、
開放・閉鎖原則
どういうこと?
コードは「拡張に対して開いている」「修正に対して閉じている」という、2つの属性を同時に満たすように設計する。
変更が発生した場合に、既存のコードには修正を加えずに、新しくコードを追加するだけで対応できるような設計にする
(参考: https://qiita.com/sho-hata/items/b6b407858e532d090003 )
どうすれば?
インターフェースを使って設計する。
インターフェースを使って共通のクラスをまとめることで、新たに変更が入った場合もクラスを追加するだけで済むようにする
(参考:https://on-resolve.com/open-closed-principle/)
NG例
class Register {
// アカウント発行する
public function processRegister(string $userType, string $id) {
if ($userType === "student") {
console.log("xx生徒のアカウントを登録しました");
} else if ($userType === "teacher") {
console.log("xx生徒のアカウントを登録しました");
} else {
throw new Error("ユーザタイプが不正です");
}
}
}
// 使用例
$register = new Register();
$register->processRegister("student", "hogehoge");
$register->processRegister("teacher", "fugafuga");
例えば、ここに新たに「事務員」というユーザタイプが追加されたとする。
その場合、条件分岐を追加する必要がある。
このように、新たに属性が追加されるたびにprocessRegister()
を修正する必要がある。
オープンクローズドの原則に沿った例
インターフェースを設計する。
これにより、既存のコードが変更されることなく、機能追加を行うことが可能になる。
interface UserMethod {
public function processRegister(string $id): void;
}
class Student implements UserMethod {
public function processRegister(string $id) {
console.log("xx生徒のアカウントを登録しました");
}
}
class Teacher implements UserMethod {
public function processRegister(string $id) {
console.log("xx生徒のアカウントを登録しました");
}
}
// 使用例
$student = new Student();
$student->processRegister("hogehoge");
$teacher = new Teacher();
$teacher->processRegister("fugafuga");