kbigwheelのプログラミング・ソフトウェア技術系ブログ

プログラミング・ソフトウェア技術系のことを書きます

swagger-playやswagger-akka-httpのようなフレームワーク連携swaggerドキュメント生成ライブラリは概ね役に立たない

swagger-playやswagger-akka-httpのような、フレームワークと連携してswagger ドキュメントを自動生成してくれるようなライブラリがある。 このようなライブラリは直接API仕様をyaml/jsonで書く必要がなくなり、swagger仕様も読み解く必要がないため一見便利に見えるが使ってみたところ以下の欠点があり現時点ではプロダクトで使うには足りなかった。

1. フレームワークとの統合に限界があり、それほど自動生成してくれない

ライブラリがフレームワークから自動生成してくれる情報はせいぜいAPIパスとメソッド(GET/POST/...)などで、ヘッダ情報やレスポンスのステータスコードのパターンなどは結局自分で書く必要がある。

2. アノテーション情報が非常にコード品質を落とす

上で述べた通りほとんどの情報は自動生成されないのでメソッド/クラスへのアノテーションとして各種情報を書く必要があるが、swaggerドキュメントの品質をあげようとするとこのアノテーションは1APIにつき簡単に10行以上にもなりコードの可読性を著しく下げる。 そのためswaggerドキュメントの品質を上げようとするとコードの品質が下がり、コードの品質を上げようとするとswaggerドキュメントの品質が下がるというジレンマが発生する。

3. ライブラリのコード品質が低い

上のような欠点により多くの人が早めに見限るので、ライブラリの品質が基本的に低い。 swagger-akka-httpswagger-playを試したがどちらも有名ライブラリと連携している割にはstarが少なく、またコードの品質が低かった。 具体的には以下を指す。

  1. アノテーションで表現できないswagger仕様がある
  2. swagger仕様のバージョンアップに追従していない
  3. case classとswagger modelを紐付けるなど比較的簡単に思いつきそうな機能がない

結論

swaggerドキュメントとコードは切り離して管理したほうが良い。 その方がコード/ドキュメントそれぞれの品質が上げやすくなる。 コードとドキュメントの歩調を合わせる手間の問題についてだが、個人的にはAPIサーバのrootにアクセスしたときswagger UIでそのAPIサーバのswaggerドキュメントが動くAPI仕様として使えるようにすればかなり楽になると思う。 例えば https://api.petshop.io/api/v1/xxxx のようなAPI集合がある場合、https://api.petshop.io/ へアクセスしたときswagger UIで https://api.petshop.io/api/v1/xxxx 系のAPIの仕様すべてを表示する。 これには以下の利点がある(番号が若いほど重要)。

  1. API利用者がswaggerドキュメントの場所を探す必要がなくなる
  2. 動くAPI仕様書は使いやすく、その結果API使用者・記述者両方がよく利用するようになる。その結果仕様の間違いや足りない記述などが発見されやすくなり、ドキュメントを修正しやすくなる。最終的にAPI仕様書の質が上がるようになる
  3. APIの追加/機能変更とドキュメントの更新を同じパッケージ(jar)で賄うことができ、それによりswaggerドキュメント変更とコード変更の歩調が簡単に合わせられる
  4. Swagger UIと対象APIが同じホスト名ならCORSを考慮する必要がない

動くAPI仕様書と実際のAPIを同じドメインにまとめることの利点はWeb API Design(その4) - winplusの日記の「ひとつのサブドメインに、APIのリクエストをまとめる」でも語られている。

chromeから複数アカウントでツイートしたい

検索キーワード: Hootsuite Hootlet chrome multi account just tweet share page

前提条件

  • ChromeからTweetがしたい
  • Twitter複数アカウントを切り替えながら使っている
  • TLを見ると集中力がそがれるので一方的にTweetするだけにしたい
  • url shortenerは使いたくない(セキュリティ上の問題などあるため)

解決案

  • ❌ TweetDeck
    • マルチアカウントに対応できるがTLを見ず投稿する機能はない
  • ❌ Hootsuite Dashboard
    • マルチアカウントに対応できるがTLを見ず投稿する機能はない
  • Share on Twitter - Chrome ウェブストア
    • TLを見ず投稿できるがマルチアカウントに対応していない
  • Just Tweet ボタン - Chrome ウェブストア
    • TLを見ず投稿できるがマルチアカウントに対応していない
  • Hootsuite Hootlet - Chrome ウェブストア
    • マルチアカウントに対応できTLを見ず投稿する機能があるが、動作が不安定
      • そのページ内でJavaScriptを動かすためgithub.comのようなページで実行するとエラーで動作しない
    • URL shortenerを無効化できない
    • おまけにgoogle検索結果やgoogle mapなどへ勝手に変なリンクなどを挿入する。XXXX
  • 🔺 hootletのbookmarklet( Hootlet Link Share Tool - Hootsuite の下部 )
    • マルチアカウントに対応できTLを見ず投稿する機能があり、動作が安定している
    • URL shortenerを無効化できない
  • ⭕ [上のbookmarkletを参考にしたURL shortenerを使わないオリジナルbookmarklet(Just Tweet With Hootsuite - Hatena::Let)
    • マルチアカウントに対応できTLを見ず投稿する機能があり、動作が安定している
    • URL shortenerもトリックで(URLとしてではなく単なるテキストとしてAPIに渡す)無効化できる

結論

Just Tweet With Hootsuite - Hatena::Letを使いましょう。

PofEAA感想 14章~18章

第14章 Webプレゼンテーションパターン

ビューとコントローラの分離は、比較的重要ではなく、必要なときにだけ分離を実践することを推奨する。

なるほど、そういう考えもあるのか。

多くの人にとって基本的なWeb環境とは、静的なHTMLページである。

時代は、変わった・・・。

トランスフォームビュー、ツーステップビューなどは飛ばす。今はclient(ブラウザ)側でもMVCバリバリなコードを書くのでサーバがUI(HTML)を描画して返す時代ではない。

第15章 リモートファサード

ここで説明していた役割は今RESTful APIサーバなどに変わっていると思う。 なので流した。

第16章 オフライン並行性パターン

軽オフラインロックは楽観的オフラインロック、重オフラインロックは悲観的オフラインロックと読み替えること。

楽観的オフラインロックの仕組みとしてはバージョン番号(auto incrementな整数のイメージ)を使う。 タイムスタンプはシステムクロックが当てにならない、特に複数サーバの場合同期が保証できないので使わないほうがよい。 master-slave型のDBであればDB側に時間を挿入させることでタイムスタンプを使ってもよいかもしれない。

一貫性のない読み込みと楽観的オフラインロックで防ぐ方法、タイムスタンプを使えば楽だと思ったがウェブサーバとDBサーバの時間が完全に同期していることを保証するのは難しいのでこのアプローチはいまいち。

(意訳) checkCurrentメソッド - 今他の誰かがデータを更新しているかどうかをバージョンカラムの値などからチェックする

書かれている通り長大なトランザクションを処理しているとき、その開始直後に失敗することが確定しているケースがある。 そういったときにこの関数でそれを予め知ることができれば非常に時間のかかるが失敗することが確定している処理に無駄な時間を割かなくて済む。

読み書きロック

これは非常にいいアイデア。何かのときに使いたいツールとして覚えておこう。

16.3 粗粒度ロック

エンティティツリー(DDD本では集合体 - aggregateと呼ばれているっぽい?)単位でロックを設定するパターン。

16.4 暗黙ロック

過去に関わっていた某システムで最用紙していた方式。 ただ、あまり良い方式には思えなかった。結局の所程度の差はあれプログラマートランザクションを常に意識する必要があり、それを暗黙的にすることはあまりよさそうではない。usingパターンを利用して勝手に開放してくれるようにするのはいいと思う。

17 セッションステートパターン

クライアントセッションステートが現代のWebアプリケーションでは良いのではないかと思う。 サーバセッションステートもデータベースセッションステートもスケーラビリティに欠け、また純粋なHTTPの考えに反する。 クライアントのコミット前の情報はクライアントサイドで持つべきである。

第18章 ベースパターン

基本的に今まで参照してきたのでスキップできる。

終わったー

PofEAA感想 9章~13章

第9章

P123

ドメインモデルっていろいろ曲解誤解されがちだけど、基本的にはデータとメソッド(振る舞い)を同じものに持たせるという古典的なオブジェクト指向そのものなんだよな。 トランザクションスクリプトやテーブルモジュールなんてものがむしろ基本的なオブジェクト指向の考えに反しているだけで。

~さらに継承が使われるのである。

現代のモダンな言語では継承は使いたくないなあ。

読んでいて思ったけど、近年の言語ではデータとメソッドとの区別が非常に曖昧になりつつある(RubyしかりScalaしかり)。 もはやオブジェクト指向定義上の「オブジェクトとはデータと振る舞い(メソッド)を持つ」というのは古くて、 内部状態としてのデータと外部インターフェイスとしてのメソッドを持つ、といった表現のほうがよりモダンなんじゃなかろうか。

P128

ドメインモデルで共通して見られるのは、複数のクラスが最もシンプルなタスクでも相互作用する方法である。この方法では、オブジェクト指向プログラムで膨大な時間を掛けてクラスからクラスへと探し続けなくてはならないというストレスを引き起こすことがある。

わかる。 ただドメインモデルのためにその欠点を飲んでやるってことは、長期的・より発展的な開発ではメリットがあっても短期的にはむしろトランザクションスクリプトでオブジェクトを活用せずprimitive型とarray、あと関数のみで書いたようなひどくシンプルなものののほうがわかりやすくなるっていうのが逆説的にはっきりした。

(意訳)ドメインモデル、というよりより純粋なオブジェクト指向は分岐をなくす

たしかに。

P 134

anEmployeeModule.getAddress(long employeeID)

テーブルモジュール、今まで1テーブルを1オブジェクトに紐付けると書いてあって訳し間違いか解釈の違いかと思ったら本当にそうだったのか! 複数レコードの集合としてクラスを定義するのはアリだとしてもそれは1レコードに対して1オブジェクトを対応付けた後のオブジェクト集合としての立ち位置が本筋で、集合の方のみをオブジェクトとするのはナンセンスな気がする。 これは現代ではまったく主流じゃないし、アクティブレコードすら1レコード1オブジェクトを返している。これは詳しく読まなくても良いかもなあ。

9.4

ここら辺のサービスレイヤの話はかなり眉唾。 DBやビジネスロジックなどのより具体的なレイヤーわけ理由がサービスレイヤにはない気がする。 アイデアとしてはありなのかもしれないが実態としてはエンジニアそれぞれが自分のサービスレイヤ定義を持ち始めて収集がつかなくなるリスクのほうが高い。 私はできるかぎりサービスレイヤの定義・利用は避けたい。

9.4.2

(意訳)クライアントが1種類で、リクエストレスポンス上で複数のトランザクションが絡んでいない場合は不要。 言い換えると複数の種類のクライアントをサポートしたい場合のみ利用するべき

だよなあ。ただしこの記述に反してサービスレイヤは乱用されている気がする。

第10章

テーブルモジュール、だいぶイメージがわかってきた。.NETで顕著らしいがUIのカラムビューでそのまま表示できるように、複数レコードをそのままアプリケーション内で長く持ち運ぶような環境だとよいっぽい。 でも実質的に.NET専用なんじゃないかなと思う。

今更だけど、この使用するタイミングって節死ぬほど大切だな。ここをちゃんとチェックすれば誤用を避けられるし変な使い方をしている人やシステムに対してこれをproofとして反論できる。

(意訳) 行データゲートウェイとアクティブレコードの違いは前者はオブジェクトにドメインロジックが含まれないが後者は含まれる

なるほど、これで行データゲートウェイが完全にイメージできた。

P170

Active Record uses the most obvious approach, putting data access logic in the domain object.

アクティブレコードはこれを使ってデータアクセスロジックをドメインオブジェクトに配置する。

これも相当やばい翻訳。 正しくは以下。

アクティブレコードはドメインオブジェクト内にデータへアクセスするロジックを置くという最も明快な方法を使う。

ここはてなブログが経過を消しやがって10ページほど記述なし

P183

一意性マッパー、やはりプログラム内でのここのテーブルに紐付けられたキャッシュ層か。 これはアプリケーションサーバが水平展開されるとまったく使えないテクニックなので基本スキップしていいかな。 この層をredisやmemcacheと言った揮発性の共有できる永続化層にて行う方法もあるが、そこまでやるならクエリベースでキャッシュするほうがシンプルそう。

一意マッピングはDBへクエリを投げるオーバーヘッドが期待より大きく、よっぽどパフォーマンスを最適化しないといけないケースでは選択肢の一つとなりえるかもしれない。それでもクエリベースのほうが良いような気はするが。何よりサーバが複数になると矛盾が発生するのが良くない。

第11章

なるほど、ユニットオブワークは単なる登録所、文字通り作業単位としてドメインオブジェクトを登録しておいてプログラムからのコミット呼び出しで登録されていたオブジェクトすべてに対してcommitを発信するのね。

登録時と比較して更新がなかったオブジェクトはSQL送らなくて良いとか書いてあるけど細かすぎる最適化の気がする。 おまけにオブジェクトが変わったかどうかでSQL発行されるかされないか変わるとなると挙動が複雑でよくわからないバグの温床になる。

これってtransactionとほぼ昨日同じでは?外部永続化装置がRDBMSのみならユニットオブワークを使う意味なさそうだな。

11.3 レイジーロード

ちょっとよくわからないものもある。レイジーイニシャライズとゴースト以外は具体的にイメージがわかない。 レイジーロード自体テクニックとしては重要だが必ずしも毎回使うわけではないのでレイジーイニシャライズ以外のテクニックはほとんど使わないんじゃないかと思う。レイジーロードをまとめる手法などはやりすぎだ。こんなものを使う前にオブジェクトの構造を見直したほうが良い。

レイジーロードの追加は、プログラムが若干複雑になるため、私としては本当に必要なとこき以外はあまり使いたくない。

禿同

P235

キーテーブル、こういった手法を見たことがある気がする。java用のスキーマ管理ツールやSCT・DMSなどでこういったものがあったよね。

第12章 オブジェクトリレーショナル構造パターン

この章、オブジェクト(レコード)間の相互参照をどうRDBMSオブジェクト指向言語の間で変換するかって話なのね。 オブジェクト指向言語ではひどく単純に参照元に参照先のポインタを保存するメンバー変数を用意するけど、リレーショナル・データベースでは1対多や多対多のケースで素直には行かない。 なのでRDBMSオブジェクト指向言語プログラミングの間では関係性をうまくマッピングしてやる必要があると。

12.5 依存マッピング

DDD本にエンティティ単位のオブジェクトグラフのアイデア(エンティティだっけ?)があった気がするけど、その単位でDBから読み出し/書き出す話。 根っこのドメインクラスにしかマッピング機構を持たないというのは自然だがたしかに良い方法。

12.6 シリアライズLOB

パフォーマンスクリティカルでもない限りそうそう使わない。だが文中でXMLならいいとこ取りできると言っていることは今ならJSONカラムがよりスマートに解決している。

レポート用

以前もレポート目的という記述があったが具体的にそれが何を指すかはまだ出てきてない。 さっさと実態を知りたいが、索引に載っている?

12.6~9 シングルテーブル継承、クラステーブル継承、具象テーブル継承

全部継承を使う前提なので基本悪手。オブジェクト指向の論理をRDBMSに持ち込もうとしているので簡単な部分ではうまく行くが問題が複雑になればなるほど歪みが増え、やがて破綻する。 そして僕らの仕事で簡単なことをできるケースはまれ。

第13章 オブジェクトリレーショナルメタデータマッピングパターン

メタデータマッピング、scalikejdbcだとcase class周りな感じか。 ただメタデータというメタデータは実際にないよね。scalaは表現力が高めなので内部DSLでなんとかできると解釈するか。

13.2 クエリオブジェクト

scalaの内部DSLSQLクエリを直接書くのではなくオブジェクトとメソッドの呼び出しで擬似的にSQLクエリを組み立てるテクニック。C#にもこういうのあったよな。

13.3 リポジトリ

ここの記述ではクエリオブジェクトを使うこと前提みたいに書いてあるけど、単純にエンティティツリーとRDBMSを直接紐付けるだけのレイヤーでもいいんじゃないかな。むしろクエリオブジェクトをわざわざ作るのはイケていない気がする。

PofEAA感想 4章~8章

第4章

サーバページ手法は「アルバム #1234 の詳細を示せ」など、レスポンスの処理が少ない場合に有効である。

PHPASPなどの仕組みについて。たしかに静的HTMLが多いサービスではPHPによる最低限のスクリプティングは有効だが、 現代ではそのようなサイト・サービスはほぼ新設されないだろう・・・。

コントローラは、多くの異なるコンテキストで使用される。

せやなあ。お互いの指しているコントローラの定義が違うことでよく混乱が生じた。

テンプレートビューを使用すると、(中略)結果として、サーバページ技術を使用するのであれば、多くの場合ヘルパーオブジェクトを使用して、ページ構造から切り離してプログラミングロジックを保持することを守らなければいけない。

せやなあ。そしてそれはどう考えても良い手じゃない。

テンプレートビュー、トランスフォームビューについて

現代ではAPI + リッチクライアント(SPA)が主流?トランスフォームビューのたとえで使われているXSLTって今まで一度も聞いたことなかった。

A single-stage view mostly has one view component for each screen in the application.

ほとんどの場合、シングルステージビューには、アプリケーションの画面ごとに1つのビューコンポーネントがある。

この訳はいくらなんでもおかしくね?

シングルステージビューはほとんどの場合アプリケーションのそれぞれのスクリーンごとに1つのビューコンポーネントを持つ。

"には" "がある" の翻訳が致命的にニュアンスを失わせている。 この辺でもう英語版読もうかという気になった。 この翻訳、こちらでいう腐った翻訳に該当する気がするなあ。

Page Controllersはクラシックな1エントリポイント1ビューな感じ。 その下のFront Controllerはエントリポイントが1箇所に集約されている、golangのweb serverみたいな感じ。

第5章

並行性のテストは難しい。

確かに。スレッド/プロセスを制御しつつテストすることは難しい。 進行状況を任意の状態に制御しつつだとなおさら。 さらにそれが容易に可能だったとしても今度は並行状態のパターン列挙は非常に難しい。 おそらく入力値の境界値分けによるテストケース生成と同じようなパターンになるだろうが、引数が増えれば値の組み合わせが増えるように並行実行の場合実行されるスレッドが増えるにつれテストケースもn乗で増えていくのである。

システム受け入れテストで最低限の動作保証を行うのが第一歩だろうが、この手の並行性の問題はカオスエンジニアリングを用いて本番でテストをしてすら検出することは難しい。 並行性の問題は現実的には起こらない理論上の問題ではなく、特定の状態、特定のタイミングでつまり確率的に必ず一定確率で起こるという質の悪い問題だから、無視することも難しい。

おそらくは並行処理を最低限に留める戦略が良いのではないかと思う。 複数・大量のデータをマルチスレッド・プロセスで並行実行するOpenMPのようなイメージの並行処理、これは良い。 なぜかというと以下の理由からマルチスレッド化したことによる複雑性の上昇が最低限であるためである。

  1. 処理対象と結果のデータが各スレッドで縦割りされており、スレッド間での書き換え可能なデータ共有(共有メモリモデル的な)が発生しづらい(共有メモリモデルによる並行処理の問題点はコップ本など参照)
  2. 各スレッドの処理が一様であり複雑性が低い

無論このタイプの並行処理を行う場合でもまずはパフォーマンス分析を行うことが最優先である。 80:20の法則を理解してネック部分だけをデータを基準とした平行化するのは十分に利益あるんじゃないかな。

ノードベースの並行性はできるならノード間結合テスト(全体テスト)で検出したいところ。

One of the great ironies of enterprise application development is that few branches of software development use concurrency more yet worry about it less.

皮肉なことに、エンタープライズアプリケーション開発において、並行性を使用することがなく、そのことを問題にしていないソフトウェア開発部門もある。

また誤訳

皮肉なことに、エンタープライズアプリケーション開発において、並行性を使用しているが、そのことをあまり問題にしていないソフトウェア開発部門もある。

こんな翻訳でよく他の人は読めてるな。本当に正常に中身を理解できているんだろうか?

あとこの指摘は非常によく分かる。PHP系のWebアプリケーションを開発している人間が並行性についてかなり無頓着なのはこの背景があると思う。

As long as you do all your data manipulation within a transaction, nothing really bad will happen to you.

ここまで読んでやっと気づいたけど、こう書いてあるってことはここまでの話に出てきた並行性って主にデータソースが絡んだ外部永続化データの操作に関してで、共有メモリモデルのことはまったく念頭に置かれていない?

その後やっとマルチスレッドの話が出てきた。これまでの並行性の話はapacheがリクエストの度にspawnするスレッドのイメージだったようだ。

After all, if you aren’t familiar with source code control systems, you really shouldn’t be developing enterprise applications.

最後に、もしあなたがソースコード管理システムに慣れていないようであれば、あなたは本当にエンタープライズアプリケーション開発をするべきでない。

辛辣w けどそのとおりだよなあ。

しばしば一貫性のない読み込み問題は見過ごされがちである、なぜならほとんどの人々は更新喪失問題が並行処理の最も重要な問題だと捉えがちだからである。

せやな。

Temporal reads

こんなところで過去に技術的に衝突した問題の解決策を見るとは・・・。

デッドロックの解説、とくにその回避策の列挙と説明・例がめちゃくちゃわかりやすい。

Consistency: A system’s resources must be in a consistent, noncorrupt state at both the start and the completion of a transaction.

一貫性(COnsistency):トランザクションの開始時点から終了時点まで、システムのリソースは必ず一貫した正常な状態で無くてはならない。

おしい。開始から終了までではなく開始と終了時点のみでいい。間ずっとだとしたらbetweenを使う。

Across multiple transactions the application’s responsibility is to ensure that one session doesn’t step all over another session’s changes, leaving the record set in the invalid state of having lost a user’s work.

複数のトランザクション間での(一貫性をサポートする)アプリケーションの責任は、レコードセットをユーザーの作業を失った無効な状態にしておくことで、あるセッションが別のセッションの変更を一歩も踏み出していないことを保証することです。

ちょっとよくわからん。作業中の状態をデータベースへ一切書き出さないってこと?

そのあとビジネストランザクションはセッションと1対1で紐付けるほうがよいって書いてあるけどそのとおりだとは思う。 ただ、近年の高度に自由度の高いアプリケーションではセッションが使われない・使えない・使いにくい状況も多く、このプラクティスに十分な現実性があるかはちょっとわからない。

5章読了。長い上に概念的にも難しい単語が多くなかなかきつかった。 これでこの分野の上辺だけっていうのだから並列実行はなるべく簡単な部分のみ触っていきたい。

第6章

開幕でStatefulをステートレスと誤訳していてうんざり

この6章は旅行中読んでいたのでメモはほぼない。

第7章

この章も翻訳ミスが多い。価値を表すValueを値と翻訳していたり、有名なData Transfer Object → データ変換オブジェクト の翻訳ミスなど。

XML - httpインターフェイスについてはこの時代での意見でしかなく、今ならRESTful API、更にはgraph-QLが主軸になるだろう。

第8章

ユニットオブワーク、先に11章を見て概要を把握したけどアプリケーション内でDBのサブコピーを作ってビジネストランザクションレベルでの変更を一旦プールし、ビジネストランザクションの終了時 = コミット時に本当のDBへ反映するようないわば階段の踊り場的仕組みを指しているらしい。 多数のサーバが並列でスケールするような今、そういった仕組みは1サーバで完結せず良くない気がするね。

ここでJavaと.NET環境にこだわるのは、これらが将来にかけてエンタープライズアプリケーション開発の共通プラットフォームになる可能性が高いからである(ただし、個人的にはPythonRubyなどの動的に型付けされるスクリプティング言語を検討したいし、競争も必要だと思う)。

書かれた時代を考えるとなかなかの慧眼。

ストアドプロシージャについて

せやねぇ、たしかにこれを使えば大小の問題はあるものの基本的にパフォーマンスは上がる。 けどポータビリティや冗長化・エラー処理・スケーリングに問題が多いから他の選択肢が有効でない部分だけ特効で最適化するために使うって方針がたしかに無難。

Webサービスについての考察は時代背景的に古いモノではあるものの、確かにマイクロサービス的なものも視野に入っているのはやはりさすが。

Webサーバ/APIサーバ用コンテナイメージの標準化を考える

きっかけ

まだ僕がコンテナ技術に不慣れなこともあって、こういった標準仕様が存在すればよいなと思っていたことがちょうど言語化されたものをtwitterで見た。

  • コンテナに割り当てるリソースの管理
  • オートスケーリング
  • graceful shutdown
  • logの転送
  • 秘匿情報のinject

これらはコンテナでWebサーバやAPIサーバを構築する場合どれもほぼ必須だったりあれば非常に便利にも関わらず、実行環境や個人の好みに実装が依存してしまっている。結果的に各地で車輪の再発明が行われたり手間を理由に実装が後回しにされている。

Web Developer も知っておきたい Kubernetes における Sidecar Pattern と Ambassador Pattern - Quipper Product Team Blogこの記事のようにここの項目で優れた技術やアイデア・仕組みが創出されても再利用されづらいのが問題である。

提案

次のようなコンテナイメージのインターフェイスの標準仕様はどうか。

  • 名前: Elastic Container Implementation Standard 柔軟性を持ったコンテナ実装の標準仕様(仮)
  • 利用方法: コンテナ作成後、そのコンテナのインターフェイス仕様を記したJSONファイルを作成してセットで取り扱う。
  • JSONサンプルイメージ
{
    "resouce": {
        "memory": "4G",
        "vcpu": 2
    },
    "scaling": {
        "min_instance": 1,
        "max_instance": 10,
        "min_cpu": "3%",
        "max_cpu": "90%",
        "min_memory": "10%",
        "max_memory": "80%"
    },
    "shutdown": {
        "max_wait_disconnection": "60s"
    },
    "log": {
        "path": "/var/log/apache/"
    },
    "variable": [
        "env",
        "db_url",
        "db_user",
        "db_password"
    ]
}

まずコンテナイメージ作成側のメリットとして、無数のバリエーションがあったリソース管理やオートスケーリングしきい値の設定方法、logの転送方式が標準化され、実装者による仕様のブレがなくなる。 コンテナ基盤(kubernetesやECS、あるいはその上に構築されるコンテナ実行環境)側のメリットとしてはまず提供するべき機能が明確になる。次にコンテナ側の仕様が固定されるため個別のコンテナの仕様に合わせる必要がなくなる。

次のステップ

実際に上の仕様にそってコンテナイメージを作ってみる。 また、その仕様に沿ったコンテナを実行できる環境をKubernetes(できるならEKS?)ベースで構築する(CloudFormationかTerraformを使いたい)

蛇足

イデアとしては動かすアプリケーションの仕様をyamlで定めたElastic Beanstalkと思想が通じるものがある。 この仕様はBeanstalkがサポートしていたDocker以外のアプリケーションを切り捨てることでDockerに特化し、かつ仕様をシンプルにしたものと言える。

PofEAA感想 はじめに~3章

はじめに

HTMLよりも優れたフロントエンドを望むためリッチクライアントが求められる

内容が古いため今の実情と乖離しているところもある

その理由は、パフォーマンスに関するアドバイスは、現実のシステム構成でパフォーマンスの測定を行ってみるまでは、当てにならないからである

現在になるまでこの点は一切変わってねえなあ。だからカオスエンジニアリングなど生まれたんだろうが

第1章

編集途中で消えて萎えたのでなし

第2章

レコードセットが何を指すのかわからん。 単なるRDBMSの行の集合ではなさそう。 → P36

レコードセット、つまりデータベースのテーブルの性質を持つ、テーブルと行で構成された包括的なデータ構造

第3章

3.2、ユニットオブワークという名前でDBデータ(レコードデータ)の書き込みを含めたオンメモリ上でのキャッシングの話をしているけど、 今の横にスケールさせるアーキテクチャではキャッシング機構が1サーバで完結しないので微妙な気がするね。 現代ではもっとシンプルなキャッシュとトランザクション手法が取られるんじゃないかなあ。

3.3、joinを使って複数のテーブルのデータを一気に返す方法、それはできるけどさすがに悪手だろw DBへのクエリ回数が膨大なシステムだとそうやって最適化する方法はあるかもしれないね。最終手段だろうけど。

3.4.1のオブジェクト型とリレーショナルデータベース間の関係情報の保持の仕方についての説明は非常によくわかる。 しかしその後の一意マッピングやレイジーロードといったアプリケーションサーバ内での頑張りすぎるキャッシング手法はあんまりイケてない。というか現代でやったら顰蹙モノの複雑さだと思う。

LOBに関してDB自体がその内包データを理解できないという欠点は、現代ではJSON型としてOracle, Mariaなど各プロダクトが限定的ながら解決しつつある感じ。

3.4の継承とRDBの問題については継承をそもそも否定的だからこの手法もややこしくなっているのだと思う。 たしかに説明されている3パターンは現実に取りうる解だが、そもそもオブジェクト指向とリレーショナルデータベースをうまいことマッピングするのがORマッパーなり各種DBライブラリの役割なわけで、継承という非常にオブジェクト指向らしい特徴をリレーショナルデータベースに持ち込む事自体が相当な悪手じゃねえかなあ。 しかしそれを考えるとオブジェクト指向RDBインピーダンスが発生しているという指摘は重い。DBの接合部分に全体の1/3のコーディング労力が割かれているというのもあながち大げさではあるまい。

3.5.1、相変わらず技術書の英訳はガバガバ。

The extra step only pays for itself when you have many commonalities, so you should use it when you have similar but annoyingly different physical data stores.

追加のステップは、多くの共通性がある場合にだけ有効なので、類似性はあるが異なる物理的なデータを格納する場合は追加のステップを使用するべきである。

data storesのstoresを動詞として約してしまっている。実際には名詞。 以下が適当か

追加のステップは多くの共通性がある場合にだけ有効なので、類似性はあるが異なる物理的なデータストアを2つ以上使用する場合に追加のステップを使用するべきである。

3.7 データベースのコネクションプールは本質的に状態を持ってしまっている(使い回されるコネクションが前回の利用の影響を受けていないことが保証できない。また接続されて最初のクエリとその後のクエリで挙動やレスポンスタイムなどが変わることもある) = immutableでない ことからあんまりよくないかも。サーバレスフレームワークが前提のアーキテクチャではコネクションプールは期待できないし、各リクエストの独立性を高めるためにも毎回コネクションを張り直す方式が取れるならそのほうが良い。またこの本自体にもそう書かれていた(意外)。

新しい接続の生成速度が速くなっているなら、プールする必要はない。

This advice leads to a couple of issues: making sure you have the connection everywhere you need it and ensuring that you don't forget to close it at the end.

この方法では、2、3の問題が生じるので、必要であれば接続し、終了時には忘れずクローズするべきだ。

ひどい訳。以下が適当。

この方法には次の2つの問題がある: あなたがコネクションを使うところすべてでそれを持つ(実質的に作る = コネクションを張る?)必要があることと最後にそれを確かにクローズしないといけないことだ。

しかしこれだけ面倒くさいRDBオブジェクト指向型言語の間のパターンを多数見せられると両者の間のインピーダンスの高さを実感する。 RDBを使うのって今は当然だけど本当にそうか?オブジェクト指向型言語でいいのでは? まあでもそれMongoDBか。