『一瞬で判断する力 私が宇宙飛行士として磨いた7つのスキル』を読んだ

転職先の入社前面談の際に教えてもらった本で、その場でポチってすぐ読んでみました。

宇宙飛行士である若田光一さんが書かれた本です。

若田さんは日本人初のコマンダー(船長)を務めた方で、宇宙に旅立つ前の訓練での出来事や、実際に国際宇宙ステーション(ISS)でコマンダーとして仕事をされた体験などを交えながら、一瞬で判断するために必要なことを7つのキーワード(テーマ)を用いて書かれています。

ここがおもしろい!

1. 一般の会社や組織で起きそうな問題は宇宙飛行士の方たちにも起きるということ

宇宙飛行士の仕事っていうのは全く何をするか知らなかったので、漠然とすごいことをしているんだろうな、めちゃめちゃ能力が高い人たちだから自然と上手くいきそうだよな、とどこか別の次元の人たちのように個人的に思っていました。

ただ本を読み進めると、会社や組織で起こる問題は宇宙飛行士やその関係者の間にも起きるし、僕たちと同じようにどう解決するか頭を悩ませるということです。

例えば、コマンダーとして仕事をしていると、地上管制官と人たちとISSの宇宙飛行士の間で意見が食い違うことがやはりあるそうです。こういう問題は、普段の人間関係の間でも起こり得ることなので、その場合はどういう風に解決したのかというのは自分の体験を思い出しながら読むと大変面白かったです。

2. 不確定要素への対応

宇宙での作業は危険なことが多いので、事前にマニュアル・ドキュメントをしっかり書いて読み込むのだそうです。

また、想定外にも対応できるようにできるだけ不確定要素を減らしたり、もし複合的なトラブルが発生しても解決できるように「たぶん」や「〜ではないだろうか」で判断せず、予知できるレベルにまで体制を整えるそうです。

このような仕事のやり方はしっかり見習いたいのと同時に、エンジニアがサービスをリリースするときにどこか似ているなと感じました。

アプリケーションの設定は大丈夫か?、メモリの容量は適切か?、リクエストがこれぐらい来ると予測しているが、スパイクにも耐えられるような体制にもしておくか等、不確定要素に対しての対応を考えるというのは参考になるなと読んでいて思いました。

3. 学びについて

第2章の「学ぶ」の内容がものすごく良かったので少しだけ記載します。 宇宙飛行士の方たちは、わからないこと・曖昧なことがをそのままにすると死に直結するため、ここまで徹底的にやられているのだと思います。

新しい環境に飛び込んだときは質問しづらい気持ちになったりすると思います。また、歳を取ると分からないことに対して今更質問するのが恥ずかしいとか、まぁいいやという気持ちになってくるのかもしれません。

そんな気持ちになったときは、この本の内容を思い出して積極的に発言・質問していきたいなと思いました。

  • 愚かな質問はない
    • 「理解したつもり」が危ない
  • 質問は、自らの理解を深めるためでもある
  • 自分が感じた疑問点をそのまま残しておいてはいけない
  • 何よりも「質問をする」という行為自体が、自分の頭で考え、「理解できている部分」と「そうでない部分」を明確に分別することで生まれ出るのも事実である
  • 「分からないまま」に甘んじない
  • あやふやな記憶は、トラブルのもととなる
  • 急いで仕事をススメなければならないときに忘れてはならないのは、「何のためにやっているか」を思い出すこと
  • 長い目で見ると、速く理解することよりも重要になるのは、長い時間をかけてでも、キチンと正しく理解すること
    • 本当の意味でその知識を咀嚼していなければ意味がない
    • 中途半端な身につけ方をしていれば、結局またいつか学び直さなければならなくなる
  • 失敗を隠さず、失敗に対して常に鋭敏にアンテナを張り、失敗から何かを学ぶ姿勢が重要
  • 同じ失敗を繰り返さない
    • 一回目の失敗は、ときには寛容に受け入れてもらっても、二回目に同じ失敗をすると信頼は失墜する
    • 自分が犯した失敗を真摯に受け止め、その理由をきちんと分析し、とるべき最善の対応策を検討して習得することを怠らなければ、今後、類似した状況で同じような失敗を繰り返す可能性は少なくなる

本の内容について

最初、タイトル通り「一瞬で判断する力」について書かれていたのかと思っていましたが、ざっくり以下のような感じです。

  • 仕事への向き合う姿勢
  • 学び方
  • ものごとを前に進める方法
  • チームワーク
  • 信頼関係の構築方法
  • 決断する方法
  • 恐怖への向き合い方
  • リーダーシップ

勘違いしてほしくないのが、方法論が書かれているわけではなく、若田さんの実体験とこう行動したのが良かったというのが書かれています。

なので、ここから自分ならどうするのか、自分なりに咀嚼する必要がある本だと感じています。

どのような人におすすめか?

新しい環境に飛び込む方、マネジメントをされている方、人間関係で悩まれている方などでしょうか。

最後に

久しぶりにおもしろくて一気読みしてしまいました。

このブログでおもしろさを伝えきれないと思うので、ぜひ手にとって読んでみてください!

AWS Certified Cloud Practitionerに合格した

2021年9月26日(日)にAWS Certified Cloud Practitioner(CLF)に合格しました!

2021年9月24日時点でCLFを残し、その他は合格していたので思い切ってほぼ勉強期間を設けずに試験に臨みました。

といってもさすがに不安だったので、前日にAWSが提供するCLFの対策デジタルトレーニングやサンプル問題を解いて、当日は本屋さんでCLFの対策本を立ち読みしました。

問題自体が普段受けていたAssociateやProfessional、Specialtyに比べて具体性がなくてとっつきにくい印象を持ちましたがなんとか合格することができました!

www.credly.com

2021年の個人目標として「AWS11冠」を掲げて頑張ってきたので、とにかく年内に定めた目標を達成できてよかったなと思います。

11冠を取得して振り返りたいこともあるので、これは別のブログ内容として書こうかなと思います。

以上!

AWS Certified Advanced Networking - Specialtyに合格した

本日、2021年9月24日(金)にAWS Certified Advanced Networking - Specialty(ANS)に合格しました🎉🎉

スコアとセクションごとのパフォーマンス

今回受けたANSのスコアは 752 で合格ラインギリギリでした!

f:id:ryskit:20210924234413p:plain

そして、セクションごとのパフォーマンスは画像のとおりです。

さすがにギリギリ合格なので、改善が必要な部分が多いです。

f:id:ryskit:20210924234749p:plain

実際に試験を受けてみた感想

ANS関連のサービスのドキュメントやDirect Connectのブログ記事など読み漁り模擬試験も3周ほどしてほぼ満点まで取れるようにしたのですが、ちゃんと理解できていなかったようで本番試験の問題は上手く解けませんでした。

やはり、Direct ConnectやVIF、BGP、Site-to-Site VPNなど学んだことをうまく整理できてなかった感が否めません。

もともとインフラエンジニアではないので出てくる用語やサービスについては具体的なイメージを想像しづらく、ドキュメントに書いていることを暗記するだけになってたのが良くなかった気がします。

今後どうするか?

正直、Direct Connect等は構築することはほぼないと思うので興味が出ないのですが、それ以外のネットワークのサービスだったり知識に関しては勉強したいなと思うので引き続き継続して書籍やドキュメントを読んで理解を深めたいと思います。

最後に

AWS ANSでやっと10冠取得できました。

あとは、一番簡単なクラウドプラクティショナーを取得できれば今あるAWS資格をコンプリートできるので引き続き頑張ろうと思います!

手動でダウンロードしたsbtをsbtenvで管理する

もともとはhomebrewでsbtをインストールして使っていましたが、sbtの複数のバージョンを使って色々検証したくなりsbtenvを使ってみることにしました。

sbtenvでsbtをインストールしようとすると僕の環境ではgpg周りでsignatureの検証が失敗してしまい、すぐに解決できそうになかったので、手動でsbtをダウンロードしてsbtenvで管理する方法を取りました。

手順

前提として、xxxenv系のツールはanyenvで管理しているため、直接sbtenvをインストールして使う場合と少しパス等が違う可能性があるのでご注意ください。

1. anyenvでsbtenvをインストールする

$ anyenv install sbtenv

以下のコマンドを実行して、sbtenvのバージョンが返ってこればOK!

$  sbtenv -v

sbtenv 0.0.24

2. sbtの公式ページからsbtをダウンロードする

公式ページから sbt 1.5.5.tgz をダウンロードします。

www.scala-sbt.org

f:id:ryskit:20210923165209p:plain

3. sbtenvのversionsにディレクトリを作成する

~/.anyenv/envs/sbtenv/versions 配下にsbtのバージョン番号と同じディレクトリを作成します。

$ mkdir -p  ~/.anyenv/envs/sbtenv/versions/1.5.5

4. ダウンロードしたsbtをファイルを解凍する

tar xf ~/Downloads/sbt-1.5.5.tgz -C ~/.anyenv/envs/sbtenv/versions/1.5.5/

5. sbtenvで管理されているか確認する

以下のように、sbtenv versions を実行して、1.5.5の横に*が付いていたらOKです。

$ sbtenv versions

  1.2.8
  1.3.9
* 1.5.5 (set by /Users/[username]/.anyenv/envs/sbtenv/version)

付いていなければ、以下を実行してください。

$ sbtenv global 1.5.5

6. sbtの情報を表示してみる

welcome to sbt 1.5.5 と表示されていればOKです。

$ cd ~ && sbt about

warning: ignoring extraneous `sbt-` prefix in version `sbt-1.5.5`
         (set by /Users/[username]/project/build.properties)
[info] welcome to sbt 1.5.5 (Amazon.com Inc. Java 11.0.3)
[info] loading global plugins from /Users/[username]/.sbt/1.0/plugins
[info] loading project definition from /Users/[username]/project
[info] set current project to ryskit (in build file:/Users/[username]/)
[info] This is sbt 1.5.5
[info] The current project is ProjectRef(uri("file:/Users/[username]/"), "username") 0.1.0-SNAPSHOT
[info] The current project is built against Scala 2.12.14
[info] Available Plugins
[info]  - sbt.ScriptedPlugin
[info]  - sbt.plugins.CorePlugin
[info]  - sbt.plugins.Giter8TemplatePlugin
[info]  - sbt.plugins.IvyPlugin
[info]  - sbt.plugins.JUnitXmlReportPlugin
[info]  - sbt.plugins.JvmPlugin
[info]  - sbt.plugins.MiniDependencyTreePlugin
[info]  - sbt.plugins.SbtPlugin
[info]  - sbt.plugins.SemanticdbPlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.12.14

参照

github.com

www.scala-sbt.org

Circeでエンコード時にnullではなくフィールドごと削除する方法

Circeのエンコードでちょっとハマって時間を溶かしたので備忘録として書いておきます。

やりたいこと

あるクラスにOption型のフィールドが含まれていて、そのフィールドが存在しない(Noneである)場合はエンコード時にそのフィールドをnullではなくフィールドごと削除したい。

可能であれば余計な記述は少なくしたい。

{
  "id" : 1,
  "name" : "ryskit"
  "age": null ← 値がない場合はこのフィールドを削除したい
}

解決策

その1

以下のように オブジェクト Response 内で io.circe.Encode トレイトを実装する。

これでも実現できますが、わざわざ書くのが面倒です。

package app

import io.circe.{Encoder, Json}
import io.circe.generic.semiauto.deriveEncoder
import io.circe.syntax._

case class Response(id: Int, name: String, age: Option[Int])

object Response {
  implicit val encoder: Encoder[Response] = new Encoder[Response] {
    private val generated = deriveEncoder[Response]
    override def apply(a: Response): Json =
      generated(a).mapObject(_.filter {
        case (_, v) =>
          !v.isNull
      })
  }
}

object Main extends App {
  val response = Response(1, "ryskit", None)
  val responseJson = response.asJson.spaces2
  println(responseJson)
}

その2 (最終的な解決策)

その1と同じように、オブジェクト Response 内で encoderを定義します。

Encoderを実装せずにio.circe.generic.semiauto.deriveEncoderを使用し、dropNullValuesでフィールドを削除します。

これで記述量も少なくなります。

package app

import io.circe.Encoder
import io.circe.generic.semiauto.deriveEncoder
import io.circe.syntax._

case class Response(id: Int, name: String, age: Option[Int])

object Response {
  implicit val encoder: Encoder[Response] = deriveEncoder[Response].mapJson(_.dropNullValues)
}

object Main extends App {
  val response = Response(1, "ryskit", None)
  val responseJson = response.asJson.spaces2
  println(responseJson)
}

github.com

『インターフェイス指向設計 アジャイル手法によるオブジェクト指向設計の実践』を読んだ

どんな本なのか

インターフェイスを用いてどのようにアプリケーションを設計するか詳しく解説された本です。

インターフェイスとは何かから始まり、原則や契約、インターフェイスの評価基準、継承とインターフェイスとの対比について、ピザ屋さんを例にして説明しています。

2008年に出版された本なので古い情報について書かれている部分はありますが、現代のアプリケーション設計でも活かせる内容が書かれていると思います。

以下、目次になります。

  • 1章 インターフェイスとは何か
  • 2章 インターフェイスと契約
  • 3章 インターフェイスと材料
  • 4章 何をインターフェイスに持たせるべきか?
  • 5章 継承とインターフェイス
  • 6章 リモートインターフェイス
  • 7章 開発プロセスの開始
  • 8章 リンクチェッカー
  • 9章 Web自動集約ツール
  • 10章 サービレポジトリ
  • 11章 パターン

目的

ソフトウェア設計について学ぶことで、テストしやすく・変更しやすい、実装の意図が把握しやすい等、継続的な開発を容易に行える設計を今よりもできるようになりたいからです。

知識や経験がないと開発の際に考えられる幅が小さくなりがちなので、そこは継続的に改善していきたいところです。

感想

具象クラスではなくインターフェイスに依存させて実装してテストの際は差し替えられるようにしたりと設計・実装してきましたが、インターフェイスの原則だったり契約や評価基準というものは知らなかったので、なるほどと思いながら読んでいました。

無意識にしていたことがこの本を読んで言語化されたこともあるので、この本を読んで良かったなと思います。

読書ノート

  • ここでの契約は、インターフェイスのユーザーと実装の間に成立する約束事を指す
  • 3つの原則
    • 原則1: インターフェイス実装は、そのメソッド名が示す通りの処理をしなければならない
      • 実装はインターフェイスの作成社が意図した通りの処理を実行できなくてはいけない
      • 実装は、戻り値を適切に処理できなくてはいけない
      • 原則1は、「サブタイプの古い米はその継承元と異なってはならない」というリスコフの置換原則(Liskov Substitution Principle: LSP)に対応している
    • 原則2: インターフェイス実装は他に危害を加えてはならない
      • ここでいう危害とは、実装がプログラム内の他モジュールや、別のプログラムの正常な動作を妨害してしまうような場合のことを指す
      • 実装は、リソースをやたらに消費してしまうようなものであってはいけない
    • 原則3: インターフェイス実装は、責務を果たせない場合にそれを呼び出し元に伝えねばならない
      • 実装は、問題に遭遇し、それを自ら修正できない場合は、その問題についての呼び出し側に報告をしなければならない
        • 報告の方法(エラーシグナル)は、リターンコードでも、例外でも構わない
      • インターフェイスが報告するエラーも、インターフェイス契約の一部
  • インターフェイスを効果的に使うためには、呼び出し側と実装側がそれぞれ契約を理解していなければならない
    • 実装が呼び出し側のどのような要求に応えるべきであるか、ということについて双方の同意が必要
  • 契約の3つの側面
    • 事前条件(precondition)
      • インターフェイスのユーザーは、メソッド呼び出し時に特定の条件が満たされていることを確認しなければならない
    • 事後条件(postcondition)
      • インターフェイス内の各メソッドは、呼び出しが適切に実行された場合に真となる条件を持つ。この保証のこと。
    • クラス不変表明(class invariant)
      • すべてのオブジェクトインスタンスが満たすべき条件を示す
      • インターフェイスにおいては、クラス不変表明は通常、特定の実装のプロパティでありメソッドではない

例)

メソッド 事前条件 事後条件
set_size() なし サイズを設定
set_toppings() サイズが設定されている トッピングを設定
set_address サイズとトッピングが設定されている 住所を設定
get_time_till_delivered サイズ、トッピング、住所が設定されている なし
  • インターフェイスのプロトコルを知ることが大切
    • プロトコルとは、実行可能なメソッドコールの組み合わせ、つまりメソッドシーケンスのまとまりのこと
    • プロトコルには、インターフェイスが作成したコールバック、生成されたイベント、呼び出されたオブザーバも示される
  • インターフェイスの機能を分離させることによって、1つのインターフェイスが持つ状態遷移の数を減らすことができ、エラーの発生率を低く抑えることができる
  • インターフェイスのテストとは、対象のインターフェイ実装が契約を満たしていることを確認するために行われるべきものだと言える
  • Christine MinginsとJean-Marc Jezequelは、契約には複数のレベルがあることを提唱している
    • 型を持つプログラミング言語における、基本となる型の契約
    • 事前条件と事後条件を含む意味的な契約
    • リアルタイムシステムにおける、パフォーマンスの契約
    • 定量化の難しい、サービスの質についての契約
    • ※テストは、こうした異なるレベルの契約それぞれに対して行う必要がある
  • データインターフェイス
    • 本書では、たくさんの属性をもつクラスに対応するメソッドで構成されるインターフェイスのこと
    • データインターフェイスのメソッドは、属性に値を設定したり、属性から値を取得したりするためのメソッド
    • 状態を持つ
      • 状態には、クラスの全属性の値が含まれる
  • サービスインターフェイス
    • 本書では、渡されたパラメータに対する処理を行うメソッドを中心に構成されているモジュールのこと
    • 渡されたパラメータを処理の対象とし、実装の属性は対象にはならない
  • Ivar Jacobsonは、オブジェクトのステレオタイプを3つ定義
    • エンティティオブジェクト
      • オブジェクトの永続的な状態を示す
    • バウンダリオブジェクト
      • システムやアクター(ユーザーおよび外部システム)とのやりとりを司る
    • コントロールオブジェクト
      • 特定の仕様に対する振る舞いを表し、バウンダリオブジェクトとエンティティオブジェクトとの間をやりとりして処理を実行する
  • インターフェイス実装は、ステートフル/ステートレスにできる
    • ステートフルインターフェイス
      • メソッドは現在の状態によって異なった動作をする
      • 状態は、メソッド呼び出しの順序によって変化する
      • 長所
        • パラメータリストが短くて済む
      • 短所
        • メソッドコールの順序が重要になる
    • ステートレスインターフェイス
      • 振る舞いがメソッド呼び出しの順序によって変わることはない
      • 長所
        • メソッドコールの順序にこだわらなくてもよい
      • 短所
        • パラメータ数が多くなる
  • インターフェイスの書くメソッドは互いに高い凝集度を持たねばならない
    • 各メソッドが提供する機能は共通するコンセプトに基づかねばならないということ
  • いくつかの処理をまとめて行うようであれば、それらは同じインターフェイスで扱うべき
  • 結合度(coupling)は、あるモジュールが他のモジュールにどれだけ依存しているうかを示す
  • 実装ではなくインターフェイスに依存しているのであれば、あるメソッドが別の実装に強く結合することは稀になる
  • 疎結合とは、呼び出される側のインターフェイスの実装を変更した際に、呼び出し側のコードを変更する必要がないということ
    • 密結合になっていると、コードを変更しなければならない
  • インターフェイスの評価基準
    • 最小
      • Pros: メソッド数が少ないので、実装とテストが簡単
      • Cons: 特定の機能を実現するためにコードを書く必要があり、コードの重複を招くこともある
    • 完全
      • Pros: すべてのメソッドを利用できる
      • Cons: メソッド数が多いため、インターフェイスの理解が難しくなる
    • 単純
      • Pros: 共通する機能を簡単に使える
      • Cons: 変化が必要なときに、新しいメソッドのコーディングが必要になる
    • 複雑
      • Pros: 「好みの方法」を柔軟に選択できる
      • Cons: インターフェイスを理解することが難しい
  • インターフェイスは完全性が高まれば高まるほど、メソッドの数は増え、実装は難しくなる
  • 凝集度の高いインターフェイスを設計することが大切
    • ただし、何をもって凝集度が高いと判断するのか
  • 疎結合を目指す
  • ポリモーフィズムとは、あるメソッドの実装を複数のクラスが提供することで実現されるものを指す
    • 実現方法は2つ
      • 継承
      • インターフェイスを用いる方法
  • 複数インターフェイスの難しい点は、各実装のメソッドに共通化できるコードがでてしまうこと
    • 避ける方法は2つ
      • 方法1
        • ヘルパークラスによる処理の委譲
      • 方法2
        • インターフェイスを実装したクラスを作成
          • このクラスはメソッドの多くの実装を提供
        • インターフェイスを実装する代わりに、この作成クラスを継承する
  • インターフェイス
    • 長所
      • クラス階層を構成する経験が不十分な場合にそれを避けることができる
      • 軽装を横断できる
      • 使い方の共通性によってまとめられる
      • 改装を横断するロールを表しやすい
      • どのメソッドを実装すべきかが明白になる
      • 別の軽装改装にあるクラスがインターフェイスのサービスを提供できる
    • 短所
      • 共通機能を提供するために、ヘルパークラスがないとコードが重複する
      • ヘルパークラスを多く作成しなければならない
  • 継承
    • 長所
      • 共通の処理の委譲が少なくて済む
      • 共通の属性を取得できる
      • 実装する処理の共通性によってまとめられる
      • 基底クラスを通じて共通の実装を提供できる
      • 継承と実装が簡単
    • 短所
      • 状況の変化に柔軟に対応できない場合がある
      • ロールの変更が難しい場合はがる
  • インターフェイスは、振る舞いの共通点を表す
  • 継承は、振る舞いの共通点に加えて、実装の共通点を表す
  • ソフトウェアプロジェクトには、ビジョンが必要
  • ビジョンとはソフトウェアの使用目的を1文か2文で簡潔に言い表したもの
  • ビジョンを明確にしたら、次はソフトウェアの要件を定義する
  • 要件を表す形式には、正式の要求仕様書や、ユーザーストーリー(誰々は何々ができる)、ユースケースなど様々なものがある
  • ユースケースには、システムに対して要求を行う人と、システムから利益を受けるエンドユーザーを記述する
  • ユースケースの定義
    • ビジネスゴールを達成するために、アクターとシステムとの相互作用を定義したもの
    • アクターとは、システムの外部にいて、システムとやり取りする主体のこと
    • ユーザーを表現するクラスやユーザーが担うロール、他システムなどがアクターとなりうる存在
  • アクターの特定は、ユーザーが行う具体的な作業やユーザーの組織内での役職だどではなく、システムにおいてユーザーが担うロールに基づいて行う

2021年8月10日 ~ 16日 振り返り

振り返る。

仕事

とある機能のリリース対応

すでに開発完了されていたとある機能の暫定対応版のリリースを行いました。

プロジェクトでは複数の機能が同時並行で開発されており、開発完了したものがお客様都合でリリーススケジュールをずらしたりすることが多々あります。

今回そのうちの一つで、この暫定対応をリリースしないとAPIのクライアントであるモバイルアプリのリリースにも影響があるリリースでした。

ただ、リリース直後エラーが発生し、一旦切り戻すことになりました。

原因としては、暫定対応時に設定していた値が固定値になっており、それが原因でとある計算ロジックで落ちるというものでした。

テストパターンが少なくCIでもテストでエラーにならないために気づけず、本番環境にリリースしていくつかのパターンのリクエストが来て判明しました。

リリース直後にエラーレートが徐々に上昇したため、ログを調査するとそのような原因だったためすぐに前のアプリケーションバージョンに切り戻すことになりました。

サーバサイドチームは何人か夏休みを取得しており人が少なかったため、積極的に調査・バグの修正、再リリースの調整等を行い、無事スプリント最後の日にリリースを完了できました。

検証環境もありCI/CD環境もあるにも関わらず、このバグを見逃したのはテストデータの網羅性が足りなかったのと適切なクラスにテストケースを追加できていなかったからです。

また、クラス設計等に問題がある可能性もあります。とある修正をしたときに正しく計算ロジックがテストで実行されていればバグに気づけた可能性があります。

今後、システムの安定稼働、開発・運用の容易性を高めるためにリファクタリングは行っていきたいと思います。

Lambdaにリソースタグを付与する

プロジェクトでは開発したリソースにタグを付与して、CloudWatchやDatadogで監視しやすいようにしています。

Serverless Frameworkでリソース作成、デプロイをしているLambdaにはこのリソースタグが付与されていなかったため付与する対応を行いました。

以下のようにStackTagsを設定すればLambdaに付与されます。

stackTags:
  key: value
iam:
  # Overwrite the default IAM role which is used for all functions
  role: arn:aws:iam::XXXXXX:role/role

www.serverless.com

プライベート

読書

  • ドメイン駆動設計入門 - ボトムアップでわかる!ドメイン駆動設計の基本

blog.ryskit.com

その他

UdemyでAkka Persistenceの動画を見終わりました。

内容も分かりやすく面白いのでおすすめです!

www.udemy.com

『ドメイン駆動設計入門 - ボトムアップでわかる!ドメイン駆動設計の基本』を読んだ

どんな本か

ドメイン駆動設計についてかなり噛み砕いて説明された本です。

難しく抽象的な説明はあまりなく、具体的なパターンを説明しながらドメイン駆動設計とはどういうものか語られています。

一つの章で一つのパターンが説明されているので読み進めやすく、サンプルコードも豊富に書かれているので具体的なサンプルからなにかヒントを掴みたい人におすすめです。

目次は以下の通り。

  • 1章 ドメイン駆動設計とは
  • 2章 システム固有の値を表現する「値オブジェクト」
  • 3章 ライフサイクルのあるオブジェクト「エンティティ」
  • 4章 不自然さを解決する「ドメインサービス」
  • 5章 データにまつわる処理を分離する「リポジトリ」
  • 6章 ユースケースを実現する「アプリケーションサービス」
  • 7章 柔軟性をもたらす依存関係のコントロール
  • 8章 ソフトウェア・システムを組み立てる
  • 9章 複雑な生成処理を行う「ファクトリ」
  • 10章 データの整合性を保つ
  • 11章 アプリケーションを1から組み立てる
  • 12章 ドメインのルールを守る「集約」
  • 13章 複雑な条件を表現する「仕様」
  • 14章 アーキテクチャ
  • 15章 ドメイン駆動設計のとびらを開こう
  • 付録 ソリューション構成

目的

システムやアプリケーションの設計力をつけて、より継続的に開発しやすく変更にも強いシステムを開発できるようになりたいと思い読み始めました。

ドメイン駆動設計にこだわらないですが、よりシステム設計に関する文書をたくさん読み込むことで、自分が持つパターンを増やして表現しやすくしたいという思いもあります。

感想

ドメイン駆動設計がドメインの知識に焦点をあてて設計する手法で、そのためにドメインやユースケースをどのようにコードで表現するのかが具体的で分かりやすかったです。

一方で、どのようにパッケージを分けるのか、どういうアーキテクチャを採用するとすると良いかに関してはページがあまり割かれておらず、他の本で補完する必要があるなと思いました。

また、エリック・エヴァンスのドメイン駆動設計と実践ドメイン駆動設計も読んで、自分の中で腹落ちするまで時間かける必要がありそうです。

読書ノート

  • ドメイン駆動設計
    • ドメインの知識に焦点を当てた設計手法
  • ドメイン
    • ソフトウェア開発におけるドメインは、「プログラムを適用する対象となる領域」を指す
  • モデル
    • 現実の事象あるいは概念を抽象化した概念
  • ドメインモデル
    • ドメインの概念をモデリングして得られたモデル
  • 値オブジェクト
    • 不変である
    • 交換可能である
    • 等価性によって比較される
    • 独自のふるまいを定義できる
  • エンティティ
    • 可変である
    • 同じ属性であっても区別される
    • 同一性によって区別される
    • ライフサイクルが存在し、そこに連続性が存在するかが判断基準
  • ドメインサービス
    • 値オブジェクトやエンティティに記述すると不自然になるふるまいが存在するが、それを解決するためのオブジェクト
    • 記述するのは「不自然なふるまい」に限定すること
  • ドメイン貧血症
    • ドメインオブジェクトに本来記述されるべき知識や振る舞いがドメインサービスやアプリケーションサービスに記述され、語るべきことを何も語っていないドメインオブジェクトの状態のこと
  • リポジトリ
    • 責務はドメインオブジェクトの永続化や再構築を行うこと
    • 重要なのはインスタンスを何らかの手段によって保存するということ
  • アプリケーションサービス
    • ユースケースを実現するオブジェクト
    • ドメインオブジェクトのふるまいを呼び出す役目を持つ
    • ドメインオブジェクトのタスク調整に徹するべき
    • ドメインのルールは記述されるべきではない
  • 凝集度
    • モジュールの責任範囲がどれだけ集中しているかを測る尺度
    • 凝集度を高めると、モジュールがひとつの事柄に集中することになり、堅牢性・信頼性・再利用性・可読性の観点から好ましい
    • 凝集度を高めるにはクラス分割が簡単な対処法
  • サービス
    • クライアントのために何かを行うもの
    • サービスはものごとではなく、活動や行動であることが多い
    • サービスは自身のふるまいを変化させる目的で状態を保持しない
    • 状態を一切もっていないことを意味しない
      • 自身のふるまいを変化させる目的の状態ではない
  • 依存関係逆転の原則(Dependency Inversion Principle)
    • A: 上位レベルのモジュールは下位レベルのモジュールに依存してはならない、どちらもモジュールも抽象に依存すべきである
    • B: 抽象は、実装の詳細に依存してはならない。実装の称しあは抽象に依存すべきである。
    • 依存の方向を制御し、すべてのモジュールが抽象へ依存するように制御する
  • ファクトリ
    • 求められることは複雑なオブジェクトの生成処理をオブジェクトとして定義すること
    • オブジェクトの生成に関わる地s樹がまとめられたオブジェクト
  • ユニットオブワーク
    • あるオブジェクトの変更を記録するオブジェクト
    • オブジェクトの読み取り動作を行う際にインスタンスの状態を記録する。読み取られたオブジェクトの変更や削除はユニットオブワークにつ打ちしない限りデータストアへ反映されることがない
    • コミット処理が呼び出されると、そこまでの変更処理をデータストアに対して適用する
    • このパターンを適用すると、永続化の対象となるオブジェクトの作成・変更・削除といった動作はすべてユニットオブワークを通じて行うようになる
  • 集約
    • 関連するオブジェクト同士を線で囲う境界として定義される
    • 集約の外部から境界の内部のオブジェクトを操作してはならない
    • 集約を操作するための直接のインターフェースとなるオブジェクトは集約ルート(AR: Aggregate Root)とよばれるオブジェクトに限定される
    • 外部から内部のオブジェクトに対して直接操作するのではなく、そのオブジェクトを保持するオブジェクトに依頼する形を取る
    • 「変更の単位」で集約を区切る
  • 仕様
    • 仕様はあるお部会j区とがある評価基準に達しているかを判定するオブジェクト
    • 値オブジェクトやエンティティにリポジトリを操作させないために取られる手段は仕様と呼ばれるオブジェクトを利用した解決
    • 仕様はれっきとしたドメインオブジェクト

2021年8月2日 ~ 9日 振り返り

久しぶりの振り返り。 毎週やっていたけど、やらなくなると途端に面倒になるので継続するには習慣化が大切だなと思いました。

仕事

外部APIから情報取得していた処理を保存しているキャッシュから読むように修正

PoCを行うため、とある外部サーバーに登録してある情報をリクエストして返すような簡単なAPIが既に実装されていました。 ただ問題があって、この外部サーバーの秒間リクエスト数の制限がかなり厳しいので、それらの情報はキャッシュして使う必要がありました。

外部サーバーに登録済みの情報をRedisにキャッシュとして保存するLambdaは先々週のスプリントで実装したので、先週のスプリントでは既存のコードを書き換えてキャッシュ(Redis)からデータを読むように処理を修正するというタスクを行いました。

キャッシュを読む処理自体はもともとすぐに既存のコードに置き換えやすいように実装していたのでサクッとタスクを完了にはできました。 また、今のプロジェクトはマルチプロジェクト構成になっており、依存関係が複雑になりつつあったのでそこの整理もできたのでなかなか楽しかったです。

Datadogエージェントのアップデート

現在開発しているアプリケーションはEC2上で動いているのですが、ミドルウェア等のアップデートの際はゴールデンAMIを作成して検証環境にデプロイし、アプリケーションの動作に問題ないか確認する必要があります。

Datadogのエージェントは結構早くバージョンが上がるので2,3ヶ月に一回バージョンを上げては動作確認しています。

動作確認等は地味に時間食うのでここらへんは自動化したいところです。

他の会社さんとかは、ミドルウェア等をアップデートした際にアプリケーションに影響ないかの確認はどのようにしているんだろうか。。。

参考にできそうなものがあればどんどん取り入れてプロジェクトを良くしていきたい。

プライベート

やったこと

AWS MLSの試験を受けた

本当は7月30日に受ける予定だったんですが、試験勉強が全く足りないなという判断で8月6日に受けてきました。

合格はできたんですが、継続的な勉強は必要そうです。

blog.ryskit.com

AtCoder Boot camp for Beginners

最近、毎日1問ずつ解くようにしています。

アルゴリズムを今までちゃんと勉強してこなかったので、もっと学び必要があるなと感じてやっています。

少し前までC++で書いていたんですが、Scalaで書きたいなと思い最近はずっとScalaで書いています。

https://kenkoooo.com/atcoder/#/training/Boot%20camp%20for%20Beginners

「Akka Essentials with Scala | Rock the JVM」 コースを修了した

仕事でPlayframeworkやScalaを使用して仕事をしていますが、Akkaをちゃんと学んだことがなかったのでもっと知りたいなと思って始めました。

解説されているAkkaのバージョンが2.5と最新ではないのですが、実際にコードを書きながらAkkaについて学べるのは大変おもしろかったです。

www.udemy.com

次は、「Akka Persistence with Scala」というコースをやってみようと思います。

www.udemy.com

AWS Certified Machine Learning - Specialtyに合格した

本日、2021年8月6日(金) に AWS Certified Machine Learning - Specialty(MLS) に合格しました🎉🎉

スコアとセクションごとのパフォーマンス

今回受けたMLSのスコアは 835 で何とか8割を超えることができました!

f:id:ryskit:20210806213414p:plain

そして、セクションごとのパフォーマンスは画像のとおりです。

f:id:ryskit:20210806213423p:plain

実際に試験を受けてみた感想

今回MLSに何とか合格することができましたが、正直これを合格できただけでAWSの機械学習関連のサービスを使いこなしてプロダクション環境に構築できるかと言われればノーです。

試験勉強中も正直意味がよく分からんなと思いつつやっていましたし、試験問題解いてるときもやっぱり分からんなと思ってたので、合格できるなんて思ってもなかったです。

機械学習で使われるアルゴリズムはいろいろあって、どういうことを期待するのか、データの特徴によっても最適なアルゴリズムも違うので、試験のためにこれらを理解するのもなかなか大変でした。

あと、そもそもモデルの学習などを一度も試さなかったし、実際にコードを書いてアプリケーションを作ったわけでもないので理解できているとは到底言える状態ではないなというのが本音です。

MLS合格したけどどうするよ?

業務で機械学習を使うわけでもなければ、MLエンジニアでもないのでがっつりのめり込んでやろうとは思ってないのですが、やったことのない分野は勉強したりするのは新鮮で面白みがあります。

せっかくMLSも合格したので、勉強も継続して続けて知識を広げたいなと思っています。

あと、合格してすぐ近くの紀伊国屋に行って、こんな本を買ってみました。

この本を読んで実際にアプリケーションを構築したり、簡単なレコメンドサービスなども作って試してみたいなとも思っています。

最後に

ひとまずAWS 9冠になりました。

残るは、Advanced Networking - Specialtyと Cloud Practitioner だけです。

9月茉までには11 冠まで行けるように頑張ろうと思います!