「150万時間の消失」を、エンジニアはどう受け止めるべきか

川崎裕一さんの「マッキンゼー『150万時間の消失』が告げる、ホワイトカラーの残酷な選別と生存戦略」を読みました。

comemo.nikkei.com

主張ははっきりしていて、AI によって「検索・要約・グラフ作成」といった、これまで “時間単価で値付けされていた作業” が価格を失うということです。

その結果、時間の切り売り (Time-based) から成果報酬型 (Outcome-based) への移行圧力が高まり、組織は二極化し、中間層が蒸発すると書いてありました。

方向性としては鋭いし、危機感も感じられます。

 

ただ、エンジニア目線ではそのまま当てはめると、ちょっとズレるところもありそうだと感じました。

「AI で要件定義や実装のスピードが上がる」→「単価が下がる」まではその通りだと思いますが、その次の「どうやってこの先生きのこるのか?」について考えてみようと思います。

 

結論から言うと、AI で速く作れる時代に単価を守るのは「運用を設計できる力」ではないかと考えています。

1. 「時間が消える」とは、エンジニアとしては何が消えるのか?

まず前提として、AI を使うことで開発スピードが上がることは、すでに現場でも実感があると思います。

ざっくり書いただけでも、

  • 仕様を読み取る
  • 設計の壁打ちをする
  • コードを書く
  • リファクタリングする
  • テストの雛形を生成する

など、このあたりは確実に加速しているところです。

ここで一番大事なのは、「時間が消える = 仕事がなくなる」わけではなく、 スピードに値付けされていた時間が価格を失う という点です。

つまり、要件定義や設計、実装が不要になるのではなく、「速く作れるようになります!」だけだと説明できる価値が薄くなってしまう ということです。

2. 運用保守は "後工程" ではない

一方で、システムは作って終わりかというとそんなことはなく、運用保守が始まります。なんならそこから使ってもらうことがスタートと言ってもいいでしょう。

このフェーズでの障害や事故は、次のところから湧いてきます。

  • 境界条件想定外の入力、データの欠損、例外系の業務
  • 性能:ピーク時のスパイク、データの偏り
  • 観測不能ログやメトリクスが足りずに切り分けできない
  • 権限や監査:誰が何をしたかが残らない、説明できない
  • リリース:障害時にロールバックできない、戻すと壊れる
  • データ移行:戻せない、再実行できない

また、(自社を含め、) 顧客の業務は日々変わっていくため、変化にも耐えられるアーキテクチャーであるかも重要です。

これらは「作って、運用してみないと分からない不確実性」の塊で、現時点での AI は "正しそうなコード" は出せても、顧客の業務や運用の地雷原を把握しているわけではありません。

そのため、AI が生み出すスピードをそのまま本番環境に流すほど、事故の確率はむしろ上がりやすいと感じています。

ここで私が言いたいのは、

運用保守の要件を設計フェーズから "織り込む" ことが重要で、そこはまだ人間の取り分が大きいのではないか

ということです。

3. 「時間売りの終焉」をエンジニアはどう捉えるか

川崎さんの記事は「時間売りが崩壊し、成果報酬型へ」と言います。これはおおむね正しいと思います。

ただ、エンジニアの “成果” は、売上 (システムを作って売った) だけではなく運用保守にある ―― 近年は SRE というポジションや、Four Keys など、よく使われる指標もあります。

  • 稼働率 (可用性)
  • 障害率 (品質)
  • MTTR (平均復旧時間)
  • 運用工数 (誰の何時間が削れるか)
  • 監査対応工数 (ログや証跡が揃っているか)
  • リリース頻度と失敗率 (デプロイの健全性)

これらを設計段階から織り込めるかどうかが、エンジニアの “Outcome” になります。

 

AI の活用により、要件定義や開発の単価が下がりうるのは事実です。ですがその分、価値の中心は、

「運用まで含めた成果 (信頼性・回復力・観測可能性)」

へと移っていきます。

ここは、AI が強い領域というより、人間および組織の経験・判断・責任の領域だと考えています。

4. 「志・判断・創造性」を、エンジニア向けに翻訳する

マッキンゼーに関する記事では「志・判断・創造性」が、AI 時代の人間に必要なスキルとして挙げられています。

エンジニアに寄せて、私なりに翻訳してみます。

 

志 (Aspiration):運用まで含めた“到達点”を言語化できる

  • 例:SLO / SLA、夜間呼び出しを減らす、障害時の復旧 30 分以内、監査対応を半減 ...


判断 (Judgment):トレードオフに責任を持てる

  • 納期 vs 品質、コスト vs 性能、シンプルさ vs 拡張性、手戻り vs 安全性 ...


創造性 (Creativity):“事故を前提にした設計” を工夫できる

  • 観測可能性 (ログ・メトリクス・トレース)、ロールバック、フェールセーフ ...

 

エンジニアとしては「これまでやってきたことを着実にこなしていく」になるでしょう。ですので、そこまで悲観的にならなくてもよく、より運用保守に関する知識が重要になってくると考えています。

まとめ:AIで速く作れる時代に、エンジニア単価を守るのは “運用を設計できる人”

川崎さんの記事の警鐘を受けて、エンジニア目線での影響と今後の価値について考えてみました。

 

AI の活用で開発は速くなる。だからこそ「速さ」だけでは勝ちになりにくい。

 

これから単価が守られるのは、 運用に耐えられる確度 (観測・復旧・説明可能性) を、設計の時点で "仕様" として作り込めるエンジニアだと思います。

言い換えると、エンジニアとしての価値の中心が「作れること」から「運用できること」へ移ることです。

 

“150万時間の消失” を恐怖で終わらせず、設計の責任範囲を一段前に進める。

それが、エンジニアの現実的な生存戦略だと考えます。

「ハーモニー」を意識して仕事を進める

私は仕事や会議などの進め方について、なにごとにも「流れ」を考えることで上手くいくと考えてきましたが、この「流れ」という言葉にはどこかしっくり来ていませんでした。 そんな中、あるブログ記事で「ハーモニー」という言葉が使われているのを見て、「これはオシャレだ」と思い、今回は改めて「ハーモニー」について考えてみたいと思います。

「ハーモニー」という言葉

プロダクトオーナーの考えるべきところ - kawaguti's diary では、次のように言及されています。

システムはハーモニーなので、継ぎ足して別の人を追加すると繋がらない

ここで指摘されているとおり、“何かをつぎ足せば勝手に成り立つ”ものとしてシステムを捉えるのはよくない、という意味だと理解しました。つまり、複数の要素が調和することで、ひとつの完成形をなしているのだといえます。

ハーモニーとは

Wikipedia には、次のようにあります。

ハーモニー (英語: harmony) は、ギリシャ神話のハルモニア (Harmonia、ギリシア語: ‛αρμονία)に由来する言葉で一般に物事の調和のこと。オリジナルはギリシャ語で「一致、連結」を意味する。

「調和」「一致」「連結」といったキーワードを俯瞰すると、複数の要素が統一的な全体をなす、すなわち“ひとつにまとまること”が「ハーモニー」の本質だと感じます。仕事を進めるなかで生じる様々なモノやコト、そして人が、それぞれ噛み合うことで“成果”という形になるのではないでしょうか。

仕事の「ハーモニー」

「調和」「一致」「連結」。仕事においてこれらを意識すると、無理や無駄が減り、最終的なアウトプットの質が上がると考えられます。

  1. 調和 (コトバンク Link)
    • 本来は独立している複数の要素が、共通の目的やゴールによってひとつの形をつくること。
    • たとえばプロジェクトメンバーの役割分担が整理され、適切に連携していれば、それぞれの作業は全体に溶け込みやすくなる。
  2. 一致 (コトバンク Link)
    • 2 つ以上の考えや意思が同じ方向を向き、同じゴールへ向かおうとすること。
    • 会議や議論でコンセンサスを取るのは時間がかかるが、そこで目指したいのは、個々の意見が形だけそろうのではなく、目的に向けて心が同じ方向を向く “一致” である。
  3. 連結 (コトバンク Link)
    • ひと続きになるようにつなぎ合わせること。
    • 言い換えれば、段階ごとの目標や役割がしっかり連結していれば、自然と“流れ”が生まれ、無理なく“ハーモニー”が構築される。

こうした「ハーモニー」の視点から仕事を見ると、どの要素が不足しているか、逆にどの要素が過剰なのかに気づきやすくなります。すべての要素がつながり、ゴールへ向かっている状態をイメージすることが大切です。

ハーモニーを生む進め方

仕事を“ハーモニー”として捉え、整合性のある流れにするにはどうすればよいのでしょうか。ポイントは、 ゴール(目的)の明確化リソースの適切な配置 だと考えます。

  1. ゴール(仕事の目的)を明確にする
    • まずはどこを目指しているのかを、関係者全員が共有できる形で定義する。
    • ゴールを曖昧にしたままだと、後から要素をつぎ足しても全体で噛み合わなくなる可能性が高い。
  2. 現在のリソースを明確にし、どのように利用するかを考える
    • リソースには「ヒト」「モノ」「カネ」「時間」「情報」など様々な要素がある。
    • それぞれの状況を可視化し、どの部分にどのくらい投入すべきかを考えることで、効果的に仕事を進めることができる。
  3. 中間ゴールを定めて、適切なリソースを投入する
    • 大きなゴールにたどり着くまで、いくつかの段階を設定する。
    • その段階ごとに必要なリソースを投下し、成果物を検証して次につなげる。
    • このとき、有名なフレームワークとして「エビデンスベースドマネージメント (EBM)」がある。事実(エビデンス)に基づいた検証と改善を繰り返すことで、プロセス全体のハーモニーが保たれやすくなる。
  4. ステークホルダーによって説明内容を変える
    • 外部関係者には「ストーリー(流れ)を語り、結末を想像させてワクワクさせる」ことが効果的だと思う。
    • 一方、内部関係者には「全体像」を示し、上流から下流までのつながりを意識させることが必要。
    • こうしたアプローチの違いが、それぞれの当事者をうまく動かすカギになるのではないか。

注意点:負荷や無駄を抑える

一方で、「ハーモニー」を意識しすぎると、かえって負荷が増える場合もあります。全体をひとつにまとめるには、それなりのエネルギーが必要です。

  • たとえば 1 人月の仕事を 10 人に振り分けても、必ずしも 2 日で終わるわけではない。
  • リソースをやみくもに増やすと、連携コストやコミュニケーションの手間が増え、結果として “ハーモニー” どころか混乱を招くケースもある。

つまり、適切な量を、適切なタイミングで、適切な人に投入することが重要です。その「適切さ」を見極めるためには、やはりゴールや中間ゴールが明確になっていることが前提になるでしょう。

まとめ

「ハーモニー」というキーワードで仕事を捉えてみると、複数の独立した要素をいかにひとつの成果にまとめるか、という視点がより分かりやすくなると感じます。この記事では「調和」「一致」「連結」という3つの観点から、仕事の“流れ”を組み立てることで、自然と全体がまとまっていくのではないでしょうか。

ハーモニーを保つためには、 ゴールをはっきりさせるリソースを現実的に把握して段階的に投入する 、そして ステークホルダーとのコミュニケーションを工夫する ことが欠かせません。大変ではありますが、こうした取り組みを続けることで、最終的には「全部がちゃんとかみ合って、成果としてまとまる」という理想的な状態をつくり出せるのだと思います。

仕事においても、音楽の“ハーモニー”のように、さまざまなパートがひとつの楽曲を奏でるイメージを持って取り組む。そうすることで、チームやプロジェクトがより気持ちのよい“流れ”に乗れるのではないでしょうか。

メリットと条件によるプロジェクト評価手法

新製品の導入やプロジェクトの評価において、「メリット」と「デメリット」(長所と短所 / Pros と Cons)でまとめる手法がよく使われます。

しかし、この方法には以下のような問題点があると感じています。

  1. 承認者がデメリットに着目し、導入が進まないケースがある
  2. 複数の対象を比較する際、一方のメリットがもう一方のデメリットになることがある
  3. 分析の有効性に疑問を感じることがある

SWOT分析のような詳細な手法を使うまでもないケースも多いため、最近は「メリット」と、それを享受するための「条件」でまとめる方法をとっています。

「条件」は具体的な内容を考えさせられる

「条件」を考慮するこの方法の大きな特徴は、対象をより現実的な視点で検討できる点です。 単にメリットやデメリットをリストアップするのではなく、具体的な条件を上げることで実際にそのメリットを享受するためにはなにが必要かを考え、明確にすることができます。 これにより、理想と現実のギャップを埋め、実行可能なプランに繋げることができると考えています。

また、デメリットではなく「条件」として提示することで、よりポジティブな印象を与えることができ、前向きな議論が可能になると考えています。

具体例:リモートワークの導入

リモートワーク導入を例に、このアプローチの有効性を見てみましょう。

メリット: - 社員の通勤時間削減によるワークライフバランスの向上と生産性の向上

条件: 1. 社員のリモートワーク環境の整備(インターネット、機器など) 2. 効果的なコミュニケーションツールとルールの確立 3. セキュリティ対策の徹底(社員用端末のセキュリティ強化など)

この方法では、メリットを実現するための具体的な要件が明確になり、現実的な導入計画を立てやすくなります。

一方で、従来の「デメリット」アプローチでは、以下のような問題が生じる可能性があります:

  • ネガティブな印象:「コミュニケーションが難しく、効率が下がる」など
  • 表面的な分析:具体的な対策や準備が見えにくい

まとめ

「メリットと条件」を考えることで、プロジェクトのメリットとその実現に必要な具体的な内容g明確になり、より現実的かつ実行可能な計画を立てることができると考えています。 みなさんもぜひこの方法を試して見てください。より多くのプロジェクトが成功することを期待しています。

2020 年の振り返り 〜 2021 年の抱負

明けましておめでとうございます。

久しぶりにブログ開いたら、昨年は 1 記事しか書かなかったようで、アウトプット不足に驚愕しています。

2020 年の振り返り

まずは、なんといっても新型コロナウイルスの影響が大きかったと思います。

仕事的には大きなリプレース案件があったので結構忙しかったので、息抜きに勉強会に参加したいところだったのですが、軒並みオンライン開催になったので、2020 年は一度も東京に行きませんでした (たぶん)。 出張も減ったので、ほぼ家と会社を往復する 1 年でした。

マネージャーのような立ち振る舞いが多くなり、大変だった年でもありました。マネジメントに苦手意識を持っていたので、その辺りの本を多く読みました。

  • SCRUM BOOT CAMP THE BOOK     この本は、改訂版が出版されたので買い直しました。ちなみに、改訂前の本はどこかの誰かに貸してるはず。(見当たらない)
  • SCRUMMASTER THE BOOK     Scrum をもっと学びたいと思って読みました。チームをどう成長させていくか、チームと Scrum Master のレベルなど、ためになる話が多かったです。
  • エンジニアリング組織論への招待     こちらはまだ読んでいる途中ですが、Chapter 1 だけ読んでも学びがあったので、じっくり読みたいと思っています。

現在のチームが、2 年目、1 年目のメンバーでまだまだ若いので、自己組織化したチームを目指して、一緒に成長していきたいと思います。

技術的には、新たに学ぶというよりは、学んできたことの答え合わせをしてきた 1 年だった気がします。

ここ数年はドメイン駆動設計を学んできているため、できれば仕事に導入したかったのですが、既に開発ツールを導入していたプロジェクトだったため、ドメインの知識をコードに落とすということができませんでした。

そのお陰で、不具合や仕様変更のたびに設計書をひっくり返して読むプロジェクトができあがっているので、全て開発ツールではなく、業務的な要件が多いところからコードを書くように、プロジェクトを変えていきたいと思っています。

開発ツール頼りな面もあり、開発メンバーが入社からほぼコーディング経験がないというちょっとアレな状態はどうにかしなければいけないと考えています。

2021 年の抱負

あまり良くはないかもしれませんが、アプリを作る際の技術スタックを固めたいなと考えています。

  • フロントエンド: Next.js (勉強中)、GraphQL (勉強中)
  • バックエンド: Spring Framework、Node.js
  • インフラ: AWS

といった感じで、フロントエンドがほぼ仕事で使ったことがなく弱いため、フロントエンド周辺を強化していきたいと思っています。

あとは、ほぼ仮想サーバーとして使っている AWS をもう少し活用できるようにしていきたいと思っています。 特に AWS の認定資格も目指してなかったのですが、ちょっと勉強してみたいなと思っています。 それと、仕事でも BI や AI など、データを活用していく機会が多くなりそうなので、勉強中の E 資格や、統計も身につけたいと思います。

その他として、コロナの影響で在宅勤務やテレワーク可能な会社も増えてきているので、色々な環境を見てみたいなーとは思っています。 あとは、増え続ける体重をセーブしなければ・・。

・・・ということで、2021 年はより技術的なところを伸ばしていきたいと思っています。本年もどうぞよろしくお願いいたします。

読書メモ「ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本」

ドメイン駆動設計入門」を読み終えたので、感想を疑問に思ったことを残しておく。

www.amazon.co.jp

本書のコードは C# で書いてあるが、あえて Java に変更して記載する。

長文注意。

全体を通して

最終的に分かったのは、これまでやっていた DDD のほとんどが「軽量 DDD」であった、ということ。 加えて「画面に必要だから・・・」とか「検索条件的に・・・」という理由で SQL に条件やら集計処理をガンガン書いていくスタイル。 これをリポジトリに実装していたもんだから、「DDD のメリットとは?」という状態だった。

パターンを使えばいいってものじゃないが、リポジトリは集約の永続化と再構築をするもので、 細かい検索は本書にも書いてある「リードモデル」を使って実装するなど、実装の場所を決めてあげることが重要だと思った。

残念ながら今のプロジェクトは開発ツールを使っているため、ドメイン駆動設計を持ち込むのが難しい状況なのだが、 今後のプロジェクトで生かしていける知識が得られたと感じている。

おかげで半分飛ばしなが読んだエヴァンス本、IDDD 本を読もうという気になったw

著者の @nrslib さん、関係者の方々、いい本をありがとうございます!

以下、疑問に思ったことなどをまとめてみた。

P39 2.5.2 「不正な値を存在させない」

値オブジェクトを作成する動機として挙げられているもののひとつで、プログラム内に不正な値が存在しないようにするため、というもの。

本書では、例として「ユーザー名は 3 文字以上」というルールを上げている。

// NG:存在してはいけない値
String userName = "me";

この場合、値オブジェクト UserName を作成し、コンストラクターにて値をチェック (本書では「ガード節」と記載されていた。) し、不正なインスタンスが生成されないようにしていた。

public class UserName {

    private final String value;

    public UserName(String value) {
        // null はエラー
        if (value == null) throw new NullPointerException("value");

        // ユーザー名が 3 文字未満はエラー
        if (value.length < 3) throw new IllegalArgumentException("ユーザー名は 3 文字以上です。(value)");

        this.value = value;
    }

}

疑問に思ったのは、UI 側でも同じエラーチェックをしたい場合、どのようにルールを 1 箇所で管理するかどうか。

ドメイン駆動設計に関して似たようなパターンとしては「仕様」があるが、それを使って UI とドメインのエラーチェックを共通化できるのではないかと考えた、ただし、それはあくまで UI とドメインが同じプログラミング言語を使っているとき限るのかなと思った。

いまのプロジェクトの場合は、最終的にはデータベースに永続化するため、テーブル定義書に桁数やコード体系などをまとめているため、そちらを参照して別々に実装してしまうケースが多い。

また、主題とは関係ないが、C#ArgumentException は、どの引数への例外かを表すコンストラクターの引数が定義されているため、メッセージの構築が楽だなと思った。Java の例外クラスは使いにくい気がする。

P78 コラム「ドメインサービスの基準」

その処理がドメインサービスかどうかを見極める際に筆者が重要視していることは、ドメインに基づくものかそうでないかという点です。 「ユーザーの重複」という考えがドメインに基づくものであれば、それを実現するサービスはドメインサービスです。 (中略) もちろん、可能な限り入出力はドメインサービスで取り扱わないようにするという方針には賛成です。

この方針は私も賛成。もしドメインサービスにてリポジトリの参照が必要な場合、リポジトリインターフェースのみをドメイン層に定義するようにしている。

・・・と書きつつ、リポジトリインターフェースが散在するのを避けるため、ドメイン層にすべて配置することが多い。

P87 コラム「リポジトリドメインオブジェクトを際立たせる」

前項とも被る話題ではあるが、リポジトリインターフェースをドメイン層に配置することが多い。本書ではリポジトリドメインの概念ではないとあり、私の考えと異なるが、これは私の中でドメインとアプリケーションの境界が曖昧であるため、と考えている。

顧客とドメインの話しをする際、次のような会話がある。

  • 受注伝票をもとに在庫を確認し、在庫があれば出荷の手続きに入る。
  • 受注伝票は会計のためファイルに閉じておく。

さて、受注伝票をファイルに閉じておくのはドメインの知識かどうか、というところが曖昧だった。この本を読んでからは、ドメインの知識を「集約」として洗い出したあと、それを保管しておくという業務手順については「リポジトリ」として、ドメイン層ではない場所に配置したほうがいいのかと思うようになった。

P127 コラム「煩わしさを減らすため」

単純に記述数が増えることを嫌う開発者は一定数います。 そうしたとき取れる手段は、彼らに降りかかる煩わしさの肩代わりをするものを用意することです。 具体的にはドメインオブジェクトを指定すると、その DTO となるクラスコードを生成するツールを作るとよいでしょう。

ドメイン駆動設計や、レイヤードアーキテクチャをやると、レイヤー間のデータ転送に DTO を用意することが多い。 上手く行っているプロジェクトは、Excel ファイルなどからソースコードを生成するツールを用意していることが多いので、確かにそのとおりだと思った。

P157 6.6.1.「サービスは状態をもたない」

Register メソッドは sendMail の値によって処理が分岐します。 (中略) 状態がもたらす複雑さは多くの開発者を混乱させるものです。 状態をもたせる以外の方法を考えてください。

ユーザー登録処理の中で登録時にメール送信をするという処理を例に、メールを送信する / しないをサービスクラスのインスタンス変数 sendMail で切り替えるという悪い例を挙げている。

メール送信も、業務によっていくつかのパターンがあると思う。

  1. テスト環境ではメールを送信しないが、本番環境ではメールを送信したい。
  2. ユーザーの設定によってメールを送信する / しないを切り替えたい。

今回はユーザー登録であるため、上記 1 が該当すると想定した場合の実装を考えてみる。(登録前にユーザーごとのメール送信する / しないの設定はないだろうという想定。)

Spring Framework の場合、設定クラス (Configuration) を DI してそちらからメールを送信するか / しないかを切り替えるための設定を読み出す方法が考えられる。 ただしこの場合、インスタンス変数がグローバル変数に移ったようにしか見えないため、完全な正解ではない気もする。

環境が用意できるのであれば、登録処理イベントを発行し、それを受信した「登録メール送信コマンド」がメール送信をするという「イベントソーシング」にしてもいいと思われる。 メール送信に時間がかかったり、失敗したときにユーザー登録処理自体を失敗としたくない場合などは、この方法が有効だと思う。

P199 8.4.1. 「ユーザ登録処理のユニットテスト

テスト用のリポジトリがデータ保管先としているフィールドを外部から操作できるようにすることは、きめ細かい検索を可能にし、テスト用モジュールのり弁性を向上させます。 フィールドを無闇に公開することは避けるべきですが、通常利用されるのは IUserRepository であるため Store プロパティを操作はできません。

これは目からウロコ。 確かに、C# の場合は LINQ で、Java の場合は Stream でコレクションを自由に操作できるため、テスト用リポジトリのフィールド等を公開しておけばテストの煩わしさがなくなる。

フィールドは private であるべき、という固定概念が崩れて、柔軟に考えられるようになった気がする。 あくまで外部からの操作はすべてインターフェース経由、ということを考えると、テスト用リポジトリだけではなく、本番用リポジトリテストのために フィールドを公開するのは有効だと思った。

P220 9.4 「複雑な生成処理をカプセル化しよう」

ポリモーフィズムの恩恵に与るためにファクトリを利用する以外に、単純に生成方法が複雑なインスタンスを構築する処理をまとめるためにファクトリを利用するのもよい習慣です。

あまり意見は無いんだけど、筆者の Web+DB での特集にて、インスタンス構築 と、インスタンス再構築 をメソッドで分けて実装されていたのを思い出した。

この使い分けはいいなーと思った記憶があるが、本書では特に構築と再構築を分けて記載しているわけではなかった。 プロジェクトや規模ごとに異なるとは思うが、上記の分け方は分かりやすいなと思っている。

P230 10.3.2 「ユニークキー制約との付き合い方」

ドメインのルールを守るための具体的な方法としてユニークキー制約に頼ることは得策と言えません。 ではユニークキー制約はまったく使えないものなのか、というとそれも間違いです。 (中略) ユニークキー制約はルールを守る主体ではなく、セーフティネットとして活用されるべき機能です。

これはその通り。 ユニークキー制約の他、外部キー制約やチェック制約などいくつかあるが、どの程度ドメイン駆動設計と併用されているのだろうと気になった。

P277 12.1.3 「内部データを隠蔽するために」

最初にもっとも単純な一般的なアプローチとして挙げられるのがルールによる防衛です。 (中略) もうひとつのアプローチは通知オブジェクトを使う方法です。

この通知オブジェクトというのは知らなかったが、エヴァンス本などにも書いてあるのだろうか。

ざっくり書くと、集約に通知メソッドを用意し、通知オブジェクトのインターフェースを経由して内部データを通知してもらう ものを指す。 通知オブジェクトのインターフェースはドメイン側で用意するため、通知する側にて内容を制限することもできるし、 通知される側も、通知オブジェクトのインターフェースを必要なものだけ実装すればいい。 もしドメイン側で項目が追加された場合、インターフェース実装クラスで追加実装が必要となり、コンパイルエラーとなる。

なかなかいい仕組みなのではないか? もう少し詳しく知りたいが、通知オブジェクトで検索してもあまり出てこないな・・・。

P320 14.1 「アーキテクチャの役割」

開発者は「一事が万事」といった言葉に目を向けず、いつかリファクタリングをすべきタイミングが訪れる、という夢を信じがちです。 (中略) もちろんそんなときは訪れません。

心当たりがありすぎて耳が痛い・・・。

P354 コラム「ユビキタス言語と日本語の問題」

オブジェクト名、メソッド名などを日本語で記述する試みは弊社でもいくつか例がある。 読みやすいという意見が多いが、エディターの補完機能の恩恵を受けることができないのは辛い。

例えば「店舗」を「te」と入力した時点で候補を出してくれるような、日本語とローマ字を突き合わせて補完候補を絞ってくれるプラグインなどがあればすごくいいんだけど。 結局「tempo」で実装するのが入力のしやすさと読みやすさのバランスがいい。仕事や会社のメンバーを考えると、無理に英語を使う必要はないかな・・・。

macOS Mojave (10.14.3) に Python3 の環境を構築する

お久しぶりです。

キカガクさんが公開している「MacPythonを使って『機械学習』を学ぶための環境構築」の手順で Python3 の環境を構築したところ、homebrew でインストールする際にエラーが発生したのでメモとして残しておきます。

play.kikagaku.co.jp

  • 1. Python3 のインストールにて失敗
  • 2. Python3 を再インストールする
  • 3. おまけ
  • まとめ
  • 参考サイト
続きを読む

Selenium + Internet Explorer 11 でファイルダウンロード

Selenium WebDriver で Internet Explorer 11 を操作し、ファイルダウンロードをしようとした時にハマったのでメモ。

問題

IE 11 でファイルをダウンロードした場合、状況によって 3 種類の画面が表示されます。

  1. ダウンロードダイアログ
  2. 通知バー
  3. ダウンロードの表示 ダイアログ

これらの画面がどういうもので、どういう状況で表示されるかについては、IE サポートチームのブログ記事をご覧ください。

ファイル ダウンロード時の通知バー、ダイアログ、ダウンロードの表示と追跡について – Japan IE Support Team Blog

Selenium + IEDriver でファイルをダウンロードした場合、上記画面が表示されると WebDriver を動かしているスレッドが停止してしまいます。

StackOverflow で調べると、その画面を操作するには java.awt.Robot を使いボタン操作で対応するという回答がありますが、そもそも処理が停止されているので Robot の処理が動きません。

対応

3 種類の画面のうち、いくつか試したところほぼ 1 と 2 が表示されたため、それらに対する対応方法です。

Robot の操作を別スレッドで処理し、ダウンロード画面を操作してメインスレッドを復帰させます。

以下、Kotlin でのサンプルコードです。

import org.openqa.selenium.ie.InternetExplorerDriver
import java.awt.Robot
import java.awt.event.KeyEvent
import java.nio.file.Files
import java.nio.file.Paths
import java.time.LocalDateTime
import kotlin.concurrent.thread

fun main(args: Array<String>) {

    // IEドライバー設定
    System.setProperty("webdriver.ie.driver", "C:\\Selenium\\InternetExplorer\\IEDriverServer.exe")

    val driver = InternetExplorerDriver()

    driver.get("http://example.com/files")
    driver.get("http://example.com/files/bigdata.csv")

    // 本ブログ記事のポイント
    // 別スレッドで、Alt + S ボタンを送信し、ファイルダウンロードする。
    thread {
        Thread.sleep(2000) // ダウンロード画面が表示されるのを待つ。
        val robot = Robot()
        robot.autoDelay = 250
        robot.keyPress(KeyEvent.VK_ALT)

        Thread.sleep(1000)
        robot.keyPress(KeyEvent.VK_S)
        robot.keyRelease(KeyEvent.VK_ALT)
        robot.keyRelease(KeyEvent.VK_S)
    }

    // driver#close() を呼び出すとブラウザが終了しファイルダウンロードもされないので、ファイルがダウンロードされるまで待機。
    // これを WebDriver 側で検知する方法を見つけられておらず、ファイル名で確認するしかなさそう。
    val downloadedFilePath = "C:\\Users\\rabitarochan\\Downloads\\bigdata.csv"
    val path = Paths.get(downloadedFilePath)
    while (!Files.exists(path)) {
        println("${LocalDateTime.now()} - ファイルがありません。")
        Thread.sleep(1000)
    }

    driver.close()

上記コードでは、ファイルダウンロード中にブラウザーが終了しないよう、ダウンロードファイルの作成をチェックしています。 IEDriver では、おそらくファイルダウンロード先を実行時に制御することはできないため、ユーザープロファイル以下の Downloads フォルダーにファイルが作成されるかどうかチェックしています。

まとめ

IE 縛りの Web ページ辛い。

参考サイト