最近(2015/03/15)これにシフトしてきた。。。
開発フローを見直せば改善できるかも!
http://it.slashdot.jp/story/15/03/03/0423236/
http://el.jibun.atmarkit.co.jp/yamayattyann/2010/05/post-38b5.html
http://agnozingdays.hatenablog.com/entry/2012/08/07/204604
・最初から良い設計は手に入らない
・コードを書いて動かしてみればわかることがたくさんある
・経験から学んだことを反映して 設計の改善を続ける
http://www.slideshare.net/masuda220/ss-67985065
システム→サブシステム→コンポーネント→モジュール→内部モジュール
ソフトウェア業界でなく、自動車業界だけど、参考にはなる。
http://techon.nikkeibp.co.jp/article/COLUMN/20150803/430622/
設計標準化が難しい理由
・設計標準化は、設計高度化の実現において必須の取り組みだが、「総論賛成・各論”大”反対」のテーマである
・標準化において、大は小を兼ねるという概念では競争力を保てず、結果として使われない標準になることが多い
・図面標準化は原因追求をしていない不具合対策のようなもので、設計のやり方を標準化するような設計ルールの標準化の取り組みが必要となる
https://docs.microsoft.com/ja-jp/azure/architecture/guide/architecture-styles/
google考案
何を・なぜ・どのように作るかを記述する
Design Doc はコードや仕様の変化に合わせてガッチリ保守したりはせず、どちらかというと作り捨てに近い
書く内容
http://d.hatena.ne.jp/cou929_la/20091116/1258373100
http://www.atmarkit.co.jp/ait/articles/1606/21/news016.html
http://ryuiki.agbi.tsukuba.ac.jp/~nishida/MEMO/naming.html
名前付けは難しいって話し http://emptypage.jp/translations/kalzumeus/falsehoods-programmers-believe-about-names.html
ソフトウェアで最も大切なのは「振る舞い」であり、振る舞いこそがユーザーの求めるものである
http://www.atmarkit.co.jp/ait/articles/1404/30/news022.html
https://www.tiobe.com/tiobe-index/
http://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017
http://redmonk.com/sogrady/2017/06/08/language-rankings-6-17/
https://stackshare.io
〇〇の情報を取り扱うクラス。
〇〇データと〇〇データ(ファイル名等)を管理する。
〇〇を入力し、〇〇を出力する。
%{color:red}@TODO%
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を一言で説明すると「抽象に依存せよ」という経験則。プログラムは具体的なクラスに依存してはいけない。プログラム内の関係はすべて、抽象クラスかインターフェースで終結すべきである。
あなたには、異なる職能をもった部下がいます。 ソフトウェア開発者と、事務担当です。 今、必要な事務仕事が一つあるのですが、事務担当者は全員手が塞がっています。 さて、あなたは少しいいかげんに、「事務」というのは会社員の基本形で、開発者はそれにソフトウェア開発の技術を付け足したものだと考えました。 つまり、漠然と事務担当は開発者のスーパークラスだと思ったわけです。 そこで、開発者に事務仕事を頼みました。 さて、結果は?
計画案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での観光には影響を与えないということですね。 開放・閉鎖原則は、こんなふうにあなたの暮らしからストレスを減らしてくれます。 あれしよう、これしようと思って、いざやってみるとなかなかうまくいかずに、考えてることの半分もできなかった。 なんて経験がある方、ひょっとして、これを念頭においてやってみると意外とうまくいくかもしれませんよ。
https://qiita.com/MinoDriven/items/5e69d9bd028aa350e2c4
ドメイン名にハイフンは英語圏ではダサいと思われているらしい。。。 だって言葉でいっても接続できないし。数字もしかり。
http://moz.com/blog/how-to-choose-the-right-domain-name
http://www.domainregistration.com.au/infocentre/info-domain-hyphen.php
http://www.steps-to-make-your-own-website.com/hyphen-in-domain.html
http://qiita.com/mserizawa/items/b833e407d89abd21ee72
https://restful-api-guidelines-ja.netlify.com
https://www.ogis-ri.co.jp/otc/hiroba/technical/WebAPI/part2.html http://wp.tech-style.info/archives/683 https://www.wantedly.com/companies/wantedly/post_articles/32977
http://qiita.com/howdy39/items/3b2b14ce73ec44c54f7b
日本語
https://developers.line.me/ja/docs/messaging-api/reference/
http://mb.cloud.nifty.com/doc/current/rest/datastore/objectRegistration.html
英語
https://developer.github.com/v3/issues/
https://cloud.google.com/resource-manager/reference/rest/?hl=ja
https://api.slack.com/methods/channels.create
Webサービス
ローカルでも使える
エンドポイントの名前は単数形と複数形のどちらを使うのが適切でしょうか。 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 はシステム間の依存性を排除するのが存在理由の一つです。 “Web”API だからといって必ずしもインターネットを介した複数のウェブアプリケーションを繋がなければならないわけではなく、一つのシステムを機能単位に区切って分割管理する用途にも使えます。 API で結合された機能同士はお互いの内部仕様に関心を持つ必要がありません。 全ては URI とリクエストメソッドが示す事象によって抽象化されています。
このように「関係を持つのに必要な情報を最低限に抑える」という関係性を疎結合と言います。
システム内部の機能同士が疎結合になることでそれぞれ異なるライフサイクルを持つことが出来ます。
これは、業務単位で機能を分割すればそれぞれ異なるリリースサイクルで運用できる事を意味します。 これこそがシステム内部に WebAPI を持つ最も大きな理由であると僕は思います。
また、システム内部に WebAPI を持てば必然的にモデルの構造も CRUD に準じるようになります。 旧来的な MVC でコントローラーが肥大化しやすかったり、モデルの定義が画一化されにくいのは実装上のバイアスが存在しない点にあります。
開発者それぞれが「俺が考えるスマートな実装」で開発していけば、とあるモデルにはゲッターとセッターがプロパティ単位で実装されていたり、様々な構造のリレーションデータを取得するためのメソッドが大量に実装されていたりと、便利かもしれないけど一貫性が無いために全体像がぼやっとしてしまい、新機能追加の度に八丁味噌のように濃度の高いソースを熟読しなければならないようなことになってしまいます。
これを防ぐためには「クラスの構造を複雑化させにくい状況」が必要です。
そのためにあるのが上述した疎結合と、もう一つが依存性の注入です。 依存性の注入は WebAPI からは少し遠い位置にありますが、疎結合の度合いをより高めるために有効なアプローチです。
従来プログラムではメソッドに対して引数として様々なデータを渡すことで複数の処理を組み合わせています。
しかしこの手法には弱点があります。 それは「呼び出す側が呼び出される側が受け入れる引数についての知識を持っていなければならない」という点です。 この弱点はこれまで書いてきた暗黙知の一種です。 同じシステム内にあるメソッド同士で何を…と思うかもしれませんが、これが例えばロガーだったらどうでしょう。 ロガーには状況に応じてログファイルですとか、Fluentd ですとか、なんかまあ色々とログデータを送りたい先があるはずです。 それら個々に送るためのメソッドを単一のロガークラスに実装するのは非常に煩雑です。 送り先が増える度にロガークラスが肥大化していくわけです。
こうやって一つのところに集中させていくことをモノリシックな実装と言うのですが、これはシステムの透明性と一貫性を損ないます。
これを防ぐ手段としてあるのが依存性の注入です。 上記のロガークラスで言えば、ロガークラスが持つのは「ログストレージに接続する」「ログを送る」という2つのメソッドだけで、ロガークラス自体は”どうやって”接続し、ログを送るのかを知りません。
ロガークラスを使う際に、例えばログファイルの依存性を注入するわけです。
ログファイルの依存性とは、ログファイルを開く方法であり、ログファイルに書き込む方法です。 つまり、 fopen()のような関数を実行するクラスをロガークラスのインスタンス生成時に渡すわけです。
こうすることでロガークラスはどれだけ接続先の種類が増えても複雑化はしません。 ロガークラスは相手が誰で、どんな処理が必要なのかという情報すら知る必要がなく、単に自分の役割だけを理解しています。
これはオブジェクト指向プログラミングにおけるメッセージの仕組み1であり、ウェブの本質(ハイパーリンク)でもあります。
良い設計はシステムの透明性を自律的に保ちます。 WebAPI は非常にシンプルなアプローチでそれを与えてくれます。 しかしながらプログラム言語のように言語仕様として制約を与えることが出来ません。 そのため、シンプルさを損なわないためにも「何故それが必要なのか」という理由を意識し、周りとそれを共有するよう心がけるのが肝要であるかと思います。
https://recompile.net/posts/microservices.html
ログレベル | 説明 |
---|---|
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
handler -> usecase -> domain <- infra
インタプリタ:ノンネイティブな機能を擬似する解釈エンジンにより機能のシミュレーションを行う
ルールベースシステム:作業メモリを持った推論エンジン、ルール群、どのルールによって作業メモリを書き換えるかを決定するコントローラにより構成する
名前 | 説明 |
---|---|
閉鎖性共通の原則(Common Closure) | 同じコンポーネント内のクラスは同種の変更に対して全体として、閉じていなければいけない。ある変更がコンポーネント内の1つのクラスに影響したとしても、その変更がコンポーネント外のクラスに影響を及ぼしてはいけない。言い換えると、複数のコンポーネントにまたがる変更が必要にならないよう、コンポーネント内の凝集度を高めておく必要がある。 |
全再利用の原則(Common Reuse) | コンポーネント内のクラスはまとめて再利用する。コンポーネント内の1つのクラスを再利用する場合には、すべてを再利用する。 |
再利用・リリース等価の原則(Release-Reuse Equvalency) | 再利用とリリースは同じ単位で行う。言い換えると、リリースしたソフトウェア要素の一部だけを再利用すべきではない。 |
非循環依存関係の原則(Acyclic Dependencies) | コンポーネント間の依存関係を循環させてはいけない。例えば、A→B→C→Aという依存は循環するため、認めてはいけない。 |
安定度・抽象度等価の原則(Stable Abstractions) | コンポーネントは抽象的であり、かつ安定していなければいけない。コンポーネントは、安定した状態のまま拡張できるよう、十分に抽象的でなければいけない。 |
安定依存の原則(Stable Dependencies) | より安定したものに対して依存する。例えば、コンポーネントAがコンポーネントBに依存する場合、AよりもBのほうが安定しているべきである(変更の可能性が低いなど)。 |
<役割>として
<機能や性能>が出来る。
それは<ビジネス価値>のためだ。
決定事項と、未決定事項を明確にする
人月の神話 フローチャートは、プログラム・ドキュメンテーションの中で、最も過大評価されている。非常に詳細なフローチャートは、不愉快であるだけでなく、高水準言語で書かれるようになったことで、時代遅れなものになってしまった
これが究極のディレクトリ構成だ!
projname/
|-- app/
|-- bin/
|-- config/
|-- data/
|-- doc/
|-- etc/
|-- lib/
|-- log/
|-- public/
|-- README.md
|-- script/
`-- tmp/
ディレクトリ | 説明 |
---|---|
app/ | |
app/ | |
bin/ | |
config/ | アプリケーション全体の設定 |
data/ | 入力・作成されたファイル、など。eg)uploadされたファイル |
doc/ | ドキュメント |
etc/ | 他のディレクトリに分類されないもの |
lib/ | ライブラリ |
log/ | ログ |
public/ | 公開ファイル,css,htmlなど |
README.md | |
script/ | シェルスクリプトなどのスクリプト言語を格納 |
tmp/ | 一時ファイルなど |
参考:
“C++”:http://hiltmon.com/blog/2013/07/03/a-simple-c-plus-plus-project-structure/
“ruby”:http://www.tutorialspoint.com/ruby-on-rails/rails-directory-structure.htm
アーキテクチャをsuffixとする
noarch bash,perl,pythonとかみたいなアーキテクチャによらないものに付けるので通常は使わない。
参考:
アーキテクチャの種類
http://kazmax.zpp.jp/linux/linux.html
https://www.python.org/dev/peps/pep-0518/#overview-of-file-formats-considered