100人のプロが選んだソフトウェア開発の名著 後編

プロが選んだソフトウェア開発の名著 後編

前回の続きです。51以降も読みたい本がたくさんありました。

持っていてもう一度読みたい本

  • XPエクストリーム・プログラミング入門

    ケント・ベックの本。アジャイルの原点とも言えます。今読むと原点に帰って今の状況を俯瞰できるかもしれません。わたしが持っているのは古い方です。

  • 人月の神話

    ソフトウェア開発のプロジェクトを成功に導くために必要な原理原則が書かれています。

  • 達人プログラマー

    偉大なプログラマになるための指針が書かれています。忘れそうになったときに何度も繰り返し読みたい本です。

  • スーパーエンジニアへの道

    ちょっと手を出しづらいタイトルですが、ミックさんが紹介していて、無駄なページが1ページもないとおっしゃっているので是非読みたいです。この紹介文が書かれた時点で20年前の本ということは、30年前の本ということです。確認したら1991年初版発行でした。こちらもワインバーグさんの本です。

  • アジャイルプラクティス

    最近スプリントがうまく回せていないので、もう一度手法を見直したいです。

  • アジャイルな見積もりと計画作り

    アジャイルプラクティスと同様、スプリントがうまく回せていないので読みたいです。

  • 情熱プログラマー

    最近チケット作成など管理系の仕事が多くてうんざりしています。仕事が楽しくできてないので、初心を取り戻すべく読んでみたいと思います。

  • 達人に学ぶSQL徹底指南書

    ここで紹介されているのは第1版です。紹介されいている時代は第2版はまだ出てないです。わたしはこの本を読んでcase式についてしっかり理解してからSQLの幅がグッと広がったのを感じました。とても良い本です。いつでも再読したい本です。

  • エンタープライズアプリケーションアーキテクチャパターン

    ActiveRecordなど今あるアーキテクチャパターンはほとんどこの本で説明されています。オブジェクト指向に傾倒しているわたしとしてはマーチン・ファウラーさんの本は読まないわけにはいきません。

持っていないけど読みたい本

  • コンピュータアーキテクチャのエッセンス

    紹介している前田修吾さんは計算機科学の専門教育を受けずにプログラマになった。そのことで大変な思いをしたので、同じような人にこの本を薦めたいとのこと。自分も物理専攻で計算機科学の専門教育を受けておらずちょっとしたコンプレックスを感じることがあります。というか、情報系の授業を受けていた人たちが羨ましいです。

  • コンサルタントの秘密

    ワインバーグさんの本。紹介してくれている方もワインバーグさんの他の著書も読んでみてはどうか?と言っています。

  • ソフトウェア・テストの技法

    なかなかテストコードを書く習慣がつかない自分を戒めてくれるのではないかと期待しています。

まとめ

後編もボニュームのある本がそろっていました。比較的古い本が多いですが、紹介されてから10年経った今も色褪せてないことは間違いないでしょう。読み終わったら紹介します。

100人のプロが選んだソフトウェア開発の名著

プロが選んだソフトウェア開発の名著

本棚を整理していたら、100人のプロが選んだソフトウェア開発の名著が出てきました。本が好きなので、本を紹介する本は読みたくなってしまいます。2012年出版の本ですが、内容や紹介されている本はプロが選んでいるだけあって、長年読まれている名著ばかりで古い感じはありません。持っていてもう一度読みたい本、持ってないけど読みたい本をリストアップしたいと思います。

持っていてもう一度読みたい本

持っていないけど読みたい本

  • プログラマの数学 第2版

    本書で紹介されているのはこちらですが、第二版が出ているので第二版を買おうと思います。紹介してくれている方は数学に対する劣等感があるそうで、数学ガールを読んだけど理解できなかったとのことです。わたしと全く一緒だなと思いました。わたしは大学で物理を専攻していたのですが、数学が理解できずコンプレックスをなくすために数学研究会のサークルに入ったくらいです。数学が好きになれるよう読んでみたいと思います。

  • ジェネレーティブプログラミング

    広範囲な問題解決を行う場合、パッケージ、ライブラリを作ることが良い方法なのかなと思います。そのために読んでみたいと思います。

  • C++の設計と進化

    紹介文にあるように、いろんなプログラミング言語に影響を与えた言語の成り立ちを知ることはプログラミング言語を理解する上で有益だと思います。

まとめ

長くなってしまったので、100のうちの50までまとめました。51からの後半はまた後日記載したいと思います。

マイクロサービスにおける単一責任の原則

動機

前回の動機で書いたように、マイクロサービスアーキテクチャには凝集性はマイクロサービスを考える際に重要な概念であり、SRP(単一責任の原則)の定義によって認識が強化されたと記載されていました。その概念はマイクロサービスを設計していく上で重要になりそうなので、しっかりと理解したいと思います。

凝集性とは

凝集性の定義を確認します。意味はわかるのですが言葉にするのは難しいです。ウィキペディアによると、凝集度(ぎょうしゅうど、コヒージョン、cohesion)とは、情報工学においてモジュール内のソースコードが特定の機能を提供すべく如何に協調しているかを表す度合いである。とのことです。
ウィキペディアの高い凝集度に記載の説明、凝集度は、あるコードがどれだけそのクラスの責任分担に集中しているかを示す尺度である。オブジェクト指向プログラミングでは、クラスの凝集度を高めるようにそのクラスの責任範囲を設定することが有益とされている。凝集度の高いシステムでは、コードの読みやすさと再利用の容易さが増し、複雑さが管理可能な程度に抑えられる。がわかりやすいかなと思います。この説明で重要だと思う点はクラスの凝集度を高めるようにそのクラスの責任範囲を設定することが有益という点です。これは責務駆動設計であり、単一責任の原則に従うべきであるということです。責務駆動設計についてはオブジェクトデザインが参考になると思います。この本は10年くらい前、まだオブジェクト指向がしっかり理解できていなかった頃に読んで、とても参考になりました。みなさんもある処理を追加するときに、この処理はどのオブジェクトに行わせるのがよいのかを考えると思います。それが責務駆動設計です。

単一責任の原則について

単一責任の原則について、再度確認したいと思います。

アジャイルソフトウェア開発の奥義によると、

クラスを変更する理由は1つ以上存在してはならない

と記載されています。これだけを見るとどういうことかわかりづらいですし、しかもそんなこと可能なのか?と思ってしまいます。実際には、クラスを変更する理由はただ1つであるように設計するということです。なぜそうすべきなのでしょうか。

単一責任にすべき理由

アジャイルソフトウェア開発の奥義にはいくつか単一責任にすべき理由がかかれていますが、正直あまりわかりやすいものではないと思います。
わたしは、単一責任にすべき理由はただ1つで依存関係を減らすということだと思います。

これは静的言語で特にいえることだと思うのですが、変更したクラスに直接依存しているクラスは再コンパイルが必要です。クラスが複数の責務を持ち、いろんなクラスと依存関係を持っている場合、ある一つの変更で、依存関係を持っているクラス全てを再コンパイルしないといけません。再コンパイルしたプログラムはさらにデプロイを行わなければいけません。
これは静的言語だけではありません。わたしが業務で関わっているRailsでも複数の責務を持つクラスを変更すると、そのクラスに影響する全てのクラスのspecを実行しなければなりません。その数は少ない方が良いです。

変更する理由を1つにするということは、関係のないクラスの再コンパイル、デプロイが発生しないということだと思います。プログラマが知るべき97のことで、ロバート・C・マーティンは、良いシステムデザインとは、システムのコンポーネントがそれぞれ独立してデプロイできるようになっているデザインのことですと言っています。まさにその通りだと思います。
ただ依存関係を持たずに単独で仕事をするクラスはあまりありません。ということは、結局あるクラスを変更すると、依存関係を持っているクラスも再コンパイル、デプロイが発生するのではないか?という指摘があるかもしれません。その場合は依存関係逆転の原則を利用します。わたしがSOLID原則の中で一番好きな原則です。また別の機会で詳しくみていきたいと思います。

マイクロサービスにおける単一責任の原則の応用

では、マイクロサービスの設計において、単一責任の原則はどう考慮していくのが良いでしょうか。
先ほどデプロイの話が出てきました。あるサービスを変更したときに、依存関係を持っているサービスが複数あると、それらを同時にデプロイしなければいけません。それっは不可能ではないかもしれませんが難しいことだと思います。それを防ぐために単一責任の原則を守っていくべきだと思います。

しかしそれでもプログラムと同じような問題は発生します。サービス間のインターフェースなどを変更してしまうと、依存関係を持っているサービスも変更せざるを得ません。それを防ぐためには依存関係逆転の原則をサービス間に適用します。サービスは他のサービスに依存するのではなく、サービス間のインターフェースに依存するようにします。そうすれば、各サービスの変更を行っても他のサービスは変更を行わなずにすみます。

まとめ

単一責任の原則をマイクロサービスの設計にどう活用するかをみてきました。マイクロサービスは以下の二つのことを守れば、他のマイクロサービスの変更の影響を受けずにすむでしょう。

  • サービスの凝集度を上げ、責務をはっきりさせる。
  • サービス間はサービスに依存するのではなく、サービスのインターフェースに依存するようにする。

マイクロサービスを設計するときには気をつけていきたいと思います。

プログラマが知るべき97のこと 09. 他人よりまず自分を疑う

動機

マイクロサービスアーキテクチャを読んでいて(寄り道するからなかなか進まないですが)、凝集性はマイクロサービスを考える際に重要な概念であり、SRP(単一責任の原則)の定義によって認識が強化されたと記載されていました。
引用がプログラマが知るべき97のことだったので、懐かしいと思いパラパラめくっていたら、全く別のところに目がとまりました。09. 他人よりまず自分を疑うというエッセイです。

他人よりまず自分を疑う

エッセイの内容を要約すると次のような感じです。

  • プログラマは自分が書いたプログラムが思い通りに動作しないことがあると、なかなか自分を疑うことをせず、何か他の原因だと思う
  • しかし実際はだいたい自分が原因である
  • なので、他に原因があることを証明することよりも、自分のコードのバグを見つけることに時間とエネルギーを注いだ方がずっと良い
  • 自分の書いたコードを疑い、デバッグに関して一般に「すべき」と言われていることをやる
  • 自分のコードを徹底的に調べて、それでもバグが見つからない場合に、他の調査を開始する

なぜこのエッセイが気になったか

少し前、同僚から以下のような指摘を受けました。

「あなたの変更が原因で、バグが発生していました。修正しましたので、レビューお願いします。」

そんなはずはないのに…と思ったのですが、まずは修正してもらったコードをレビューしました。修正は私の変更とは関係ないところがされていて、しかもバグは残ったままのようでした。冷静に、「この修正では、バグはなくなっていないのではないですか?この部分を修正すべきだと思います。」とコメントで伝えました。

コメントの内容は伝わったようで、バグの原因であるコードを修正してくれたのは良いのですが、まだ納得がいかないようで、「あなたが修正する前は、正しく動作していました。」と言ってきます。修正した箇所をしっかり理解していれば、そんなことを言うはずがありません。「本当ですか?」と聞いてみたのですが、「本当です!」と強気な態度を崩しません。

結果的に、修正箇所だけではなく、その周りのコードの説明をすることで理解してもらえました。しかし、なぜこのような無礼なことを言ってくるのでしょうか。相手の精神状態などいろいろ原因はあると思いますが、プログラマ、エンジニアとして足りてないことは確かです。そしてチーム内に無駄な軋轢を生んでいます。

まとめ

他人よりまず自分を疑う

常に自分が間違っているかもしれないと思いながら、自分のコード、作業に細心の注意を払うことでバグをなくすことができます。また、バグをなくす過程で発生する不要な人間関係の悪化を防ぐことができます。そしてなにより、自分の失敗からよりたくさん学ぶことができます。そういった姿勢、マインドがプログラマ、エンジニアの成長する条件だと思います。

AWSの薄い本 IAMのマニアックな話 その3 IAMグループのデザインパターン

前回まで

前回はIAMポリシーとそのデザインパターンについて学びました。
今回はIAMグループのデザインパターンについて理解したいと思います。

IAMグループのデザインパターン

IAMグループのデザインパターンは大きく2つの方法があります。

  • 個々のIAMグループには、グループの責務にあったIAMポリシーのみを付与し、IAMユーザーは複数のIAMグループに所属する方法
  • 1つのIAMグループに必要な権限を全て付与し、IAMユーザーはそのIAMグループにのみ所属する方法

それぞれのメリット、デメリットをみていきましょう

複数のグループに所属するバターン

ユーザーが複数のグループに所属することを前提とします。

メリット

ポリシーが複数のグループから利用されることがほとんどない(ポリシー:グループ = 1: 1)ので、変更の際の影響範囲がわかりやすくなります。
ポリシーから見ると、グループは1つに特定されるように設計すべきだということです。

また、必須の権限を全ユーザーが所属するグループに付与することで、抜け漏れを防ぐことができます。

デメリット

ユーザーがどのグループに所属しているのか、どのグループに所属すべきなのかの管理が煩雑になりそうが気がしています。本来ポリシーを付与すべきでないユーザーに付与してしまう事故が起こりかねないと思います。

グループ内に複数のポリシー

ユーザーが1つのグループに所属することを前提とします。

メリット

ユーザーは基本的に1つのグループにしか所属しないため、ユーザーから見るとシンプルな構造になります。また、ポリシーも複数のグループから利用されることが前提になるため、自然とシンプルで使いやすいポリシー設計になります。

デメリット

権限を細かくわけたい場合は、そのユーザーのためのグループのような設計になってしまうかもしれません。1ユーザーあたり1グループ作成しないといけなくなる可能性もあり、グループの数が増えて管理が煩雑になるかもしれません。

まとめ

IAMグループのデザインパターンとして、複数グループに所属するパターンと、グループ内に複数ポリシーを配置するパターンの2つを見てきました。
筆者はこの2つの方法に、機能的な優劣はないので、どちらを選択するかは好みの問題であると言っています。しかし、筆者はグループ内に複数ポリシーを配置するデザインパターンを利用することが多いとのことです。特に好みがなければグループ内に複数ポリシーを配置するパターンを利用するのがよいのではないでしょうか。

わたしは、この2つのデザインパターンの違いは責務(権限)をどこに凝縮するかによるのかなと思います。ユーザーが複数のグループに所属するパターンだと、グループが責務の単位となり、グループがそれぞれ疎になると思います。設計としてはこちらの方がきれいかもしれません。グループ内に複数のポリシーをもつパターンだと、ポリシーが疎になります。グループ自体はポリシーを複数持っており重複する部分もあるため、設計はそれほどきれいではないかもしれませんが、ユーザーから見た時にとてもシンプルになると思います。

一旦はグループ内に複数のポリシーを持つパターンで設計を考えてみるという指針にしようと思います。

次回はIAMのセキュリティーについて読んでいきたいと思います。

クリーンアーキテクチャ

動機

前回、ヘキサゴナルアーキテクチャについて調べました。日本語訳で、似たようなアーキテクチャであると紹介されていたクリーンアーキテクチャを知ることでより深くヘキサゴナルアーキテクチャを知ろうと思います。

書籍 Clean Architectureとブログの内容について

原文日本語訳(はもちろん一緒)と書籍でクリーンアーキテクチャに言及している章をみてみましたが、内容はすべて一緒でした。なので、ここからは書籍の22章をもとに内容を理解していきたいと思います。

クリーンアーキテクチャ

アーキテクチャの特徴

ヘキサゴナルアーキテクチャの紹介のなかで、実践テスト駆動開発で採用したものと記載がありました。この書籍の中では、17章のMainクラスを分解するで、Mainクラスからさまざまな責務を抽出した結果、「ポートとアダプタ」アーキテクチャになったという形で利用されていました。こちらの書籍についてはまた別の機会で詳しくみていきます。

いろんな類似のアーキテクチャがありますが、共通する点は「関心ごとの分離」という目的を持っている点です。外部との依存関係がなくなるため、外部の環境(UI,DBなど)は交換可能になります。

クリーンアーキテクチャ

この図はブログでも紹介されています。正直言って、六角形が円になっただけのような気がしなくもないです。層がすこし増えているかなというのと、ビジネスロジックがEnterprise Business RulesApplication Business Rulesにわけられているところが変わったかなというくらいです。

このアーキテクチャを動作させるもっとも重要なルールは、依存性のルールであると言っています。そのルールは

ソースコードの依存性は、内側(上位レベルの方針)だけにむかっていなければいけない。

ということです。外部に依存してはいけないということです。次にこのアーキテクチャを構成する各要素を書籍を引用して紹介します。

エンティティ

エンティティは最重要ビジネスルールをカプセル化したもの。

ユースケース

ユースケースはアプリケーション固有のビジネスルールが含まれている。ユースケースは、エンティティに入出力するデータの流れを調整し、ユースケースの目標を達成できるように、エンティティに最重要ビジネスルールを使用するように指示を出す。

インターフェースアダブター

インターフェースアダプターはユースケースやエンティティに便利なフォーマットから、データベースやウェブなどの外部エージェントに便利なフォーマットにデータを変換するアダプター。

この層のインターフェースに依存するように実装することで、外部エージェントを交換可能にしているのだと思います。

フレームワークとドライバ

図のもっとも外側の縁は、フレームワークやツールで構成されています。たとえば、データベースやウェブフレームワークなどです。フレームワークとドライバの層には詳細が詰まっています。ウェブも詳細、データベースも詳細。被害が抑えられるようにこれらは外側に置いておきます。

境界を越える

図の右下に、円の境界線をどのように越えるべきかの例が記載されています。コントローラーからプレゼンターへの制御の流れがあるが、ユースケースを経由しています。この際に、依存関係逆転の法則を用いてコントローラー、プレゼンター共通のインターフェースを提供します。
制御の流れは外側から内側であるが、ソースコードの依存関係は内側から外側へ発生します。

まとめ

こうした単純なルールに従うのは、それほど難しいことではなさそうです。ルールを守っていればいずれ多くの苦痛から解放してくれると言っています。

全体のまとめ

クリーンアーキテクチャも関心ごとの分離が目的のアーキテクチャです。外部を交換可能にするためには依存関係を守ること、しっかりと関心ごとを分離することが重要です。ここでもオブジェクト指向の基本原則であるSOLIDが重要になってきます。特にD(依存関係逆転の法則)は重要だと思いました。

マイクロサービスにおけるサービスはオブジェクト指向におけるオブジェクトと同義だと思います。責務を明確にし、インターフェースを正しく定義し利用しやすいマイクロサービスを設計したいものです。

ヘキサゴナルアーキテクチャ

動機

わたしが担当しているWebアプリケーションがいろんなサービスを扱っていて、変更が予期せぬところに影響を及ぼすようになってしまっています。そこで、Webアプリケーションを分割しようと思い、マイクロサービスについて調べようと思いました。
まずはじめにマイクロサービスアーキテクチャを読み始めました。すると、すぐにヘキサゴナルアーキテクチャについて記されていました。

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

レイヤ化アーキテクチャが好ましくないような記述に疑問がわいたので、しっかり理解しようと思います。

書籍マイクロサービスアーキテクチャにあったヘキサゴナルアーキテクチャについてのURLは2020年5月23日現在、改装中でした…こちらに日本語訳がありました。

PoEAAの中でのヘキサゴナルアーキテクチャ

翻訳者の方のコメントにもあるように、PoEAAに記載があるということで、早速読んでみました。

ヘキサゴナルアーキテクチャについてはかなり序盤でふれられていました。以下がその引用になります。

(中略) プレゼンテーションレイヤとデータソースレイヤには多くの類似点があるように見える。どちらも外部との接続に関するレイヤだからだ。これは、Alistair Cockburnのヘキサゴナルアーキテクチャーパターンの背後にあるロジックである。ヘキサゴナルアーキテクチャは、外部システムへのインターフェースで囲まれた核としてシステムを視覚化したものである。ヘキサゴナルアーキテクチャでは、外部にあるものは基本的にすべて外側のインターフェースであり、したがってこれは対照的なビューであって、私の言う非対称のレイヤ化スキーマではない。

さらに、以下のように続きます。

しかし、私はこの非対称性こそ有用だと思っている。他へのサービスとして提供するインターフェースと、他のサービスを使用することとの間には、歴然とした違いがあるからだ。核心に触れていえば、これこぞが私の言うプレゼンテーションとデータソースとの違いなのである。(中略)これらを分けて考えることは有用であると私は考える。

両者の考え方はわかれていてちょっと対立しているようにも捉えられます。
プレゼンテーションとデータソースは外側のインターフェースであるという共通点はあるものの、利用用途を考えると別のものと認識するのがレイヤ化、どちらも外側のインターフェースであるという共通点を持っているので同じものと考えるのがヘキサゴナルアーキテクチャということでしょうか。

ヘキサゴナルアーキテクチャ

翻訳いただいた内容をもとにまとめいきます。意図や動機、構造など書かれているので、GoFのデザインパターンの説明みたいな感じです。

ヘキサゴナルアーキテクチャは別名Ports and Adapter*Ports and Adaptersパターンといいます。
Portsは外部との接点という感じでしょうか(プレゼンテーション、データソースなど)。TCPのポート番号と同じようなイメージです。
Adaptersはその具体的な外部(HTTPなど)とのインターフェースを統一するためのアダプタです。

意図

アプリケーションを、ユーザー、プログラム、自動テストあるいはバッチスクリプトから、同じように駆動できるようにする。そして、実際のランタイムデバイスとデータベースから隔離して、開発とテストをできるようにする。

外部のインターフェースに依存しないようにアプリケーションを構築するということだととらえました。すなわち、アプリケーションの外側に対して同じインターフェースを提供し、ビジネスロジック自体はそのインターフェースの外には実装しないということだと思います。

動機

数年来、ソフトウェアアプリケーションで一番怖いことのひとつは、ビジネスロジックがユーザーインターフェイスコードに侵入することだった。これが引き起す問題は、3つある:
・はじめに、システムを自動テストスイートで綺麗にテストすることができない。なぜなら、テストを必要とするロジックの部分が、フィールドサイズやボタン配置など、頻繁に変わるビジュアルの詳細に依存するからだ。
・同じ理由により、人間駆動のシステム使用から、バッチ処理システムに移行することが不可能になる。
・これも同じ理由から、他のプログムからプログラムを駆動したくなったときに、そうすることが難しいか、または不可能になる。

ビジネスロジックがユーザーインターフェースコードに侵入するのは確かに問題ですね。ユーザーインターフェースが交換可能ではなくなってしまいます。

(多くの組織によって繰り返し)試みられた解法は、アーキテクチャに新しい層を足すことだ。そのときには、今度は、本当に絶対に、ビジネスロジックが新しいレイヤーに置かれることはないという取り決めをする。しかしながら、取り決めへの違反が起きたときに検出する仕組みはなく、組織は、数年後、新しいレイヤーがビジネスロジックでとっちらかっており、同じ問題が起きたことに気付く。

ロジック・責務を持たせるクラスに迷った時、層を追加することはありますね。RailsでいうService層やDecorator層がまさにそれかなと思いました。層を足す=間に挟み込むようなイメージで実装しています。ControllerとModelの間にロジックを詰め込みたいみたいな感じですね。これがよくないと解釈しました。

解決法の本質

利用すべき非対称性は、アプリケーションの「左側」と「右側」ではなく、アプリケーションの「内側」と「外側」だ。従うべきルールは、「内側」の部分にあるコードが「外側」の部分に漏れ出さないようにすべき、ということだ。

プレゼンテーション(フロント)、ビジネスロジック、データソースと左からリクエストを受け付けてレスポンスを返すまでの絵を思い浮かべたりしますが、そうではなく、すべて内側と外側のやりとりであると考えるということですね。プレゼンテーションとデータソースは同じ外側であるという考え方をしましょうということです。
内側であるビジネスロジックはAdapterのインターフェースに依存し、外側もAdapterのインターフェースに依存するように実装すべきです。

ポート用のプロトコルは、2つのデバイスの会話を目的として、与えられる。
このプロトコルは、アプリケーションプログラムインターフェイス(API)の形を取る。

やっとマイクロサービスの本で紹介されていた理由がわかってきました。まさに外側と内側のやりとりをサービス間で行うべきということですね。

また、なぜ六角形なのかの説明も記載されていました。

六角形は、視覚的に、
1.内側と外側の非対称性と、ポートの似たような特性(1次元のレイヤーの絵と、それが想起させるものから完全に離れるために)と、
2.定義された数の異なるポートの存在 ー 2,3,あるいは4つの(4が、わたしがこれまで遭遇した中では一番多かった)
に焦点を当てるよう意図されている。

構造

アプリケーションは各ポートの責務を実装し、ポートは具体的な外部とやり取りするためにAdapterを実装します。
ここでの例はポートがuser-side APIdata-side APIで、user-side APIの具体的な外部には、http adapterGUI adapterなどが記載されていて、data-side APIの具体的な外部はDB access servicemock in-memory databaseとなっています。余談ですがデータベースへのインターフェースを考えるときに必ずSOLID原則のD、依存関係逆転の法則を思い出します。

構造については特に真新しいものはないですね。ですが、応用ノートにおもしろい内容が記載されていました。

応用ノート

ports and adaptersパターンは、意図的に、すべてのポートが基本的に類似しているふりをしながら書かれている。このようなふりをすることは、アーキテクチャレベルで有益だ。実装においては、ポートとアダプターには2種類のものがあることがわかる。すぐに明らかになる理由から、わたしが、「プライマリ」と「セカンダリ」と呼ぶものだ。これらは、「駆動する」アダプターと「駆動される」アダプターと呼ばれることもある。

構造の例でいうと、駆動するアダプタはuser-side APIのことで、駆動されるアダプタはdata-side APIのことでしょう。結局は外部を全て同等には扱えないということでしょうか。レイヤ化アーキテクチャとの大きな違いだと思っていた外部は全て同じように扱うという考え方ではなくなっている気がします。

まとめ

ヘキサゴナルアーキテクチャはシステムをビジネスロジックがある内側と、ビジネスロジックと相互作用する外側におおきくわけるという考え方。その意図はビジネスロジックが外部に侵入しないようにするため。

元々の引用

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

ビジネスロジックが階層化によって本来の場所ではないところに侵入する(から見えなくなる)ことをいっているのだと思います。マイクロサービスではビジネスロジック自体が一つのサービスとして稼働すると思うので、外部との境界をしっかりと認識することが重要かと思います。

ヘキサゴナルアーキテクチャはレイヤ化アーキテクチャをより抽象化したような考え方だという印象を持ちました。マイクロサービスを構築する際のサービス間の責務を考える際には有用かなと思いました。その場合も駆動する側、駆動される側という考え方はどうしても必要になるかと思います。駆動する、駆動されるサービスが多数になるので、レイヤ化よりヘキサゴナルアーキテクチャの方が視覚的にわかりやすく記述できるという利点があると思います。

次はヘキサゴナルアーキテクチャに似ていると言われているクリーンアーキテクチャについて考えたいと思います。

AWSの薄い本 IAMのマニアックな話 その2

前回まで

前回はIAMについてと、IAMの基本機能5つの説明のところまですすみました。
今回はIAMポリシーの具体的な設定方法、デザインパターンについて理解したいと思います。
(書籍の中では具体的なカスタマー管理ポリシーの作成のチュートリアルに入っていくのですが、ここでは重要だと思うポイントにしぼって記します。)

IAMポリシー

IAMポリシーを構成する要素(エレメント)は大きく以下の2つです。

  • Version
  • Statement

Version

Versionは2008-10-172012-10-17があります。指定しない場合は2008-10-17になるので、必ず明示的に2012-10-17を指定しましょう。

Statement

Statementは大きくEffect, Action, Resourceの3つがあります。
EffectはAllowDenyを指定します。
ActionはAWSサービスを指定します。全てを指定するアスタリスクも利用できます。
Resourceは利用するリソース(リージョン、IAMユーザー名、S3バケットなど)を指定します。

チュートリアルで紹介されていた特定のIPアドレスを許可するポリシーはこんな感じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"8.8.8.8/32"
]
}
}
}
]
}

ここで新しくConditionというStatementが出てきています。制限を追加する場合に利用します。
この例は送信元IPが8.8.8.8/32であれば全て許可されるということです。aws:SourceIpで指定するIPアドレスはグローバルIPでなければなりません。VPC内のリソースを制限したい場合は、VPCのプライベートIPを指定するのではなく、VPC IDもしくはVPC Endpoint IDを指定します。
6章で紹介されているVPC Endpoint IDが指定されている例を記します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"Version": "2012-10-17",
"Id": "ListrictAccess",
"Statement": [
{
"Sid": "Allow-from-specific-VPC-only",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::kindle-iam-test",
"arn:aws:s3:::kindle-iam-test/*"
],
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-id1234"
}
}
}
]
}

Conditionのところに、VPC Endpointが指定されていることがわかります。

IAMの許可・拒否ポリシーの挙動

権限の指定の優先度は以下の順序になっています。

明示的なDeny > 明示的なAllow > 暗黙的なDeny(デフォルト)

設定しなければ暗黙的なDenyとなります。こう言った優先度になるので、明示的なAllowをAWS管理ポリシーで設定し、明示的なDenyをカスタマー管理ポリシーで設定するのがよさそうです。この設定方法は後にハイブリッドパターンとして紹介します。

IAMポリシーのデザインパターン

大きく3つのパターンに分けられます。

  • ホワイトリストパターン
  • ブラックリストパターン
  • ハイブリッドパターン

一つずつみていきましょう。

ホワイトリストパターン

許可する権限のみ付与していくパターン。
サービス単位で指定する場合は、AWS管理ポリシーを利用します。

メリット

必要最小限の権限のみ付与するので、セキュリティ面での信頼性が高くなります。

デメリット

事前に役割が決まっていないと権限を付与できない。
アクション単位で指定する場合、AWSサービスが拡大したときなど、都度それに対応しないといけない。

ユースケース

業務、運用、設計が確立している本番環境に適用すべきです。
AWS管理ポリシーもほぼホワイトリストパターンの実装になっています。

ブラックリストパターン

許可してはいけない権限のみを剥奪するパターン

メリット

禁止事項のみを定義すれば良いので、IAMポリシーの設計、設定が最小ですみます。

デメリット

予期せぬ機能が突然使えるようになる点。

ユースケース

  • 一般的なIAMの運用としては、ブラックリストパターンの利用が多くなる。
  • AWSの権限のデフォルトは暗黙的拒否。
    そのため、どこかで許可のステートメントを作った上でブラックリストで拒否するというタイミングになります。

ハイブリッドパターン

AWS管理ポリシーによる許可と、カスタマー管理ポリシーによる拒否の組み合わせ。

メリット

AWSの定義済ポリシーと自分で作ったブラックリストを組み合わせて利用することにより、最小の労力で実用的なポリシーを作ることもできる。個々のポリシーもシンプルにできる。

デメリット

特になし

ユースケース

1ポリシーで管理すべきか、グループで組み合わせて1ポリシー管理するか、どちらが良いのでしょうか。

1ポリシでーで全て書くことのメリット

視認性が高い
そのポリシーを付与するだけで良い

デメリット

再利用性(モジュラリティ)が低い

グループでの組み合わせで書くことのメリット

各ポリシーの再利用性が高い=管理するポリシーが少なくて済みます。
各ポリシーは独立していて、疎な関係を持ちます。

まとめ

IAMロールを付与するパターンはホワイトリストかブラックリスト
どちらかだけで良いと言うわけではなくどちらも重要なのでこれらの組み合わせで権限を制御します。
〇〇以外という反転のパターンを考えられるようになると記載できるルールの幅が広がりそうです。

次回はIAMグループのデザインパターンをみていきます。

AWSの薄い本 IAMのマニアックな話

動機

IAMのことを今までちゃんと考えたことはありませんでした(よくない)。
サービスを利用するときに、そのサービスの既存のポリシーをReadOnlyで割り当てようか、FullAccessで割り当てようかを考えたくらいでした…
でもそれではよくない!ということで、この本を読んだのを機に、IAMについてしっかりとりかいしたいと思いました。

IAMとは

AWS Identity and Management (以下、IAM)は、AWS 利用に関する認証と認可を司るサービスです。

認証と認可

認証と認可はOAuthに関わるときにもよく出てきますね。
認証は本人性のの確認(Authentication)で、
認可はリソースに対する利用権限の付与(Authorization)です。
わかりづらいですね…ログインは認証で、その対象者はなにができるのか、なにができないのかが認可です。
OAuthの場合だと、認証はそのサービスへのログインであり、認可はサードパーティのアプリケーションになにをどこまで許可するのかということです。
例えばfacebookの認可だと、フィードへの投稿を許可するなどがあります。

AWSアカウントとIAMユーザー

AWSアカウントはルートアカウントとも呼ばれるアカウントで、絶対的な権限を持ちます。
通常利用してはいけません。IAMユーザーを作成し、IAMユーザーでログイン、管理など行いましょう。

IAMの機能

IAMには以下の5つの機能があります。

  • IAMユーザー
  • IAMグループ
  • IAMポリシー
  • IAMロール
  • パーミッションバウンダリー

ひとつずつみていきます。

IAMユーザー

共有アカウントは作成せずに、必ず個々でユーザーを作成しましょう(MFA利用推奨)。
プログラム、ツールから利用の際もそれぞれに作成します。

IAMユーザーに直接権限を付与することも可能ですが、管理コストが高くなるのでやめましょう。
次に紹介するIAMグループで管理し、ユーザーの役割に応じてグループに所属させる方法が良いです。

IAMグループ

IAMグループは同一の役割を持つIAMユーザーをグループ化する機能です。IAMユーザーは複数のグループに所属することもできます。
IAMグループに権限を付与することにより、権限を容易に、かつ正確に管理することができます。
権限の付与方法は管理ポリシーとインラインポリシーの2つです。

IAMポリシー

IAMポリシーはAWSリソースへのアクセス権限をまとめたものです。
以下の3つの大きなルールに基づいて権限を設定します。

  • Action(どのサー ビスの)
  • Resource(どういう機能や範囲を)
  • Effect(許可 or 拒否)

IAMポリシーの種類

IAMポリシーには2種類あります。

  • AWSが最初から設定しているAWS管理ポリシー
  • ユーザーが作成したカスタマー管理ポリシー

ポリシーはIAMユーザー、IAMグループ、IAMロールに付与できます。

IAMポリシーの使い分け

筆者のオススメは足し算と引き算。
AWS管理ポリシーで基本的な権限を付与、カスタマー管理ポリシーで権限を制限するのがよいと言っています。

IAMロール

IAMロールはAWSサービスやアプリケーションに対してAWSの操作権限を与える仕組みです。
LambdaやECSなど、実行している個々のタスクに対してIAMユーザーを割振れないようなサービスでIAMロールを利用します。
IAMロールは使わなくてもなんとかなりますが、IAMロールを正しく使うことによって、AWSの安全性も利便性も格段に高まります。積極的に使っていくのが良さそうです。

パーミションバウンダリー

IAMの移譲権限を制限する機能です。
IAMユーザー、IAMロールに対してアクセス制限を行います。
付与した権限とパーミションバウンダリーで許可した権限の重なり合うところのみ有効な権限として動作します。
あまり利用しなさそうな機能なのですが、一旦どういうものかは理解しておきたいです。

まとめ

パーミッションバウンダリーを除いた4つのIAMについてしっかりと理解することで、9割方マスターできます。
IAMユーザーはユーザーごとに作成します、また、共有アカウントは禁止です。
IAMグループはグループ化する機能で、グループにたいしてポリシーを付与します。
IAMポリシーは権限をまとめたものです。
IAMロールはAWSの操作権限を与えます。
IAMロールをうまく使うとアクセスキーがほぼ不要になります。

次回からはIAMポリシーについて詳しく掘り下げます。またIAMポリシーのデザインパターンについても理解していこうと思います。

systemdの起動でハマった

systemdのエラー

Let’s Encryptの導入でsystemdを利用してHexoをdaemonとして起動しようとしました。
その際に解決に時間がかかるハマりどころがあったので忘れないように記載しておきます。

systemdの導入

はじめに/etc/systemd/system/hexo.serviceを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Unit]
Description=hexo
After=syslog.target network.target

[Service]
Type=simple
ExecStart=sudo /home/ec2-user/.anyenv/envs/nodenv/shims/hexo server -p 8080
WorkingDirectory=/home/ec2-user/blog
StandardOutput=syslog
StandardError=syslog
KillMode=process
Restart=always
User=ec2-user
Group=ec2-user
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

書き方はこちらを参考にしてください。

登録されたかどうかを確認します。

1
2
$ sudo systemctl list-unit-files --type=service | grep hexo
hexo.service disabled

大丈夫でした。

enableしてstartします。

1
2
3
4
5
6
$ sudo systemctl enable hexo
Created symlink from /etc/systemd/system/multi-user.target.wants/hexo.service to /etc/systemd/system/hexo.service.
$
$ sudo systemctl start hexo
Failed to start hexo.service: Unit is not loaded properly: Invalid argument.
See system logs and 'systemctl status hexo.service' for details.

起動に失敗しました。See system logs and 'systemctl status hexo.service' for details.と書いてあるので言われた通りにやってみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo systemctl status hexo.service
● hexo.service - hexo
Loaded: error (Reason: Invalid argument)
Active: failed (Result: start-limit) since 水 2019-06-26 20:40:03 JST; 10 months 10 days ago
Main PID: 13043 (code=exited, status=2)

5月 07 01:04:35 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:04:35 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:06:36 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:06:36 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:07:03 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:07:03 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:10:02 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:10:02 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
5月 07 01:10:18 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: [/etc/sy...
5月 07 01:10:18 ip-172-31-43-237.ap-northeast-1.compute.internal systemd[1]: hexo.ser...
Hint: Some lines were ellipsized, use -l to show in full.

全然わからない…

1
2
Loaded: error (Reason: Invalid argument)
Active: failed (Result: start-limit) since 水 2019-06-26 20:40:03 JST; 10 months 10 days ago

この辺がヒントといえばヒントなんだと思いますが、結果的にここに惑わされた形になりました。

全くヒントも掴めずに調べていると/var/log/messagesを見るとよいみたいなコメントを見つけました。なのでみてみると

1
May  7 01:04:35 ip-172-31-43-237 systemd: [/etc/systemd/system/hexo.service:7] Executable path is not absolute, ignoring: sudo /home/ec2-user/.anyenv/envs/nodenv/shims/hexo server -p 8080

めちゃくちゃわかりやすいメッセージが書かれています。
起動コマンドがsudoで始まっていて、それがが絶対パスではないので起動できてなかったようです。
なのでsudo/usr/bin/sudoに変更して問題なく起動しました。

まとめ

systemdのエラーは/var/log/messagesを見ること。