これはテストです。
Chapter 1 - Intruduction / A Philosophy of Software Design
A Philosophy of Software Design の第1章を読んだのでそのまとめ。
Intro
- プログラムは機能が増えるごとに複雑さが増していく。複雑さが増えると、開発スピードが遅くなりバグが増える
- 開発ツールは複雑性に対処するに役立つが、これには限界がある。一方、シンプルなソフトウェアのデザインはより大きくてパワフルなプログラムを導いてくれる。
- 複雑性に対処するには2つのアプローチがある。
- 1つ目はコードをシンプルかつ明らか(わかりやすく)すること。例えば複雑性は特殊ケースを削除することで減らすことができる。
- 2つ目のアプローチはカプセル化でmodular design とよばれている。
- Modular designではソフトウェアをモジュールに分割して管理して(OOPだとクラスとか)それぞれのモジュールは他のものに依存しない。
- そのため、プログラマーはあるモジュールの開発をするときに、他のモジュールの詳細を知らなくて済む。
ウォーターフォールモデルの紹介
- ウォーターフォールだと基本的には設計フェーズではすべてを設計し、開発のフェーズでは設計をしない。ソフトウェアは物理的なシステムより複雑で目に見えないので、特に大きなシステムであるほど全体を細部まで理解することは難しい。
- 開発フェーズで初めて問題がわかるケースもよくあり、場合によっては設計のやり直しが発生する。ウォーターフォールモデルだとこれは大きな手戻りになってしまう。
- この問題があるため、最近のソフトウェア開発ではアジャイルのようなインクリメンタルなアプローチが使われている。
How to use this book
ソフトウェアの設計スキルを向上させるための良い手法の一つは、"red flags"という複雑なソースコードの断片のサインを認識することである。この本ではその"red flags"を、メジャーな設計の問題を通じて説明する。
A Philosophy of Software Designを読み始めた
タイトル通りで、最近第2版が発売されたのと、いろんなところでオススメされていたのでこの本を読んでいる。やっと第6章まで読み終わったので、それぞれの章のまとめをブログにアップしていく予定。
以下は読んだ章のINDEX.
- Chapter 1 - Intruduction / A Philosophy of Software Design - oinume journal
- Chapter 2 - The Nature of Complexity / A Philosophy of Software Design - oinume journal
- Chapter 3 - Working Code Isn’t Enough / A Philosophy of Software Design - oinume journal
- Chapter 4 - Modules Should Be Deep / A Philosophy of Software Design - oinume journal
- Chapter 5 - Information Hiding (and Leakage) / A Philosophy of Software Design - oinume journal
JavaScriptの記号の演算子と構文
JavaScript / TypeScript では一見すると「これなんだ?」という記号の演算子や構文がよく出てくるので、自分用の備忘録としてメモしておく。式と演算子 - JavaScript | MDNには演算子の一覧のページがあるため、わからない記号が出てきたら以下のページを見るとだいたい載っているはず。
?? - Nullish coalescing operator
- Null 合体 (??) - JavaScript | MDN
- Null 合体演算子 (??) は論理演算子の一種です。この演算子は左辺が null または undefined の場合に右の値を返し、それ以外の場合に左の値を返します。
- 例えば以下のコードだと、aがnull or undefinedの場合は
a is null or undefined
がvalに代入される
const val = a ?? 'a is null or undefined';
!! - Double not operator
- Logical NOT (!) - JavaScript | MDN
- 複数の否定演算子を連続して使用することで、明示的にあらゆる値を対応する論理型プリミティブに変換することができます。
- 否定の否定なので肯定ということになり、元の値をbooleanに変換するということらしい
const val = !!a; // val is always boolean
?. - Optional chaining operator
- オプショナルチェーン (?.) - JavaScript | MDN
?.
演算子の機能は . チェーン演算子と似ていますが、参照が nullish (null または undefined) の場合にエラーとなるのではなく、式が短絡され undefined が返されるところが異なります。関数呼び出しで使用すると、与えられた関数が存在しない場合、 undefined を返します。
const val = a?.b?.c; // aがnull or undefinedの場合 val が undefinedになる
... - Spread syntax
- スプレッド構文 - JavaScript | MDN
- スプレッド構文 (...) を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値のペア (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。
- 一番多用されるのは配列やオブジェクトをコピーするときなのではないかと思われる
const arr = [1, 2, 3]; const arr2 = [...arr]; // arr.slice()みたいな
! - Non-null assertion operator
これはJavaScriptではなくてTypeScriptにしかない演算子。
- TypeScript: Documentation - TypeScript 2.0
- 以下のようなコードの時に、
e
がundefinedまたはnullではないことを保証して、name
にアクセスできる
// Compiled with --strictNullChecks function validateEntity(e?: Entity) { // Throw exception if e is null or invalid entity } function processEntity(e?: Entity) { validateEntity(e); let s = e!.name; // Assert that e is non-null and access name }
TypeScriptのDestructuring assignment
最近仕事でfrontendの開発を少しずつやるようになったのだけど、TypeScriptはGoに比べて演算子や記号を使う記法が多くて読むのに一苦労する。なので「これなんだろう?」と思ったやつをメモしておく。
TypeScriptやっていて一番最初に「ん?」と思ったのは、以下のような構文だった。
const obj = { title: 'hello' } const { title: myTitle } = obj // ★ console.log(myTitle) // "hello"
★のコードでは
- obj というオブジェクトから title という要素を取り出して
- myTitleという定数を宣言
- myTitleに 1. で取り出した要素を代入する
ということをやっている。myTitle
が定数宣言であるのに対して、キーのtitle
は単純にオブジェクトのキーなので特に何かが宣言されているわけでない、ということが初めはわかっていなかったのでこの構文を見るたびに頭が混乱していた。
調べてみると、これはJS由来の構文でDestructuring assignment
と呼ぶらしい。
上の例ではオブジェクトから要素を取り出す例だったが、当然配列から特定の要素を取り出すこともできる。
const array = [1, 2] const [ first, second ] = array console.log(first) // 1
さらにスプレッド構文 ...
を使って以下のような代入も可能。
[a, b, ...rest] = [10, 20, 30, 40, 50]; console.log(rest); [30, 40, 50]
Goと違って多値が返せないからこういう構文が必要になるのかなと思ったのだけど、どうなんだろう?