設計
設計書不要論
最近(2015/03/15)これにシフトしてきた。。。
不要な理由
内容は酷く古い
一貫性も無い
必要な情報が載っていない
プログラムの改修時に設計書を参考にプログラミングをする人間は誰もいない
オブジェクト指向とはそもそも変更に強いため、ドキュメントを書く時間よりも変更になったら作り直したほうが速い。
オブジェクト指向時の開発フロー
プログラマは作る対象である分野の専門知識について、いろいろな書籍を読んで習得する。
要件定義者から要件を口頭で聞く。このとき、オブジェクト指向が分かっている開発者は複数のオブジェクトの相互作用として、システムが動作することを頭に思い浮かべながら、ヒアリングをする。専門用語がそのまま必要なクラスの1つになることもある。
ある程度要件を理解したところで、DBのテーブルの設計を始める。DBのテーブルだけは、作ってから変更を入れる必要があった時、工数が大きくなるので、ここはある程度の熟考が必要になる。
プログラミングを始める。頭の中に、複数のクラスを作り、それを1つひとつ実装していく。
そしてある程度できあがったところで、その時点の成果物を要件定義者に見せて意見を聞く。
要件を完全に理解せずに始めた実装である。おそらく多くの修正依頼が出てくるだろう。
修正する。(オブジェクト指向の基本原則に、SRP(Single Responsible Principle)、つまり「各クラスモジュールの責務は1つだけ」というものがあるため、修正が容易である。変更内容を分割し、分割した変更それぞれが1つひとつのクラス内に収まるようにして、少しずつ変更を入れていくことが可能になる。変更のたびに、あらかじめ作成している自動テストプログラムを走らせる。)
設計書が必要とされるケース
顧客が設計書を求めている
設計者とそれ以降の作業者が分かれている
設計書が他の利害関係者との合意形成に必要
有識者レビューによる品質担保が必要
開発フローを見直せば改善できるかも!
参考リンク
インクリメンタルな設計
・最初から良い設計は手に入らない
・コードを書いて動かしてみればわかることがたくさんある
・経験から学んだことを反映して 設計の改善を続ける
記述すべき内容
エンジニアがプログラムを正しく設計する助けとなる
場当たり的な開発のリスク
機能仕様書によって正しい設計に速く到達できる
機能仕様書によって未決定事項がはっきりする
コミュニケーションにかかる時間を節約する
スケジュールを立てるための基本情報となる
システムの階層構造
システム→サブシステム→コンポーネント→モジュール→内部モジュール
設計標準化
ソフトウェア業界でなく、自動車業界だけど、参考にはなる。
設計標準化が難しい理由
・設計標準化は、設計高度化の実現において必須の取り組みだが、「総論賛成・各論”大”反対」のテーマである
・標準化において、大は小を兼ねるという概念では競争力を保てず、結果として使われない標準になることが多い
・図面標準化は原因追求をしていない不具合対策のようなもので、設計のやり方を標準化するような設計ルールの標準化の取り組みが必要となる
システム設計
クラウドシステム設計
Azure
Joel機能仕様書
注意書:純粋に自己防衛のため。「この仕様書は未完成である。」みたいな1文を入れる
作成者:1人
シナリオ:製品をデザインするときには、人々がそれをどう使うだろうかという現実的で生き生きとしたシナリオが頭の中に入っている必要がある。
対象外
概要:これは仕様書の目次みたいなもの
未解決の問題
傍注:テクニカル・ノート、テスティング・ノート、マーケティング・ノート、ドキュメンテーション・ノート
仕様書は生きている必要がある
Design Doc
google考案
何を・なぜ・どのように作るかを記述する
Design Doc はコードや仕様の変化に合わせてガッチリ保守したりはせず、どちらかというと作り捨てに近い
書く内容
プロジェクトの背景、目的
おおまかな設計(コードを見ただけでは判らないような、アーキテクチャ)
プロジェクトの参加者(このプロジェクトに関して、誰に連絡を取ればいいのか)
セキュリティやプライバシーについての考察(問題と対処方法)
テスト、モニタープラン(運用時の考慮。障害の発見と復旧手法など)
レポジトリ上の位置やサーバのアドレスなど
目的
背景
対応項目
プロジェクトの参加者
スケジュール
仕様
実装
セキュリティやプライバシーについての考察
リスク
既知でオープンな問題
テスト計画
参考文献
リポジトリ
編集履歴
やること
Googleのエンジニアがソフトウエアを開発する際に必ず書くドキュメント。
アイディアが出たら書く。
プロジェクト立ち上げ時に1、2週間かけて書く。
あるソフトウエアについて,何を・なぜ・どのように作るかを端的に記す。
長く、または、詳細を書く必要があるときは、別のプロジェクトを立ち上げるとき。
名前付け
用語
振る舞い
ソフトウェアで最も大切なのは「振る舞い」であり、振る舞いこそがユーザーの求めるものである
プログラミング言語
人気比較
技術選定
プレクラス設計
〇〇の情報を取り扱うクラス。
〇〇データと〇〇データ(ファイル名等)を管理する。
〇〇を入力し、〇〇を出力する。
セキュリティ
%{color:red}@TODO%
5つの設計原則
No.
原則名
説明
1
単一責任(責務)の原則
クラスを変更する理由は1つ以上存在してはならない (SRP:Single Responsibility Principle)
2
オープン・クローズドの原則
ソフトウェアの構成要素(クラス、モジュール、関数など)は拡張に対して開いていなければならず(オープン:Open)、修正に対しては閉じていなければならない(クローズド:Closed) (OCP:Open-Closed Principle)
3
リスコフの置換原則
派生型はその基本型と置換可能でなければならない (LSP:Liskov Substituion Principle)
4
依存関係逆転の原則
a.上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存すべきである DIP:Dependency Inversion Principle) b.「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである
5
インタフェース分離の原則
クライアントに、クライアントが利用しないメソッドへの依存を強制してはならない (ISP:Interface Segregation Principle)
DIP
DIPを一言で説明すると「抽象に依存せよ」という経験則。プログラムは具体的なクラスに依存してはいけない。プログラム内の関係はすべて、抽象クラスかインターフェースで終結すべきである。
リスコフ
あなたには、異なる職能をもった部下がいます。 ソフトウェア開発者と、事務担当です。 今、必要な事務仕事が一つあるのですが、事務担当者は全員手が塞がっています。 さて、あなたは少しいいかげんに、「事務」というのは会社員の基本形で、開発者はそれにソフトウェア開発の技術を付け足したものだと考えました。 つまり、漠然と事務担当は開発者のスーパークラスだと思ったわけです。 そこで、開発者に事務仕事を頼みました。 さて、結果は?
オープン・クローズドの原則
計画案1 出発(9:00)→2時間→観光地A 昼食もとる(~14:00)→1時間→観光地B(~18:00)→移動30分→ホテル到着(18:30)
計画案2 出発(9:00)→2時間→観光地A到着(11:00)→A'を観る(11:00~11:30)→A''で遊ぶ(11:30~12:00)→昼食(12:00~13:00)→A'''を散策(13:00~14:00)→1時間→観光地B到着(15:00)→…以下略
どうでしょうか? どっちが失敗しにくい計画でしょう? といっても、もちろん計画する人や参加する人の性格、計画性や体力、実行力など、いろいろな状況によって左右されますので、実際にはなんとも言えませんよね。 でも、今回着目する側面から言うと、1の計画のほうがベターということになります。 なぜか? はい、計画を拡張しても問題になりにくいからです。 この場合、観光地A、観光地Bでの観光がそれぞれオブジェクトだと捉えることができます。 それぞれの到着時間と出発時間がインターフェイスです。 (すでに契約をご存知の方は、事前条件と事後条件であると捉えていただいても結構です。そもそも、インターフェイス自体が、広い意味で契約の一部ですし) 計画案1では各観光地の到着時間は決めていません。 インターフェイスには出発時間しかありませんね。 (事前条件はなしということですね) で、ポリモーフィズムを考えると、それぞれのオブジェクトは、インターフェイスに違反しない限り、勝手に振舞えるはずですよね。 でも、計画案2の場合はどうです? 参加者の誰かが、実は観光地Aでもうひとつやりたいことがあると強情に言い出したら、難しいことになります。 その余分な行動をカバーするのに、あなたには2つの選択肢があります。 以降の計画の時間を後ろだおすために、(頭の中でも紙の上でもいいですが)全て再計算する。 代わりにどれかの行動を取りやめる。 ただし、細かい計算ですから、観光地内での歩行時間まで考慮に入れて、どの行動をやめるべきか慎重に決定する必要があるかもしれませんね。 どちらも面倒で、骨の折れることですね。 計画案1の場合は? そもそも、観光地Aの中で何をするのかまでは決めていないんですから、そんなの変更でも何でもありませんね。 とにかく14:00に出発できさえすれば、なんの問題もありません。 では、もし渋滞にはまっちゃったらどうでしょう? 計画案2を採用された方は、前の車のテールランプを眺めながら、どれだけのストレスを抱えてらっしゃるのか。 その方の胃が心配です。 計画というのは、紙に書いたりして参加者に伝えた段階で、「守るべきもの」になってしまいます。 観光やプライベートなものであっても、軽々しくあれもこれもと細かいことを詰め込んだりしないことをオススメします。 ストレスにさらされるより、気楽に楽しみたいですからね。 まして、仕事や責任のあることなら、なおさらです。 がんばって細かいことを決めれば決めるほど、逆に失敗する可能性が高まるわけですから。 ただし、注意してください。 これは計画をイイカゲンにやれというわけでも、ましてや計画を立てるなということを言ってるわけではありませんよ。 計画は必要最小限にとどめようということです。 ソフトウェア開発者の方向けに言えば、「守るべきもの」とはプライベートでないメンバやオーバーライド可能なメンバのことです。 そういったメンバを作るときに注意深くすることで、失敗の可能性を減らせるケースは非常に多くあります。 さてさて、原則の言わんとしてるところは、わかっていただけましたでしょうか? では、最初に戻って「拡張に対して開いている」とはどういうことでしょう?また、「修正に対して閉じている」とはどういうことでしょう? 「拡張に対して開いている」とは、オブジェクトの振る舞いを拡張できるということです。 今回の例で言えば、観光地AやBそれぞれの中での観光の仕方を、好きに変えたり増やしたりできるということですね。 「修正に対して閉じている」とは、それでも他のオブジェクトに影響を与えたりしないということです。 今回の例で言えば、たとえば観光地Aの中で何をするのかを変えても、観光地Bでの観光には影響を与えないということですね。 開放・閉鎖原則は、こんなふうにあなたの暮らしからストレスを減らしてくれます。 あれしよう、これしようと思って、いざやってみるとなかなかうまくいかずに、考えてることの半分もできなかった。 なんて経験がある方、ひょっとして、これを念頭においてやってみると意外とうまくいくかもしれませんよ。
DDD(ドメイン駆動開発)
Value Object
Webサービス
ドメイン名
ドメイン名にハイフンは英語圏ではダサいと思われているらしい。。。 だって言葉でいっても接続できないし。数字もしかり。
GET,POST,PUTの使い分け
GET /tickets - チケットのリストを取得する
GET /tickets/12 - 指定したチケットの情報を取得する
POST /tickets - 新しいチケットを作成する
PUT /tickets/12 - チケット #12 を更新する
PATCH /tickets/12 - チケット #12 を部分的に更新する
DELETE /tickets/12 - チケット #12 を削除する
WebAPI
REST API
規約
わかりやすい解説
RESTfulなURLにしよう
いつ何時も、SSL通信を使おう
かっこいい仕様書を作ろう
バージョンはURLに含めよう
フィルタ・ソート・検索はリクエストパラメータでやろう
レスポンスのフィールドを絞れるようにしよう
作成・更新の後は変更後の情報をフルで返そう
HATEOASを採用するのは待とう
可能な限りJSONで返そう
フィールドの命名規則を考えよう
JSONはデフォルトで整形しよう
要素はラップせずに返そう
追加・更新時のリクエストボディにはJSONを使おう
ページング情報はレスポンスヘッダに入れよう
関連データを埋め込む手段を作ろう
HTTPメソッドを上書きしよう
リクエスト制限情報はレスポンスヘッダに入れよう
トークン認証を使おう
キャッシュの情報をレスポンスヘッダに入れよう
ちゃんとしたエラーメッセージを返そう
HTTPステータスコードを有効活用しよう
REST APIのドキュメント・リファレンス
日本語
英語
REST APIドキュメント作成ツール
Webサービス
Apiary.io (API Blueprint(markdown拡張))
API Blueprint (API Blueprint(markdown拡張))
Swagger (yaml)
ローカルでも使える
iodocs (Json Scheme)
aglio + api-mock (API Blueprint(markdown拡張))
ドキュメント記述記法
JSON Schema
RAML
WADL
Swagger
Apiary
API設計の勘所
できる限り Web の標準に従うこと
開発者に親切な作りにすること。 また、ブラウザのアドレスバーから叩けるようにすること
シンプルで一貫性を持たせ、直感的かつ心地よく使えるようにすること
Enchant(本体のサービス)が提供する機能を十分に活用できるものにすること
様々な要件とのバランスを保ちつつ、効率的に開発ができるようにすること
エンドポイント
エンドポイントの名前は単数形と複数形のどちらを使うのが適切でしょうか。 KISS の原則に従えば、答えは「一貫して複数形を使う」です。
エンドポイントを主語、リクエストメソッドを述語として要求を伝えているわけです。動詞は主語足りえませんので、エンドポイントの名前に動詞を使うべきではないのです。
バージョン
API は必ずバージョン管理しましょう。 バージョン管理することで開発速度を速められますし、廃止された仕様でのリクエストを弾いたり、メジャーアップデートがあるような場合に、移行期間として過去バージョンと共存させることもできます。
フィルタ・ソート・検索はリクエストパラメータでやろう
フィルタリング
各フィールドに対して、フィルタリングをするためのパラメータを用意しましょう。 例えば、 /ticketsでチケットのリストを取得する際に、state が open のものだけに絞りたいことがあると思います。 このような要望はGET /tickets?state=openのようにして実現させましょう。 リソースの項目であるstateをそのまま、フィルタするためのリクエストパラメータとするのです。
ソート
並び順の指定については、 sortパラメータを用意して処理するようにしましょう。 複雑なソートにも応えられるように、ソート対象とする項目をカンマ区切りで指定して、かつ、昇順・降順をネガポジで指定するようにします。 いくつか例を挙げてみます。
GET /tickets?sort=-priority - チケットのリストを priority の降順で取得する
GET /tickets?sort=-priority,created_at - チケットのリストを priority の降順、かつ created_at の昇順で取得する
検索
フィルタクエリでは事足りず、全文検索が必要になることもあると思います。 おそらく、 ElasticSearchや他のLuceneベースの検索エンジンを使うことになると思いますが、特定リソースに対して投げるクエリには、 qパラメータを使いましょう。 検索クエリはそのまま全文検索エンジンに伝えられ、API のアウトプットは普段と変わらない形式となります。
以上を組み合わせてみると、以下のような感じでリクエストパラメータが構築できます。
GET /tickets?sort=-updated_at - 最近更新されたチケットを取得する
GET /tickets?state=closed&sort=-updated_at - 最近クローズされたチケットを取得する
GET /tickets?q=return&state=open&sort=-priority,created_at - オープン状態で優先度の高いチケットのうち、「return」という単語を含むものを返す
レスポンスのフィールドを絞れるようにする
API 利用者は、常にリソースの全項目を必要としているわけではありません。 レスポンスのフィールドを絞る手段を用意することは、API 利用者のネットワーク負荷を下げ、通信速度を向上させることに貢献します。
GET / tickets? Fields = id, subject, customer_name, updated_at & state = open & sort = -updated_at
作成・更新の後は変更後の情報をフルで返そう
created_at や updated_at といった項目は、こちらが明示的に指定するものではなく、作成・
更新の際にサーバが自動で挿入するものです。 API 利用者が作成・更新後のリソース情報を取得するためにもう一度 API を叩くのは大変なので、POST, PATCH, PUT リクエストのレスポンスには変更後のリソースの情報を含めるようにしましょう。
なお、POST で新しくリソースを作成した際には、 ステータスコード201を返し、 Locationヘッダに作成されたリソースへの URL を含めるのが良いです。
WebAPIの利点
WebAPI はシステム間の依存性を排除するのが存在理由の一つです。 "Web"API だからといって必ずしもインターネットを介した複数のウェブアプリケーションを繋がなければならないわけではなく、一つのシステムを機能単位に区切って分割管理する用途にも使えます。 API で結合された機能同士はお互いの内部仕様に関心を持つ必要がありません。 全ては URI とリクエストメソッドが示す事象によって抽象化されています。
このように「関係を持つのに必要な情報を最低限に抑える」という関係性を疎結合と言います。
システム内部の機能同士が疎結合になることでそれぞれ異なるライフサイクルを持つことが出来ます。
これは、業務単位で機能を分割すればそれぞれ異なるリリースサイクルで運用できる事を意味します。 これこそがシステム内部に WebAPI を持つ最も大きな理由であると僕は思います。
また、システム内部に WebAPI を持てば必然的にモデルの構造も CRUD に準じるようになります。 旧来的な MVC でコントローラーが肥大化しやすかったり、モデルの定義が画一化されにくいのは実装上のバイアスが存在しない点にあります。
開発者それぞれが「俺が考えるスマートな実装」で開発していけば、とあるモデルにはゲッターとセッターがプロパティ単位で実装されていたり、様々な構造のリレーションデータを取得するためのメソッドが大量に実装されていたりと、便利かもしれないけど一貫性が無いために全体像がぼやっとしてしまい、新機能追加の度に八丁味噌のように濃度の高いソースを熟読しなければならないようなことになってしまいます。
これを防ぐためには「クラスの構造を複雑化させにくい状況」が必要です。
そのためにあるのが上述した疎結合と、もう一つが依存性の注入です。 依存性の注入は WebAPI からは少し遠い位置にありますが、疎結合の度合いをより高めるために有効なアプローチです。
従来プログラムではメソッドに対して引数として様々なデータを渡すことで複数の処理を組み合わせています。
しかしこの手法には弱点があります。 それは「呼び出す側が呼び出される側が受け入れる引数についての知識を持っていなければならない」という点です。 この弱点はこれまで書いてきた暗黙知の一種です。 同じシステム内にあるメソッド同士で何を…と思うかもしれませんが、これが例えばロガーだったらどうでしょう。 ロガーには状況に応じてログファイルですとか、Fluentd ですとか、なんかまあ色々とログデータを送りたい先があるはずです。 それら個々に送るためのメソッドを単一のロガークラスに実装するのは非常に煩雑です。 送り先が増える度にロガークラスが肥大化していくわけです。
こうやって一つのところに集中させていくことをモノリシックな実装と言うのですが、これはシステムの透明性と一貫性を損ないます。
これを防ぐ手段としてあるのが依存性の注入です。 上記のロガークラスで言えば、ロガークラスが持つのは「ログストレージに接続する」「ログを送る」という2つのメソッドだけで、ロガークラス自体は”どうやって”接続し、ログを送るのかを知りません。
ロガークラスを使う際に、例えばログファイルの依存性を注入するわけです。
ログファイルの依存性とは、ログファイルを開く方法であり、ログファイルに書き込む方法です。 つまり、 fopen()のような関数を実行するクラスをロガークラスのインスタンス生成時に渡すわけです。
こうすることでロガークラスはどれだけ接続先の種類が増えても複雑化はしません。 ロガークラスは相手が誰で、どんな処理が必要なのかという情報すら知る必要がなく、単に自分の役割だけを理解しています。
これはオブジェクト指向プログラミングにおけるメッセージの仕組み1であり、ウェブの本質(ハイパーリンク)でもあります。
良い設計はシステムの透明性を自律的に保ちます。 WebAPI は非常にシンプルなアプローチでそれを与えてくれます。 しかしながらプログラム言語のように言語仕様として制約を与えることが出来ません。 そのため、シンプルさを損なわないためにも「何故それが必要なのか」という理由を意識し、周りとそれを共有するよう心がけるのが肝要であるかと思います。
マイクロサービス
サービスによるコンポーネント化:ライブラリではなく別プロセスで動作するサービスによってアプリケーションのコンポーネント化を実現している。
ビジネスケイパビリティに基づく組織化:役割ごとにチームが構成されるのではなく、複数の役割が混在したチームがひとつのサービスを構築する。(コンウェイの法則!)
プロジェクトではなくプロダクト:コンポーネントは期限のあるプロジェクトとして開発されるではなく、継続的なプロダクトとして提供される。
スマートエンドポイント、ダムパイプ:サービス間のメッセージは、HTTP経由でAPI呼び出しされるか、RabbitMQやZeroMQといった軽量メッセージングシステムによる通信で交換される。
分散ガバナンス:サービスごとに言語やデータベースなどは統一されず、個別に適切なものが選択される。
分散データ管理:サービスごとにデータを持ち、統合されていない。
インフラストラクチャ自動化:継続的デリバリが実現され、自動テスト、自動デプロイなどが採用されている。
障害設計:構成されるサービスの障害に耐性を持つように設計されている。
進化的設計:各サービスごとに変更が行なわれ、漸進的に設計がされる。
ログ設計
ログレベル
ログレベル
説明
FATAL/Critical
致命的なエラー。プログラムの異常終了を伴うようなもの。コンソール等に即時出力することを想定
ERROR
エラー。予期しないその他の実行時エラー。コンソール等に即時出力することを想定
WARN
警告。廃要素となったAPIの使用、APIの不適切な使用、エラーに近い事象など、実行時に生じた異常とは言い切れないが正常とも異なる何らかの予期しない問題。コンソール等に即時出力することを想定
INFO
情報。実行時の何らかの注目すべき事象(開始や終了など)。コンソール等に即時出力することを想定。従ってメッセージ内容は簡潔に止めるべき
DEBUG
デバッグ用の情報。システムの動作状況に関する詳細な情報。コンソールではなくログ上にだけ出力することを想定
TRACE
トレース情報。更に詳細な情報。コンソールではなくログ上にだけ出力することを想定
Notice
通知メッセージ
Alert
critよりも重大なエラー
Emergency
サーバが稼動できないほどの重大なエラー
ネットワーク設計
ネットワーク構成図
【物理構成図】
OSI階層モデルでいうL1,L2、つまり機器同士の接続関係、つまりLANケーブルの敷設やラッキング、機器の接続
○記述内容
・配置場所(フロア、ラック)
・物理的なネットワーク機器の接続
・機種/機種名
・osのバージョン
・設置場所
・接続ポート
・L3/L2switch
・回線の速度
○ポイント
・機器を省略しない
・これとは別にラック構成図、フロア図を作成する
【論理構成図】
論理構成図の目的はここからOSI階層モデルでいうL3の設定(ルーティング、ACLなど)設定
○記述内容
・機種/機種名
・IPアドレス/サブネットマスク
・ホスト名
・VLAN
・冗長化の設定
○ポイント
・1枚にまとめること(まとめるために一部機器は省略L2SWなど)
・セグメント毎、拠点毎など色分けしたりするとわかりやすい
・機器は省略可能。L3以上
・サーバ、ネットワーク機器など凡例で分ける
アーキテクチャ
用語
意味
アーキテクチャ
ソフトウェアシステムのサブシステムとコンポーネント、およびそれらの間の関係に関する記述である。サブシステムとコンポーネントは、ソフトウェアシステムの中で、関連を持つ機能特性と非機能特性を表現する複数の異なったビューにより規定される。システムのソフトウェアアーキテクチャはソフトウェア設計作業の成果物である。
アーキテクチャ
ソフトウェアシステムのサブシステムとコンポーネント、およびそれらの間の関係に関する記述である。サブシステムとコンポーネントは、ソフトウェアシステムの中で、関連を持つ機能特性と非機能特性を表現する複数の異なったビューにより規定される。システムのソフトウェアアーキテクチャはソフトウェア設計作業の成果物である。
アーキテクチャパターン
複数のソフトウェアアーキテクチャの構造上の特徴を捉えたアーキテクチャのクラス。クラス、インスタンス、及びコンポーネントレベル以上の抽象概念を定式化する。アーキテクチャパターンの例には、MVC、ORBなどがある。
アーキテクチャスタイル
アーキテクチャパターンと同義だが、様式という語感を持つこともあるアーキテクチャフレームワークの選択、ミドルウェア、推奨される一連のパターン、またはアーキテクチャ説明の技術やツールによって定義される。アーキテクチャスタイルの例には、パイプ-フィルタ型、クライアント-サーバ型、イベント駆動型などがある。
レイヤアーキテクチャ
UI -> アプリケーション -> モデル <- インフラストラクチャ
クリーンアーキテクチャ
UI -> Controllers,Gateways -> Usecase -> Domain Model
ヘキサゴナルアーキテクチャ
Adapter -> application
pospomeさんのアーキテクチャ
handler -> usecase -> domain <- infra
データフローシステム
バッチシーケンシャル:データ処理の分野で従来から採用されてきたいわゆるバッチ処理に相当するパターン
パイプとフィルタ(Pipes and Filters):データストリームに対して段階的、追加的に処理を行う際に用いられるパターン
プロセスコントロール :連続的な入力を動的に管理し、出力の特性を特定の目標に照らして維持したい場合に用いられるパターン
コール/リターンシステム
メインプログラムとサブルーチン:プログラムを小さなモジュールに分割することにより、変更容易性や拡張性を向上させ、また分担開発を可能にすることを狙ったパターン
オブジェクト指向システム:抽象データの考え方を踏襲し、手続きとデータをクラスとしてカプセル化することで、変更容易性や再利用性を高めるパターンである。
階層的レイヤ(Layers):適当数の階層の各層に、実行上の役割の異なるコンポーネントを割り当て、各層の間のやりとりを制御することにより、変更を局所化し、変更容易性や拡張性を向上させるパターン
独立コンポーネント
クライアント/サーバ:ユーザの機能を実現するクライアントと、クライアントに対するサービスを実現するサーバーで構成する。
イベントシステム:各コンポーネントがイベントを発行すると、それに関心のあるコンポーネントはそれを通知され、それぞれ応答する。
ブローカ(Broker):ブローカ、プロキシ、ブリッジなどのコンポーネントが、クライアントとサーバの間のやり取りを仲介する
インタラクティブシステム
MVC(Model-View-Controller):コアデータや機能を管理するモデル、ユーザへの情報提示をするビュー、ユーザとのインタラクションを行うコントローラにより構成
PAC(Presentation-Abstraction-Control):エージェントを木構造に構成、各エージェントは外部から見える振る舞いを提供するプレゼンテーション、データモデルを管理するアブストラクション、他のエージェントと通信する制御の3つのコンポーネントから構成
仮想マシン
インタプリタ:ノンネイティブな機能を擬似する解釈エンジンにより機能のシミュレーションを行う
ルールベースシステム:作業メモリを持った推論エンジン、ルール群、どのルールによって作業メモリを書き換えるかを決定するコントローラにより構成する
データ中心システム
リポジトリ:データを集中管理する共有データと、それに対するアクセスを行う複数のクライアントから構成される
黒板(Blackboard):データを集中管理する黒板、処理を行い黒板を更新する知識ソース、および全体を制御するコントロールで構成。更新があると関心のある購読者に通知するなどする
適応システム
マイクロカーネル(Microkernel):基盤機能をカプセル化したマイクロカーネル、マイクロカーネルでは実現できない機能を提供する内部サーバ、マイクロカーネルに新たなインタフェース(ビュー)を与える外部サーバから構成
リフレクション(Reflection):メタオブジェクトという形態でシステム構造と振る舞いの自己記述を提供するメタレベル、メタオブジェクトを用いてアプリケーションロジックを定義するベースレベル、及び両者の橋渡しをするメタオブジェクトプロトコルから構成
ネームスペース(パッケージ)設計
名前
説明
閉鎖性共通の原則(Common Closure)
同じコンポーネント内のクラスは同種の変更に対して全体として、閉じていなければいけない。ある変更がコンポーネント内の1つのクラスに影響したとしても、その変更がコンポーネント外のクラスに影響を及ぼしてはいけない。言い換えると、複数のコンポーネントにまたがる変更が必要にならないよう、コンポーネント内の凝集度を高めておく必要がある。
全再利用の原則(Common Reuse)
コンポーネント内のクラスはまとめて再利用する。コンポーネント内の1つのクラスを再利用する場合には、すべてを再利用する。
再利用・リリース等価の原則(Release-Reuse Equvalency)
再利用とリリースは同じ単位で行う。言い換えると、リリースしたソフトウェア要素の一部だけを再利用すべきではない。
非循環依存関係の原則(Acyclic Dependencies)
コンポーネント間の依存関係を循環させてはいけない。例えば、A→B→C→Aという依存は循環するため、認めてはいけない。
安定度・抽象度等価の原則(Stable Abstractions)
コンポーネントは抽象的であり、かつ安定していなければいけない。コンポーネントは、安定した状態のまま拡張できるよう、十分に抽象的でなければいけない。
安定依存の原則(Stable Dependencies)
より安定したものに対して依存する。例えば、コンポーネントAがコンポーネントBに依存する場合、AよりもBのほうが安定しているべきである(変更の可能性が低いなど)。
ユーザストーリ
<役割>として
<機能や性能>が出来る。
それは<ビジネス価値>のためだ。
いいユーザストーリを作るためには INVEST
I – Independent (独立して優先順位がつけられる)
N – Negotiable (何をつくるかの案が調整可能である)
V – Valuable (ビジネス価値のある)
E – Estimable (見積り可能である)
S – Small(チームで扱いやすい手頃なサイズである)
T – Testable(テストできる)
機能仕様書に書くべきこと
エンジニアがプログラムを正しく設計(デザイン)する助けとなる
設計の共有・見直しや修正が非常に簡単にでき、結果的に開発期間の短縮になる
決定事項と、未決定事項を明確にする
コミュニケーションにかかる時間を節約する
スケジュールを立てるための基本情報となる
フローチャート
人月の神話 フローチャートは、プログラム・ドキュメンテーションの中で、最も過大評価されている。非常に詳細なフローチャートは、不愉快であるだけでなく、高水準言語で書かれるようになったことで、時代遅れなものになってしまった
フローチャートがまともに記述できるのは「手続き」だけだ
フローチャートで書くのが困難なのは、OOPだけではない。関数型はもっとそう
フローチャートは、関数型を排除した手続き型パラダイム限定で[しか適用できない]。
フローチャートのどこが抽象化なのかと。
並列処理とかでなければ、フローチャートは設計した結果を記述するのには使える。
高級言語でプログラミングするのに、フローチャートは害の方が大きいと思う。
ある一つの処理の順序しか表せない。そのため...
プログラム内に複数並行に動く処理がある場合、他の処理との関係が示せない。
また、プログラム全体像を、俯瞰したものにしにくい。
アルゴリズムの表現であるため、その処理の意味・役割が見え難い。
プログラムは、データを処理するためにあり、データの違いによって制御の流れ が変更されます。あくまでも、データが主体です。変数、引数などのデータをどう定義するかで、 プログラムの組易さは大幅に改良されます。データ構造がどうなっているかの図の方が、フローチャー トよりはるかに役立ちます。
ここではフローチャートの是非を論じるつもりはない。クソだから。もっと一般化してしまえば、○○設計書みたいに「設計書」と名のつくものは全部クソだ。だって動かないんだもん。
もちろん、机上検証で見つかる凡ミスもあるだろうけど、そんなのはズボンもパンツも履かずに会社に向かうのと同じくらいのレベルの間違いだろう。
抽象的な表現を徐々に具体表現に落としてきているわけだから、コードのある部分を変更したときに影響を受ける設計書の範囲を特定するのは簡単ではない。仮に頑張ってそこを特定し、設計書を修正したとしても、今度は各設計書間の整合性を確認するのに膨大な時間がかかる。つまりお金がかかる。
ディレクトリ設計
これが究極のディレクトリ構成だ!
ディレクトリ
説明
app/
app/
bin/
config/
アプリケーション全体の設定
data/
入力・作成されたファイル、など。eg)uploadされたファイル
doc/
ドキュメント
etc/
他のディレクトリに分類されないもの
lib/
ライブラリ
log/
ログ
public/
公開ファイル,css,htmlなど
README.md
script/
シェルスクリプトなどのスクリプト言語を格納
tmp/
一時ファイルなど
参考:
ライブラリ
選定基準
GitHubにリポジトリを持つこと
Starが100以上ついていること
直近1年でコミットがあること
コミットの頻度が1回/月以上あること
Issue/Pull requestが放置されていないこと
ライブラリ依存が少ないこと
アプリケーション本体と疎結合に導入できること
ドキュメントが充実していること
検索エンジンで情報が十分に収集できること
必要としているテストケースにパスしていること
リリースパッケージ
アーキテクチャをsuffixとする
i686
x86_64
src
など。
noarch bash,perl,pythonとかみたいなアーキテクチャによらないものに付けるので通常は使わない。
参考:
アーキテクチャの種類
設定ファイル
JSONとYAMLとTOMLどれがいいんだ問題
Last updated