IT本

2024/08/31

「システム開発・刷新のためのデータモデル大全」を読み直した感想~親子頻出アンチパターンは初心者モデラーに多い

システム開発・刷新のためのデータモデル大全」を読み直した。
今までの経験を思い出しながら読み直すと気づきが多かった。
気づきをラフなメモ。

【参考】
業務ロジックをデータモデリングはどこまで表現できるか?: プログラマの思索

【1】テーブルをリソース系とイベント系の2種類に分けてみた

データモデリングが重要と分かっていても、ER図を書いてみても実際の業務フローや画面UIがイメージしにくい。
データ構造から業務フローがイメージできないと、単にデータがそうなっているだけとしか分からない。

そこで、マスタであるリソース系はR、トランザクションであるイベント系にはEをテーブルに付けて区別して見るようにしてみた。
業務フローをイメージするために、イベント系のテーブルは、TA字型ER手法を使って、外部キーがある関係は、先行後続を付けて見るようにした。
この考え方は「システム開発・刷新のためのデータモデル大全」にないがあえてやってみた。

業務ロジックをデータモデリングはどこまで表現できるか?: プログラマの思索

(前略)
* resourceとresourceをつなぐ場合:対照表を生成する。対照表はeventである。
 (例)従業員と営業所
     従業員-営業所の対照表を作成し、リレーションシップを保全する。
* resourceとeventをつなぐ場合:event側に参照キーを持たせる。
 (例)顧客と注文
     注文entityに顧客コードを持たせる。
* eventとeventをつなぐ場合
** 「1:1」「1:m」:時系列の遅い方に持たせる。
 (例)受注と請求(一つの受注に対し請求は一つ)
     請求に受注番号を持たせる。
** 「m:1」「m:m」:対応表を生成する。
 (例)受注と請求(複数の受注に対し請求は一つ)
     受注-請求の対応表を生成し、リレーションシップを保全する。
(後略)

その結果、イベントに先行後続が順序付けられて、業務フローが見えてきて、付随するリソース系のイメージも湧いてきた。
そこから色々感じたこと、気になったことをメモしておく。

【2】リソース系テーブルのフィーチャオプションモデル

システム開発・刷新のためのデータモデル大全」では、製造業のモデルだけでなく、サービスやその他のモデルでもリソース系テーブルのフィーチャオプションモデルがよく出てくる。
なぜ頻出されるのか?

たとえば、製品や商品の属性をテーブルで保持しようとすると、横持ちでカラムが多くなる。
サイズ、色、重量などいろんな属性があるし、新製品によってさらに属性も新規追加されやすい。
横持ちのテーブルでは品種が多くなると破綻する。
そこで、品種という属性群を別テーブルで保持し、縦持ちでデータを持たせて、新規追加できるようにする。
つまり、製品や商品の属性データを横持ちから縦持ちにもたせて、汎用化している。
その分、マスタテーブル設計は複雑になるが、理解さえできれば応用が効きやすい。

フィーチャオプションはマスタ管理を整理するためのテクニックと思う。

【3】強属性のキーはサロゲートキーの代わり

複合主キーのマスタは、サロゲートキーにすると扱いやすくなる。
しかし、関数従属性がサロゲートキーのために分かりにくくなる。
そこで、サロゲートキーに置き換えられた複合主キーに当たるカラムを一度追加更新されたら更新できない制約をかける。
システム開発・刷新のためのデータモデル大全」では、この制約を強属性と呼んでいた。
複雑な商品マスタをサロゲートキーで主キーにした時、品種区分とFO項番が主キーのようになるが、「システム開発・刷新のためのデータモデル大全」の例では、品種区分を強属性としている。

強属性を使うことでマスタテーブルの関数従属性を表し、データの不整合が出ない仕組みにしている。


【4】親子頻出アンチパターン

データモデリング初心者はテーブル同士を関連付けようとする時、主キーの親子関係だけで表現しようとする。
特にトランザクション系のテーブルで多い。
注文と注文明細みたいに。
たぶんそういう関係付けの方がイメージしやすいからだろう。
そういうアンチパターンは、親子頻出アンチパターンと言われている。

しかし、本来は外部キーを使って、トランザクション系のテーブルに先行後続を関連付けるべきだ。
その場合、先行後続では多重度が異なる。

先行後続が1対多ならば、先行イベントテーブルの主キーが後続イベントテーブルの外部キーとして設定される。
一方、先行後続が多対1や多対多ならば、先行イベントテーブルと後続イベントテーブルの間に、連関テーブルが入り込んで2つのテーブルを1対多で関連付ける。
たとえば、出荷したデータをまとめて一括請求する場合などがあげられるだろう。

データモデルではイベント系テーブルを抽出した後、多重度から先行後続を読み取り、そこから業務フローを組み立てると一連の流れが見えてくると思う。

【5】時限NULL、永続NULLデータの考え方

イベント系テーブルでは、カラムの初期値はNULLだが、後続の業務が実行されてデータが更新されるタイミングで、NULLから値がセットされる。
システム開発・刷新のためのデータモデル大全」では、このようなデータを時限NULLデータと呼んでいる。
たとえば、後続イベントテーブルにある先行イベントテーブルの主キーを外部キーとして張っている場合がそうだろう。

データモデルではNULL値はできるだけ避けるべきだが、一時的にNULLの状態であって、データ更新のタイミングで値が更新されるならそれで良しという考え方になる。
システム開発・刷新のためのデータモデル大全」では、発注と入荷のデータモデルで入荷コードが時限NULLとして使われる例があって分かりやすい。

一方、マスタテーブルでは一つのマスタに属性を増やしていくと、カラムの初期値がNULLのまま永遠にセットされる場合がある。
このような例が永続NULLデータになる。
システム開発・刷新のためのデータモデル大全」では、永続NULLデータが存在する場合、サブタイプに分割すると良い。
つまり、テーブルの継承関係を使って、親テーブルのマスタに共通するカラムをまとめ、子テーブルのマスタにそれぞれの属性を集めたデータをまとめる。
顧客や取引先、仕入先などをまとめたテーブルを作りたい場合が相当するだろう。

【6】2次キー(2次識別子)の使い道

システム開発・刷新のためのデータモデル大全」では、2次キーが有効に使われるデータモデリングの例が多い。

たとえば、在庫推移監視モデルでは、受払テーブルが受払予定テーブルと受払履歴テーブルをサブタイプに持たせるが、それぞれの主キーは異なるので、そのままでは継承関係をデータモデルで表現できない。
そこで、受払・受払予定、受払履歴テーブルに2次キーを持たせて、継承関係を表現する。
2次キーはいわゆるAlternative Keyであり、一意なキーだから、検索時にも使える。

他にも、売上履歴に出荷明細、回収明細、一般取引明細の各テーブルを関連付けて、売上の履歴を一元的に管理していつでも検索できるようにするには、それぞれの主キーは異なるので、2次キーを持たせる。

一般に2次キーは、JANコードやマイナンバーのようにマスタテーブルでよく出るが、トランザクションテーブルに使うと効果的に扱える場合が割とあるように思える。

【7】負荷計画のモデルは2種類ある

システム開発・刷新のためのデータモデル大全」では、業務知識を埋め込んだデータモデルがふんだんに盛り込まれているので、データモデルを読み解いていくと、この関数従属性にはこういう業務ルールを埋め込んでいたのか、と気づく時が多い。
宝物探しの感覚に似ている。

システム開発・刷新のためのデータモデル大全」にあるデータモデルで興味深かった例は、負荷計画のモデルだ。
製造業では、工場の機械がリソース制約になり、工場の稼働率を決めて最終的には原価につながる。
そこで、設備の制約に関するスケジューリング決定について、TOCのアイデアを入れて、工程の日程を決める。

負荷計画を立てるときに、リソースの制約がスケジューリングに最も関わるので、制約になるリソースは何があるか、という問いに置き換えられる。
制約になるリソースは、製造業の工場なら設備だが、病院の看護スケジュールなら、専門技術を持つ人員になる。
ソフトウェア開発のスケジュールでも、インフラ環境の設備もあるだろうが、専門技術を持つ開発者が最も大きな制約になるだろう。
つまり、要員シフト管理では、専門技術を持つ人員が制約になる。
制約となるリソースが業態やビジネスによって大きく異なる点が面白い。

また、負荷計画では受注生産の工場、病院の看護師なら、受注済みの製品または予約済みの患者という需要に対し、「需要を設備の稼働を確保する」考え方になる。
一方、航空機運輸業の予約搭乗管理では、飛行機を既に持っており、その飛行機の座席をいかに予約で埋めていくか、になる。
つまり、「設備の稼働ありきで需要を確保する」ことになる。
他にも、新幹線や特急の予約もこの考え方になるだろう。

では、データモデルにはどのような違いが出てくるのか。
受注生産の工場、病院の看護師の負荷計画では、予定→製造指示のようにイベントテーブルは1対多の関係になる。
「需要を設備の稼働を確保する」データモデルでは、需要という予定をいかに設備で捌くか、という考え方になるので、予定→負荷を割り当てた計画スケジュールのように、先行後続のイベントテーブルが1対多になる場合が多い。

一方、飛行機のフライト管理では、フライト日程→フライト日程明細--予約搭乗明細→予約搭乗というイベント系テーブルで関連付けたデータモデルになっている。
つまり、先行後続のイベントテーブルが多対多の関係になっている
「フライト日程明細--予約搭乗明細」の関係は、それぞれの主キーが異なるのでそのままでは関連付けられないが、フライト日程明細テーブルの主キーを2次キーとして予約搭乗明細テーブルに持たせて、関連付けるモデルにしている。
これにより、フライト日程を決めたら、フライト日程の飛行機の座席に予約を割り当てて管理するという業務フローが成り立つことになる。

さらに、フライト日程明細テーブルの主キーを予約搭乗明細テーブルの2次キーに設定しているので、2次キーはNULLも設定できる。
NULLが設定される例として、座席指定できていないデータ、キャンセル待ちや搭乗者にカウントされない乳幼児があげられていて、そこまで業務ルールとして埋め込んでいるのか、と気付いて面白かった。

他のデータモデルでも、関数従属性に業務ルールが巧妙に埋め込まれているので、この辺りを読み解くと面白いと思う。

| | コメント (0)

2024/05/06

「システムアーキテクチャ構築の原理」の感想part2~非機能要件がシステムのアーキテクチャに影響を与える観点をプロセス化する

システムアーキテクチャ構築の原理」を読んでる。
平鍋さんの記事「『ソフトウェアシステムアーキテクチャ構築の原理(第2版)』読んだ #Java - Qiita」を読み直して、理解が深まった。
平鍋さんの記事に触発されたので、理解できたことをラフなメモ。
間違っていたら後で直す。

【参考】
『ソフトウェアシステムアーキテクチャ構築の原理(第2版)』読んだ #Java - Qiita

「システムアーキテクチャ構築の原理」の感想: プログラマの思索

【1】「システムアーキテクチャ構築の原理」を読んでいて分かりにくかったことは、ビュー、ビューポイント、パースペクティブという概念が出てきて混乱したこと。
これらの言葉は何を表しているのか、具体的に理解できていなかった。

平鍋さんの記事「『ソフトウェアシステムアーキテクチャ構築の原理(第2版)』読んだ #Java - Qiita」では、概念モデルでまとめてくれているので理解しやすかった。

【2】図4-3.コンテクストにおけるパースペクティブが「システムアーキテクチャ構築の原理」のメッセージを全て表している。
平鍋さんの解説が分かりやすい。

43

(引用抜粋 開始)
「非機能要件がシステムのアーキテクチャに影響を与える」という観点を本書は、この言説を徹底的に解説したもの。

非機能要件に限らず、横断的な視点を「パースペクティブ」として捉えている

実際にアーキテクチャを記述しようとすると、1つの文書ではとっても複雑で巨大な説明になる。「ステークホルダー」の「関心事」毎に分割するために、「ビュー」と「ビューポイント」を導入する

「パースペクティブ」は、従来の言葉で近いものとして「非機能要求」「横断的関心事」がある。本書ではこの「ビューポイント」と「パースペクティブ」のカタログを作っています。
(引用抜粋 開始)

【3】図15-1.ビュー間の関係では、ビューを開発や運用の観点で分解している。
この図は、システム開発とシステム保守で分割すれば理解しやすい。
今ならDevOpsだから、開発も運用も一体化しているだろう。

151

【4】図7-3.アーキテクチャ定義のプロセスは、「システムアーキテクチャ構築の原理」が提唱している、アーキテクチャを定義し評価するプロセス。
アーキテクチャ設計の中で、特に非機能要件を含めた横断的関心事をいかにアーキテクチャに盛り込むのか、を考えた一連のプロセスになる。
プロセスの流れは、アーキテクチャ要素や横断的関心事を段階的詳細化して組み立てたあとにアーキテクチャを評価するので、違和感はない。

73

【5】「システムアーキテクチャ構築の原理」では上記3つの図が本書のメッセージになると思う。
本書のやり方を各システム、各案件にテーラリングして設計、実装する必要があるから、本書は、アーキテクチャ設計のメタ概念、メタプロセスの解説書みたいな感触を持っている。

【6】「システムアーキテクチャ構築の原理」の副題「ITアーキテクトが持つべき3つの思考」が指す「3つ」とは、「ステークホルダー」「ビューポイント」「パースペクティブ」と最初に書かれている。

その意図は、ステークホルダーの横断的関心事、特に非機能要求をユーザ観点のビューポイント、システム観点のパースペクティブで分解して組み立てて、トレードオフを考慮したアーキテクチャを設計すること、を意味していると考える。

他にも気づいた他内容があれば書いていく。

| | コメント (0)

「システムアーキテクチャ構築の原理」の感想

システムアーキテクチャ構築の原理」を読む機会があったので感想をラフなメモ書き。

【参考】
「システムアーキテクチャ構築の原理」の感想part2~非機能要件がシステムのアーキテクチャに影響を与える観点をプロセス化する: プログラマの思索

『ソフトウェアシステムアーキテクチャ構築の原理(第2版)』読んだ #Java - Qiita

アーキテクチャ構築の原理 第2版を読んだ - 勘と経験と読経

【0】「システムアーキテクチャ構築の原理」は最新版の第2版もある。
僕は確か、デブサミ2010の時に会場で購入した記憶があり、第1版を持っている。
その時から興味のある部分だけかいつまんで読んでいたので、全部を通して読んでいなかったので、輪読するのは良かった。

システムアーキテクチャ構築の原理」を読んで興味を持った部分はいくつかある。

【1】1つ目は、2008年の初版でありながら、マイクロサービスやサービス志向のアーキテクチャ設計を目指していること。
機能的ビュー、情報ビュー、並行性ビューなどのソフトウェア構造のアーキテクチャ設計の観点は、業務システム設計と微妙に違うな、と感じていたが、実際はクラウドベースのマイクロサービス設計を目指しているのだろう。
実際、並行性ビューでは、昔のバッチ処理設計よりもイベント駆動の並列性アーキテクチャに力点をおいている。
たとえば、REST APIやAdapter・Facadeパターンのようなアーキテクチャ設計を念頭に置いて実装しようとしている。

そう考えると、マイクロサービス設計における新たな設計思想はまだ含まれておらず、荒削りな内容を感じるが、文章の背後にある著者の思い、こういうことを言いたいのではないか、を推測しながら読むと理解できるのでは、と感じる。

【2】2つ目は、ATAMという非機能要件の設計技法を解説してくれている点だ。

データベースコンサルタントのノウハウちょい見せ アーキテクチャをレビューする方法(ATAM)

ATAMはシナリオベースで非機能要件を評価する設計技法。
僕の理解では、システムのアーキテクチャの特に非機能要件を品質特性ごとに分類し詳細化して、それをシナリオに落とす。
そのシナリオを優先度付けして、シナリオベースにアーキテクチャを評価して整合性を取ったり、システム設計を明確化する。

利点は、非機能要件をアーキテクチャとして評価する技法として、シナリオベースを用いているので、アジャイル開発をやっている人には取り組みやすいと思う。
デメリットは、CMMIを作ったSEIがATAMを提唱しているので、重たいプロセスになりがちで、テーラリングが必須であり、プロマネによってばらつきが出やすいこと。

ATAMに関する日本語書籍は「システムアーキテクチャ構築の原理」と「間違いだらけのソフトウェア・アーキテクチャ―非機能要件の開発と評価 (Software Design plus)ぐらいしかないので、貴重だと思う。

データベースコンサルタントのノウハウちょい見せ 書評「間違いだらけのソフトウェア・アーキテクチャ―非機能要件の開発と評価」

【3】3つ目は、2009年頃の書籍なので、UMLをベースとした設計を念頭に置いていること。
機能的ビューではコンポーネント図、情報的ビューではER図やDFDや概念クラス図、並列性ビューではステートマシン図を使うと良いと説明されている。
このあたりの意見は僕も同意するが、注意点はいくつかあると思う。

コンポーネント図は「アジャイルソフトウェア開発の奥義」でも重要視されている。
機能を1つのコンポーネントとみなし、コンポーネント間のインターフェイスを重視する設計は重要だと思う。
一方、コンポーネント図だけでは表現しきれない仕様や要件があり、不十分と感じる。

その点は「システムアーキテクチャ構築の原理」でも、メッセージングのやり取りは記述できないので補足説明や別の図が必要と書かれている。

並列性ビューに出てくるステートマシン図は、より詳しく書いていくと結局、詳細設計レベルになってしまう。
アーキテクチャ設計ではRFPに出てくる要件レベルまでで留めたいので、粒度を揃えるのが難しい場合が多いだろう。

【4】「システムアーキテクチャ構築の原理」を読んでいて思い出すのは、2000年代にソフトウェア・プロダクトラインが流行した頃に読んだ「 実践ソフトウェアアーキテクチャ」に出てくる一節だ。

そのボタンを押したら何が起きるのですか?~アーキテクチャは利害関係者のコミュニケーション手段: プログラマの思索

実践ソフトウェアアーキテクチャの解説記事: プログラマの思索

実践ソフトウェアアーキテクチャ」では、政府のある委員会の2日間に渡る討議の中で、新人のアーキテクトが、政府が作ろうとしているシステムのアーキテクチャをコンサル独自の記法でモデルを描いて委員会の参加者に説明していたところ、委員会の参加者たちは何が問題なのかに初めて気づいた。
そして、委員会の参加者たちは、新人のアーキテクトの説明を途中で止めさせて、システムのアーキテクチャの問題点を活発に議論し始めたという一節だ。
これが意味しているのは、アーキテクトの役割とは、システムのアーキテクチャ設計に関する最終責任者ではなく、各利害関係者の間でシステム要件のトレードオフを考慮させる調停者であることだ。

つまり、アーキテクトの役割はシステム要件を決めることではなく、システム要件のトレードオフを色んなステークホルダーに説明して理解させて、最終的な意思決定を引き出す調停者として振る舞うべきだ、ということ。
この一節は僕が一番好きなところでもある。

システムアーキテクチャ構築の原理」では、アーキテクトがすべてのパースペクティブやビューポイントを理解している全能の神のように思えてしまうが、実際はそうではなく、アカウンタビリティを持つ調停者という観点で捉えると理解しやすいと考える。

気づいた点はまた書き留めていく。

| | コメント (0)

2023/12/10

「GitLabに学ぶ 世界最先端のリモート組織のつくりかた」の感想

GitLabに学ぶ 世界最先端のリモート組織のつくりかた ドキュメントの活用でオフィスなしでも最大の成果を出すグローバル企業のしくみを読んだ。

【0】リモートワーク主体の組織運営をどうやってやるか、PDCAで整理した本と思う。
とは言っても、リモートワーク普及に奇策はない。

【1】Planでは、ガイドラインを定めて形式知化する。
リモート責任者など組織体制も整備する。
経営層が率先してリモートで働く。
利用するツールは絞り込む。

他にもいくつか施策はあるが、割りと形式知化を重視している点が印象に残った。
リモートだからこそ、対面でのやり取りがないので、どうしてもローコンテキストな対話にならざるを得ないだろうから。

コミュニケーションルールも定める。
非公開情報ではSAFEアプローチを取る。
Sensitiveなのか、Accurateなのか、Financialなのか、Effectなのか、の判断基準を定めて、情報を公開しても良いのか判断する。

【2】Doでは、従業員の動機づけ要因、衛生要因を整備する。
リモートに合った組織文化が根付くように実行する。
心理的安全性を重視する。
人材戦略、つまり従業員の動機づけ要因では、ダイバーシティ、インクルージョン、ビロンギングを重視する。

ダイバーシティは、人種や性別、年齢、宗教、性的指向などの多様性を認めること。
インクルージョンは、マイノリティもマジョリティもすべての従業員が活躍できる状態を目指すこと。
ビロンギングは、自分の居場所はここである、という感覚。
帰属意識みたいなものかな。
一昔前の日本の会社の愛社精神みたいなもの。
今風ならエンゲージメントかな。

面白い点は、ビロンギングを重視していること。
従業員の流動性が高くても、帰属意識を重視しているのはなぜか。
たぶん、マズローの欲求5段解説で考えれば、帰属欲求が満たさなければ、承認欲求や自己実現を満たす欲求に達しないからだろう。

他にも、イテレーション、透明性も重視している。
この辺りはアジャイル開発の文化に近いので理解しやすい。

コンディショニングを実現する章は衛生要因の話だろう。
長期休暇制度、人間関係の構築、運動の推奨。

【3】CheckとActoinでは、KPIを用いた評価制度を作り、イテレーションごとにフィードバックを回していく。

SMARTな目標を定めて成果を評価する。
GitLabで活躍できる能力や意欲があるのに、マネジメントの問題で活かしきれない状況を避けるために支援する。
マネージャはメンバーを支援する。

優れたマネージャのコンピテンシーは事前に把握しておく。
感情的知性(EQ)、コーチング、衝突の解決、フィードバック文化の体現、高業績チームの構築。

Actionでは、メンバーに精神的成長と技術的成長を促す。
技術的成長を促すには、現状のスキルレベルと目指すスキルレベルの可視化が不可欠。
しかし、日本企業はスキルマップが画一的だったりそもそもなかったり、メンバーのスキル保有を把握していない。

能力開発のプロセスでは、コルブの経験学習モデルが有効。
具体的経験→内省的観察→抽象的概念化→積極的実践のサイクルを回して、能力を高めていく。
日本と海外の差は、抽象的概念化と積極的実践の部分だろう。

抽象的概念化では、普通の業務では既に他の人や過去の人が既に実践しているから、ノウハウや問題解決の手順は既に知られている。
しかし日本ではわりと形式知化されていないので、一人で暗中模索して試行錯誤しながら解決策を導く手間がかかる。
海外では形式知化されたマニュアルや書籍、トレーニングが充実しており、それらを通じて先人が得た整理された知識まで早期に到達することができる。

積極的実践では、せっかく研修したのに、研修に対して意味がないと感じたりネガティブな印象を持ったりする。
座学の場合は特にそうだろう。
だから、研修を実務に適用し、研修転移を進めるために、マネージャや周囲が定期的にコミットメントしたりフィードバックするのが大事になる。
GitLabでは、個人開発計画を作成し、メンバーのキャリア開発について議論しているという。

【4】そんな話を読むと、GitLabではリモートワークを単に活用しているだけでなく、包括的にメンバーの意識付けからスキルアップまで組織的に考えていることが分かる。
おそらく長年の試行錯誤を経て、3000ページにのぼるGitLabのガイドラインにまとめられたのだろう。

また、この本では、既に知られているビジネスやマネジメントのフレームワークがふんだんに使われていて、情報が整理されて理解しやすいと感じた。


| | コメント (0)

『世界一流エンジニアの思考法』が学べる環境を手に入れてかつ継続する方法の感想 #devboost

デブキャリで牛尾さんの講演を聞いた。
世界一流エンジニアの思考法」を出版されている。

Developers CAREER Boost 2023 (2023.12.09)

デブキャリでこっそりシェアする三流エンジニアが『世界一流エンジニアの思考法』が学べる環境を手に入れてかつ継続する方法

話が上手いし面白い。
牛尾さんには15年以上前にXP祭り関西2006でXP寸劇にも参加して頂いたこともあり、あの頃の雰囲気を思い出した。

Subject: [ruby:1293] XP祭り関西2 006 in ワッハ上方

XP祭り関西2006 in ワッハ上方 (プログラミング C# - 翔ソフトウェア (Sho's))

【告知】XP祭り関西2006 in ワッハ上方: プログラマの思索

牛尾さんの講演の気づきは3つ。

1つ目は、常日頃から職歴を更新して、アピールできるレベルに随時ブラッシュアップすること。
牛尾さんはアジャイルのエバンジェリストでは超一流だったが、自身曰く、プログラマのスキルは低かった。
だから、マイクロソフトでプログラマになるべく、Githubに書いてアップしたり、エンジニアが来日したらAttendeしたり、色々アピールした、と。
そのためにも、職歴に、第三のスキルを常に磨いて記載するようにした、とのこと。
職歴は、LinkedInのプロフィールみたいなもの。
私はこういう人です、こういうスキルがあります、こういう職歴を積んできました、とアピールできるもの。
自分がより良い職業や職場に行きたいなら、そういうアピールできるものが必要。

一方、会社は「こういう人が欲しい」というジョブディスクリプションを出す。
それを見て、そのジョブディスクリプションに応募する。
その時に、会社が提示したジョブディスクリプションに対し、2つ上のレベルを目指すようにする。
そうすれば他人の目を引くことができるから。

牛尾さんほどの優れたエバンジェリストのレベルであっても、地道に努力されているんだなと思った。

2つ目は、何をやらないか、が大事なこと。
Be Lazyと言っていた。

Xユーザーのakipiiさん: 「Be Lazy。何をやらないか。物量よりもインパクトが大事。日本人は勤勉重視、努力重視なので価値観が正反対だよね。染み付いた価値観を捨てるのは難しい。 #devboost」 / X

どうしても日本人は「努力」が好きなので、全部をやろうとしてしまう。
捨てるのが難しい。

物量よりもインパクト重視。
たくさんできるよりも、何か一つ目立つものが成果として出れば十分。
そういう発想が大事。

3つ目は、「チャンスの時に受けないと次に進まない。受けましょう。」

Xユーザーのakipiiさん: 「牛尾さんが最後に伝えたこと。チャンスの時に受けないと次に進まない。受けましょう。つまり、挑戦しましょう。実力がなくても英語力がなくても関係ないと。 #devboost」 / X

今、牛尾さんはマイクロソフトでAzureファンクションのプログラマをされていると聞いた。
そのきっかけは、米国チームから、新卒に教えるのが得意なエンジニアで採用されたのがきっかけ。
そこからチャンスを掴み、今プログラマとしてバリバリ働かれている。
気後れせずに、チャンスをつかめ、というメッセージとして受け取った。

牛尾さんがすごいなと思うのは、40代を過ぎてから、英語を習得し、エバンジェリストからプログラマへキャリアを転換されたこと。
今までの実績や経験をすべてアンラーニングして一からやり直されたのはすごいと思う。
普通は、今までのキャリアやスキルをベースに深めていくのが普通であって、最初からやり直すのは大変。

本当に自分がやりたいことは何なのか、を深く考えて実行されたのだろうと思う。

| | コメント (0)

2023/11/12

「ソフトウェアアーキテクチャ・ハードパーツ」の情報リンク~マイクロサービスの設計技法の課題は何なのか

ソフトウェアアーキテクチャ・ハードパーツ ―分散アーキテクチャのためのトレードオフ分析を読んでいて、まだ中身を理解できていない。
ネット上の感想記事を自分用にリンクしておく。

【参考】
『ソフトウェアアーキテクチャ・ハードパーツ』 - Don't Repeat Yourself

(引用開始)
また、最近話題になっていた『ソフトウェアアーキテクチャの基礎』(以降、「基礎」)を執筆した著者陣が書いたもう一冊の本でもあります。
「基礎」はアーキテクトとしての姿勢や、それぞれのアーキテクチャの簡単な概要が中心でしたが、この本はより実践に近く方法論寄りです。「基礎」が「What」を扱うとすれば、本書は「How」を扱うといった関係性でしょうか。
(引用終了)

(引用開始)
現代ではデータをどのように設計し、分割しつつ整合性を保って保管しておくかといった一連の流れの重要度が増しています。この問題についても本書は拾い上げるよう努力しています。[*1]
従来のアーキテクチャの議論では、マイクロサービスはどう分割するかとか、コードの関心事がどうこうとかそういったアプリケーションに限った範囲が中心だったように私は思っています。が、そうではなくデータをどう分割、配置、保管していくかといった問題についても議論に含めるようにしています。
(引用終了)

『ソフトウェアアーキテクチャ・ハードパーツ』完全に理解した - Mirai Translate TECH BLOG

(引用開始)
一言で言うと
「マイクロサービスの大きさと通信方式をどう決定するか」について書かれた書籍です。
(引用終了)

ソフトウェアアーキテクチャ・ハードパーツ - Forkwell Library #12に参加してきた - 天の月

(引用開始)
レガシーで大規模なモノリシックシステムをどう解決していくか?というのを物語形式で紹介してくれているということです。

ソフトウェアの中でも土台となるような部分の決定は「モノリシックなシステムをどう分解していくか?」で前半部分に表現され、「ソフトウェアアーキテクチャをどう決めるか?」は分散システムで直面する難しい問題をどのように決定するか?で後半部分に表現されているということです。

もう少し具体的に言うと、前半部分は戦術的フォークとコンポーネントベース分解を中心に登場人物がトレードオフ分析を行なっている様が描かれており、後半部分は、粒度分解要因と粒度統合要因のバランスによって決定されるという前提をもとに、分解をどこまでするかが具体的に描かれているそうです。
(引用終了)

「ソフトウェアアーキテクチャの基礎」読書感想

【1】「マイクロサービスの大きさと通信方式をどう決定するか」が根本テーマであるとすれば、マイクロサービスの設計上の課題や留意点がテーマになる。

2020年代の現在では、マイクロサービスの実装はAWSなどのクラウド基盤が前提条件だろう。
AWSならEC2ではなく、CloudFormationを使って各種サービスを組み合わせて一体化したシステム設計をするのではないか。
一方、オンプレ環境のシステムでは、弾力的なスケーラビリティ向上、つまりスケールアップやスケールアウトを動的に変更するのは非常に難しい。
逐一サーバースペックをサイジングしてどれだけのスペックを持つべきか見積もりして導入するまでに非常に手間がかかる。

では、マイクロサービスの落とし穴はどこにあるのか?
マイクロサービスの利点や美味しいメリットを得るにはどんな留意点があるのか?

モノリシックな基幹系システムやモノリシックな巨大なシステムをビジネス上の観点でサービスごとに分割して、分散サービス化した時、それぞれのサービスの粒度は小さくなるので運用保守しやすくなる点もあるだろう。
昨今のDevOpsの観点では、小さな開発チームが設計や開発から運用までを担当する流れなので、チームが担当するシステムのサイズは小さい方が実現しやすい。

一方で、複数のサービスを連携して初めて、顧客が満足する1つのユースケースが成り立つような場合、途中でサービスが停止すると成り立たなくなる。
分散サービスのアイデアは20年以上前のCORBAやEJBからずっと言われていては失敗してきたが、クラウド基盤でようやく実現可能な設計手法になった面もあると思う。
僕はまだAWSやクラウド基盤のことは無知なので、今までのオンプレ環境で構築するシステム設計とは違った観点がマイクロサービスの設計にはあるのだろうと思う。

理解できた内容はBlogに残しておこうと思う。


| | コメント (0)

2023/10/21

概念モデリングや設計原則は進化しているのか

最近、概念モデリングや設計原則の勉強会に参加して色々気づきがあった。
ラフなメモ書き。

【1】「実践UML第3版」を勉強会で読み始めた。
僕は「実践UML第1版」を購入して読んでいた。
思い出せば20年前になるのか。
そこから第2版も買ったし、最近第3版も買ってみた。
中身は変わってきているが、版を重ねるごとにオブジェクト指向設計の内容が洗練されて、RUPという開発プロセスに準じるように設計から実装、移行まで一気通貫する。

2020年代の現在、「実践UML」を再度読んで気づきがいくつかある。

【2】1つ目は、RUPはもう不要と思う。
スパイラル開発プロセスはWF型開発からの脱却という観点で重要だったが、Scrumを中心としたアジャイル開発が全盛の時代だから、わざわざテーラリングが必要な重厚長大なRUPを利用するメリットはないと思う。

【3】2つ目は、モデリングに必要なUMLのダイアグラムの力点が変わっていること。
「実践UML第1版」では、以前は協調図(コラボレーション図)、今のコミュニケーション図がオブジェクト指向設計で重要です、と主張していた。
理由は、コラボレーション図を描くことで、機能をどのクラスに割り当てるべきか、凝集度や結合度、生成などの観点で検討する時に有用だから。
オブジェクトからたくさんの指示が出ていれば責務が多すぎるね、と気づきやすいから、と。
当時の自分はすごく納得した。

実践UML第2版実践UML第3版では、クラス図やシーケンス図で説明する場面が多い。
コラボレーション図の話はなくなっていた。
たぶん、UMLの中でも重要度が下がったためだろう。

しかし、機能の割り当ての考え方は普遍的と思う。

【4】3つ目は、GRASPパターンは「情報エキスパート」パターンが一番大事ということ。
このパターンが「実践UML」の重要ポイント。

機能や責務はどのクラスに割り当てるべきか?
責務の遂行に必要な情報を持っているクラス、すなわち情報エキスパートに責務を割り当てるべきだ。

つまり、責務の遂行に必要な情報を自身のクラスの属性、関連先のクラスから取得した情報を自身のクラスで持ってること。
そして、処理を実行する時に、他クラスへメッセージを投げ出せること。

コミュニケーション図なら、情報エキスパートとなるクラスからメッセージという矢印が出ているだろう。
シーケンス図なら、情報エキスパートとなるクラスからメッセージが出て、他のクラスに処理が委譲されて、階段状の図になっているだろう。

その他のパターンも8つくらいあげられているが、そこまで重要ではないように思う。
生成、疎結合、高凝集度、多相性、コントローラは読めば分かる。
バリエーション防護壁はFacadeやAdapterみたいなもの。
純粋加工物、あるいは人工品は、機能の関連だけで構成するのではなく、ソフトウェアのプログラムの都合上、論理的なオブジェクトをワンクッション挟むようなもの。

【5】4つ目は、概念モデリングとデータモデリングは似ているようでやはり異なることだ。

「実践UML」では、概念モデリングでの注意点がいくつかある。

【6】属性とクラスは区別する。
一般に、ある概念をクラスの属性にするか、クラスで独立させるか、識別は間違いやすい。
「実践UML」の指針では、ある概念Xが現実世界では数値でもテキストでもなければ、Xは概念クラスであり、クラスの属性ではない、と言い切っている。

これは重要と思う。
初心者だった頃、どれをクラスにすべきか迷ってしまう時が多かった。
迷って、概念をクラスの属性にしてしまいがちな時が多い。

例えば、Destination、AirportはFlightに含めるべきか。
それぞれクラスとして独立させて、関連で結ぶべき。

実際は、1つの概念はクラスのロール名としていろんな別名として現れる。
例えば、企業クラスは顧客だったり仕入先だったり、取引先だったり、もしかしたらグループ内企業だったりする。
つまり、企業クラスはいろんなロール名として呼ばれる時がある。

【7】属性にはプリミティブ型を使わず、データ型を使う。
たとえば、属性にはDate型、Number型、String型を使う。
あるいは、Address、Color、PhoneNumber、UPC、SKU、ZIP、列挙型を使う。
区分値は列挙型を使う場合が多いかな。

例えば、会員クラスの会員名、会員IDみたいなものだろう。
でも、同じ会員名であっても、実際の人物は異なるケースもある。
だから、ValueObjectを別で用意して利用する場合もあるだろう。
ドメイン駆動設計なら、ValueObjectをかなり頻繁に使うだろうと思う。

【8】概念クラスの関連付けに外部キーや複合キーを書かない。
概念クラスの関連付けは、属性ではなくクラス間の関連で書く。

この部分がデータモデリングと異なるし、引っかかるところと思う。
一般にオブジェクトには唯一の主キーとなるサロゲートキーが割り当てられる場合が多いだろう。
すると、データモデリングで考えた時、外部キーや複合キーがなく、全てサロゲートキーなので、クラス間の制約条件が分かりにくくなる。
RailsのActiveRecordがそういう例になるだろう。
データモデリングなら、サロゲートキーを使っている場合、外部キーのペアが複合キーの役割を持つので強属性になるような制約をもたせるだろう。

では、概念モデルから実装モデルへ詳細化されていくうちに、関連はどう変わっていくのか?
概念モデルの関連から相手先のロール名が割り当てられて、最終的には関連はどこかのメソッドとして実装されて、そのメソッド内でロール名は変数名と同一視されて利用されるだろうと思う。

【9】概念クラス図でも、関連クラスのように、複合キーを使った事例はある。
しかし、関連クラスを多用すると、クラス図から読み取りにくくなる。
一方、データモデリングの観点では、関連クラスを複合キーを持つクラスと置き換えれば、明確な意味を読み取りやすくなる。

【10】概念モデリングでは、クラス間の関連と多重度でクラス間の制約条件を読み取る場合が多いように思う。
慣れるまで大変だけど。

【11】そんなことを考えてみると、概念モデリングや設計原則は以前よりも変化していないように思う。
UMLが流行していた2000年代からモデリング技法は進化しているのだろうか?

オブジェクト指向設計とデータモデリングの違いは他にも整理してみる。

| | コメント (0)

2023/09/18

ビジネス書の名著はどれ?

山口周さんがお勧めのビジネス名著をリストアップされていたのでメモ。

自分が読んだ経験のある本があったので、共感できた。

経済学をベースにした戦略論、組織論は好き。
人間の意志を超えた次元で、自然法則のように戦略も組織も縛られる。
そういう原則を抑えていれば、悪循環に陥る状態を防ぐことができるはず。
マンキュー入門経済学
戦略の経済学
イノベーションのジレンマ
組織の経済学
組織は戦略に従う

戦略/組織/人事と組織の経済学シリーズを読んでいる: プログラマの思索

組織論一般の理論を解説しているのが分かりやすかった。
組織行動のマネジメント

とても薄い本なのだが、アイデアがどうやって生まれるか解説してくれている。
アイデアの作り方

佐藤さんの解説記事がわかりやすい。
素早く考える能力、じっくり考える能力 : タイム・コンサルタントの日誌から

IT業界の営業戦略、プロセス導入ではキャズム理論が必須と思う。
パッケージ製品の営業だけでなく、新しい開発運用プロセスを導入する時もキャズムの法則に似たような事象が見られるから。
キャズム

キャズムの感想~イノベータ理論とホールプロダクト理論: プログラマの思索

伝記本として読んだ。
スティーブ・ジョブズ I」「スティーブ・ジョブズ II

岩波文庫なので文章は硬い。
プロテスタンティズムの倫理と資本主義の精神
君主論

自分が弱いのは意思決定、ゼネラルマネジメント、財務会計の分野かな。
全部読み切るには10年ぐらいかかりそうな感じ。

| | コメント (0)

2023/06/10

「ゲームをテストする バグのないゲームを支える知識と手法」の感想

「ゲームをテストする バグのないゲームを支える知識と手法」を読んだ。
JSTQB FoundationLevelを取得した後に読んだので、ソフトウェアテストの基本を抑えていて、かつ、ゲーム業界特有の考え方や組織、技術に関する話があって面白かった。
ラフな感想をメモ書き。

【1】僕は業務系システム開発しか経験がないので、ゲーム業界のことは知らない。
「ゲームをテストする バグのないゲームを支える知識と手法」を読むと、ゲーム業界特有の特徴がいくつかあると感じた。

業務系システム開発では、機能の網羅性、性能要件やセキュリティ要件などを踏まえた品質担保を重視する。
決められた要件があって、その要件に基づいた機能の網羅性の品質を担保することをすごく重視する。
つまり、当たり前品質の確保にかなり重点を置くように思える。

一方、ゲーム業界の品質は単に機能が網羅されていることが重要視されているわけではない。
UIや面白さなどの魅力的品質がかなり重視される。
だからゲームでバッグのように、開発中のゲームをプレイしてバグを探すように、ユーザが楽しめるプレイを中心に見る。
そこには機能の担保ももちろんあるがUIや楽しさもかなり重視しているように思える。
この辺りは業務系システムがBtoBビジネスに対し、ゲームソフトがBtoCビジネスであることから生じている事情もあるだろう。

しかし、ゲームソフトのソフトウェアテスト専門会社が出現し、品質向上や品質の可視化を目的として目標とする品質を定め、専門的な技術を使ってその品質レベルに到達するために必要なテストを計画したり設計するようになってきたという。
つまり、ゲームソフトでも品質管理や品質保証という考え方がビジネスとして必要になってきたわけだ。

【2】「ゲームをテストする バグのないゲームを支える知識と手法」では、JSTQBのソフトウェアテスト体系に基づき、ソフトウェアテスト7原則、ソフトウェアテストの専門体制、テストの種類、テストの活動、ソフトウェアテストの技術が紹介されている。
ゲーム業界特有のゲームでバッグの話は面白い。
一方で、ゲーム業界に限らず、JSTQBのソフトウェアテスト体系に基づいて内容が紹介されているので、その知識があれば、より理解しやすくなるだろうと思う。

たとえば、テストの体制には、テストマネージャ、テストリーダー、テスト担当者ごとに役割がある。
テストの種類(テストレベル)には、機能テスト、非機能テスト、探索的テストなど各種テストがある。
テスト活動には、テスト計画→テスト分析→テスト設計→テスト実装、テスト管理などがある。
この辺りはJSTQBの話と全く同じ。
換言すれば、こういうソフトウェアテストの専門知識を持ってゲームソフトのテストを専門的に実施しているならば、かなり組織的にテストをやっているわけなので、品質管理や品質保証もかなりレベルが高いのではないかと思う。

JSTQBのテストプロセスの概念モデルを描いてみた: プログラマの思索

【3】ゲーム業界のテスターのキャリアマップは興味深かった。

管理系・技術系のキャリアに分かれている。
管理系キャリアは、テストマネージャやテストリーダー。
技術系のキャリアは、テスターから始まり、テスト設計者、自動化エンジニア、ゴッドハンドデバッガー。
この観点は一般的なプログラマやSEのキャリアに似ている。

【301】個人的に興味を引いたのは自動化エンジニア。
彼の役割はテスト自動化ツールを活用してプログラムを実装して自動テストを実現する。
Pythonの利用が多いらしい。
また、昨今はAIを活用したテスト自動化技術が注目されているらしい。
mablとかもそうなのかなと思う。

アジャイルチームのためのインテリジェントなテスト自動化ソリューション | mabl

テスト自動化が今後重要な役割を持つだろうと直感する。
ソフトウェアテストはどうしても手動テストや手動デバッグが多く、人海戦術になりがち。
そういう部分をプログラムそのもので自動化すれば品質が担保されるし、回帰テストによりデグレードも防げるメリットがあるのは誰もが理解する。
一方、テスト自動化は技術の難易度が高いし、やみくもにテスト自動化してもコスト削減効果がさほど得られない話もよく聞く。

テスト自動化の8原則という概念も初めて知った。
この辺りも色んなノウハウがあると思うので調べてみる。

テスト自動化研究会 - テスト自動化の8原則

テスト自動化の8原則について解説

【4】テストエンジニアの年収が記載されていたのも目を引いた。
一般アルバイトなら時給1072円、テストリーダーなら時給1172円。
年収は225万~400万円程度。
テストマネージャなら月給30万~50万レベルとのこと。
今はインフレなのでこれよりも高いだろうが、まだまだ低い気がした。
ソフトウェアテストの専門性が認知されれば、今後も上がっていくのだろうと思う。

| | コメント (0)

2022/12/25

JavaGold SE11の感想

JavaGold SE11を無事に取得できた。
試験勉強を通じて、有意義な経験を得られたと思う。
ラフなメモ書き。
間違っていたら後で直す。

【参考】
Java歴13年がJava Gold(SE 11)を受けてみた - yucatio@システムエンジニア

JavaGoldSE8に受かったので(前編) - Qiita

JavaGoldSE8に受かったので(中編) - Qiita

JavaGoldSE8に受かったので(後編) - Qiita

JavaSilverの感想~Javaはオブジェクト指向と関数型言語の2つの性格を持つ: プログラマの思索

Javaはなぜ関数型言語になろうとしているのか: プログラマの思索

【1】受験のきっかけ
コロナ禍がずっと続いて、リモートワークになりプライベートでも対面の付き合いがほとんどなくなって、余った時間を有効活用したい。
過去にJavaで開発していた頃はせいぜいJava5くらいで、それ以降のバージョンは完全に理解できていなかったので、ラムダ式等をきちんと習得したい。
15年以上前にSunのJava試験を受けて落ちたのでリベンジしたい。

【2】勉強方法
オラクル認定資格教科書 Javaプログラマ Gold SE11(試験番号1Z0-816)」(通称、紫本)と『徹底攻略Java SE 11 Gold問題集[1Z0-816]対応』(通称、黒本)を最終的に5回転以上回した。
黒本だけでは理解できず、紫本を5回転以上回して慣れる必要があった。
なお『徹底攻略Java SE 11 Gold問題集[1Z0-816]対応』の「総仕上げ問題」は実際の試験問題に似ているのでやるべき。

【3】JavaSilverは「Javaはオブジェクト指向である」ことを設計でもコーディングでも理解できれば合格できる。
しかし、JavaGoldは「Javaは関数型言語である」こと、特にラムダ式を使って設計でもコーディングでも理解する必要があった。
頻出論点は、ストリームAPIと関数型インターフェイス、モジュールシステムだったと思う。
僕には正直難しかった。
理由は、オブジェクト指向プログラミングはUMLによるモデリングを通じて経験していたが、関数型言語プログラミングのお作法もその概念も理解していなかったから。
「OptionalはMaybeモナド、ストリームAPIはMapReduceでありリストモナド、入出力APIはIOモナド」ということを最終的に理解する必要があるのではと思った。

【4】 第1章 クラスとインタフェース

なぜ内部クラス(inner class)が必要なのか?
2つのクラスソースファルを1つにまとめる必要がある時に使う。

内部クラス→static内部クラス→ローカルクラス→匿名クラス→ラムダ式 の順に昇華されていく。
よって、ラムダ式の発端は内部クラスにある。

インナークラスのインスタンス化には、エンクロージングクラスのインスタンス化が必要である。
つまり、無意味なインスタンス化のロジックが発生する。
そこで、インナークラスをstaticインナークラスにすれば解決できる。
staticインナークラスならば、エンクロージングクラスのインスタンス化無しで、インナークラスのインスタンス化ができる。
staticインナークラスにすれば、staticなインナークラスのフィールドやメソッドをエンクロージングクラスでそのまま参照できる。

staticなインナークラスでは、フィールドやメソッドの参照はコンパイルエラーになる。
一方、staticでないインナークラスでは、フィールドやメソッドを参照できる。

Effective Javaでは、「内部クラスにはstaticを付けるべき」というプラクティスがある。

内部クラスにstaticを付けると、内部クラスから外部クラス(エンクロージングクラスとも言う)のフィールド変数にアクセスできなくなる。
つまり、スコープが小さくなる。

ローカルクラスから参照するローカル変数は、実質finalが必須。
実質finalでなければコンパイルエラーになる。
ローカルクラスから参照するローカル変数を、ローカルクラスの後で変更するとコンパイルエラーになる。
この仕様は関数型言語のイミュータブルな性質に似ているので、そのような仕様にJavaが合わせたのではないか。

一方、RubyやPythonのクロージャでは、ローカル変数を変更しても問題なく動く。
Rubyのブロックはメソッドによる手続きブロックとは異なって、ブロックの外側で定義されたローカル変数をブロック内で参照・変更できるという性質を有する。ただブロック内で定義された変数はその外側で参照できない。

無名クラスは、メソッド内に無名のインナークラスを定義するので、ラムダ式。と実質同じ。
Effective Javaでは、「無名クラスよりもラムダを選ぶ」プラクティスがある。
無名クラスは冗長な記述であり、ラムダ式の方が簡潔に書けるからだ。

匿名クラスにコンストラクタは定義できない。
しかしインスタンス初期化子を使えば、似たような処理を行うことが出来る。

インターフェイスのdefault/privateメソッドは、Scalaのtrait, Rubyのmoduleと同じ。
ただし、インターフェイスを継承した2階層下のクラスや2階層下のインターフェイスでは使えない。
インターフェイスのstaticメソッドは、継承直下の子クラスのみ利用できる。
privateメソッドはdefaultメソッドから呼び出されることを前提としている。
インターフェイスは型の提供が目的であり、メソッドの実装は基本は実装クラスが提供する。
インターフェイスのstaticメソッドとラムダ式のおかげで、Factroyクラスが不要になった。

なぜJavaのインターフェイスがのstatic/default/privateメソッドを必要とするのか、理由が分からなかった。
たぶん、Scalaのtrait, Rubyのmoduleを真似て、共通ロジックをわざわざインスタンス化して利用する面倒な手続きを減らしたい意図があるのだろう。

Enumはシングルトンクラス。
Effective Javaでは、Enumに独自に新規メソッドを実装するプラクティスがある。

Javaのenum型はシングルトンクラスみたいだ: プログラマの思索

Effective Java 第3版 第6章enumとアノテーション - Qiitaでは、int型をEnu型で書くべき、というプラクティスは理解できる。
しかし、「拡張可能なenumをインタフェースで模倣する」プラクティスのように、通貨クラスに「+」「-」のようなメソッドを独自で実装するという発想はなかった。
こういう考え方がドメイン駆動設計の値オブジェクトの実装に役立つのだろう。

【5】 第2章 関数型インタフェースとラムダ式

Javaのラムダ式は、関数型インフェーエイスの宣言とインスタンスの生成を同時に行う文法とみなす。
つまり、ラムダ式=関数型インターフェイス(抽象メソッド1個だけ)+インスタンス生成。

ラムダ式を使えば、Factroyクラスは不要になる。
つまり、DIを実現するために、Factoryパターンを使い、その実装にラムダ式を使う。
ラムダ式を使えば、Strategyパターンを短く書ける。
ラムダ式をメソッドチェーンで書けば、Builderパターンを短く書ける。

Javaのラムダ式のローカル変数は、スコープ外では実質finalとして扱われる。
ローカル変数の値を更新するとコンパイルエラーになる。
この性質は関数型言語の特徴に似ていると思う。

@FunctionalInterfaceを付けたインターフェイスは、自動的に関数型インターフェースとして使用できるが、抽象メソッドは1個だけ限る。
他言語では関数1個で定義できるが、Javaは必ず関数をclassで囲む必要があるので、関数型IFで定義する必要がある。

Javaの関数型インターフェースの抽象メソッドで注意すべき点は、java.lang.Objectのメソッドはカウントされない。
たとえば、public abstract String toString()があれば、抽象メソッドにカウントしない。

ラムダ式を使うと何が嬉しいのか?
1.抽象メソッドを実装したクラスを最小のコード量で実装できる
2.抽象メソッドの実装と、メソッドを使うところを一つにできる

関数型インターフェイスには1つしか抽象メソッドがないので、戻り値・引数の型と順番を、関数型インターフェイスの型からJavaコンパイラが推測できる。この仕組みが型推論なわけだ。
だから、Haskellのような関数型言語はコンパイラを作りやすいという理由は、型推論が強力な特徴があるからだろう。

通常パターン;
* Function, XXXFunction :apply()
* => 戻り値:R
* Supplier:get()
* => 戻り値:T
* Consumer, XXXConsumer :accept()
* => 戻り値:void
* Predicate, XXXPredicate :test()
* => 戻り値:boolean

特殊パターン:
* ToXXXFuntion:applyAsXXX()
* ToIntFunctionならapplyAsInt()のような感じ。
* XXXSupplierの形だけ注意! => getAsXXX()
* IntSupplier:getAsInt()
* DoubleSupplier:getAsDouble()
* LongSupplier::getAsLong()

UnaryOperator、BinaryOperator=引数と戻り値の型が同じ。
引数と戻り値の型が同じなので、Gnericsは1つで良い。

【6】 第3章 並列処理

並行処理(concurrent):処理を切り替えて同時に動いているように見せる。Threadクラスと同じ。
並列処理(parallel):複数のコアで同時に処理を行う。ストリームAPIでparallelメソッドを使う。

Executor によって処理されるタスクの状態遷移図
created(タスク生成) 
→ submitted(キューにタスクを登録) 
→ started(タスクのrun実行)
→ completed(タスクの終了)

Thread.run()がキューに登録されて、Thread.start()で、run()が実行される。
キューに登録されたRunnable.run()が実行される。

なぜ、並列処理はラムダ式や匿名クラスを使うのか?
スレッドのタスクは、関数型インターフェイスRunnnableのラムダ式で実装されるから。

Future=スレッドを生成したメソッドが、新しく作ったスレッドの結果を保持する。
submitの戻り値=Future => Future.get()で取得できる。
list.add(services.submit( XX -> XX))を実行できる。
一方、executeの戻り値=無し。

Runnable.run()はvoidなので、何も返さないから、Future.get()はNULLを返す。
Callable.run()は戻り値があるので、Future.get()は結果を返す。

Future fut = ex.submit( () -> {処理}, 0); は、第2引数0を返す。

Callableで定義したタスクで例外が発生した時、ExecutionExceptionでキャッチする。

CyclicBarrier=スレッドを待機させる。
java.util.concurrent.CyclicBarrierクラスを利用すると、複数のスレッドが特定のポイントまで到達するのを待機させることができる。
CyclicBarrier=複数のスレッドが特定のポイントまで到達するのを待機できるようにする同期化支援機能を持つスレッドクラス。
スレッドN本目を通過すると、await()の待機は解除される。

* バリアー:複数スレッドの待ち合わせポイント
* バリアーアクション:待ち合わせ後に実行される処理

マルチスレッドで扱うクラスのフィールドにvolatile修飾子を付けると、キャッシュされなくなる。
これにより並列処理時にどちらかがキャッシュを読み込むことによる不整合をなくせる。

【7】 第4章 ストリームAPI

ストリームAPIとは何なのか?
一言で言えば、JavaのMapReduce用APIと思えばいい。
大量データをリストで引数として設置して、Mapで処理させて並列処理できるようにばらして、並列処理の結果をreduceで1つにまとめて戻り値に返す。

実際の問題では引っ掛けパターンが多い。

ラムダ式のローカル変数は実質finalなのに、2回代入している
ただし、ローカル変数が配列ならポインタ参照なので、2回代入はOK。
たとえば、ArrayListやint[]の場合。

ラムダ式を{}で書いたのに「;」なし。

ラムダ式の中で、varの引数はコンパイルOK。
つまり、ラムダ式内の処理の引数は型推論される。
ただし、varはメソッド引数やメンバ変数に使うとコンパイルエラーになる。

Stream<型>のようなGnericsで引っ掛けるパターンが多い。

* map(T -> R)とflatMap(T -> Stream)
* mapToInt()とmapToObject()
* mapToInt(ToIntFunction)とmap(T, R)
* pararell(Stream --> Stream)とpararellStream(Collection --> Stream)
* reduce(BinaryOperator --> Optional)とreduce(DoubleBinaryOperator -->DoubleStream)

終端操作を2回実行すると実行時に例外が発生する。
例:anyMatch, count, reduce, forEach, collect

中間操作だけで終わると、値は返却されない
例:peek

終端操作countだけ実行しても出力されない。System.out.println(count)が別途必要。

List.stream().pararell() <=> List.pararellStream()は同じ。

boxed()は、XXStream -> Streamへ変換する。
逆の操作は、Stream --> mapToInt(IntToIntFunction)--> IntStream。

reduce().orElse()でint型、double型を返す。

Javaのsumはreduceで置き換えられる: プログラマの思索

Javaのreduceの使い方は2種類ある: プログラマの思索

モナドとは「メソッド内の副作用の存在を戻り値の型で表現する」ためのデザインパターン。
「関数に副作用がある」ことを「戻り値の型」で表現している。
Genericsを使って、戻り値の型を増やしている。

なぜ関数型IFではGenericsが頻繁に使われるのか?
理由は、関数の副作用を戻り値の型で表現するために、Genericsを使って戻り値の方の個数を増やしているからと考える。

OptionalはMaybeモナド。
Optionalの語源:値がないかもしれない => オプションの値を作りましょう。

StreamはListモナド。
MapReduceの戻り値はOptionalを返す。
それにより、Nullの戻り値はなく、ヌルポを防げる。

IOはIOモナド。
入出力処理における副作用は、戻り値の型をGenericsで表現する。

StreamAPIはメソッドチェーンで書かれるので、処理の途中でどのように戻り値の型が変換されて遷移するのかわかりにくい。
そこで、StreamAPIはバラして考えるとよい。
Eclipseの「ローカル変数の抽出」を使って、メソッドチェーンをばらすといい。

【8】 第5章 入出力

java.ioパッケージは古い機能。
たとえば、Fileクラスは、ディレクトリやファイルへのパスを扱うだけで、ファイル自身を表すのではない。

java.nioパッケージは新しい機能なので、痒い所に手が届くようになっている。
nio.Filesクラスは新しい入出力API => 同じパスに同じファイルがあれば作成時に例外を発生させて検知してくれる。
NoSuchFileException - ファイルが存在しない場合
DirectoryNotEmptyException - ファイルがディレクトリで、ディレクトリが空でないために削除できなかった場合

FileクラスとFilesクラスの違いは覚える。
Fileクラス提供のisXXXメソッドは、引数を取りません。
* 例:File.isDirectory() : boolean
* 例:File.isFile() : boolean

Fileクラス提供のメソッドは、renameTo(dest)以外はほとんど引数を取りません。
* 例:dirFile.mkdir()
* 例:dirFile.mkdirs()
* 例:file.renameTo?(File dest)
* 例:dirFile.listFiles()
* 例:file.getAbsolutePath()
* 例:file.toPath()
* => new File("ファイル名").toPath()の形式でPathオブジェクトを生成する

Filesクラス提供のメソッドは、全て引数を取ります
これ覚えとくだけで事前にコンパイルエラーかわかるようになった。
* 例:Files.isDirectory(Path dirPath)
* 例:Files.deleteIfExists(Path path) =>ファイルやディレクトリが存在している場合だけ削除する
* 例:Files.list(Path dirpath): Stream =>ディレクトリ内の全てのパスを表示
* 例:Files.find(開始パス、深さ、BiPredicateオブジェクト、オプション): Stream
* 例:Files.isSameFile(path1 : Path, path2 : Path) : boolean : path1とpath2が同じか否か
* Files.move?(Path source, Path target, CopyOption... options)
* Files.copy?(Path source, Path target, CopyOption... options)

Files.walk(), Files.find()は引数を覚えるのが重要。
Filesクラスのwalk()は再帰的にパス情報を取ってくる。
Files.walk(開始パス、深さ、オプション):サブディレクトリまで展開したパスを再帰的に表示
指定された開始ファイルをルートとするファイル・ツリーを参照することで Pathが遅延移入されるStreamを返します。

Filesクラスのfind()は再帰的にパス情報を処理して、判定条件に合致したファイルだけを探す。
Filesクラスのfind()の引数の順番は覚えたほうが良い。
Files.find(開始パス、深さ、BiPredicateオブジェクト、オプション):サブディレクトリまで展開したパスを再帰的に処理して必要なフィルのみ表示
指定された開始ファイルをルートとするファイル・ツリー内でファイルを検索することで Pathが遅延設定されるStreamを返します。

XXのようにStreamがついてなければCharacterストリーム。
XXStreamのようにStreamがついていればByteストリーム。

getDefault()は、FileSystemsクラス, Localeクラスにある。
SystemDefault()はZoneIdクラスにある。

Serializableのtransient修飾子は、シリアライズ対象から外す。
デシリアライズ後はnullになる。
static変数は、シリアライズ対象外になる。
∵static変数はグローバル変数なので値は保持される。

【9】 第6章 JDBCによるデータベース連携

Statement ◇--PreparedStatement, CallableStatement

Statement 単純な実行計画を行いたい時(select * from ... を 1 回だけ など)
PreparedStatement 複数回に渡る実行計画を行いたい時, ? のパラメーター解析を使いたい時
CallableStatement ストアドプロシージャを実行

Statementは静的なSQLを扱い、PreparedStatementはプレースホルダを使った動的SQLを扱えます。
基本は、Statementクラスを用いずにjava.sql.PreparedStatementクラスを使用する。
∵SQLインジェクション対策になる。
∵名前の通り、SQLがDBにキャッシュされるため、繰り返し同じSQL文を発行する場合に処理速度が速くなる。
PreparedStatementはDBMSが理解できるようにSQL文をあらかじめコンパイルするから。

まあ、今ならベタなPreparedStatementで実装することはなく、フレームワークで書くのが普通だろう。

【10】 第7章 汎用とコレクション

Genericsの使い道は2種類しか思いつかない。
ListやMapの型安全。
関数型IFの引数、戻り値の型定義。

Cell と Cellは全く別のクラスになる。
Genericsを使う時に、初心者が間違えやすいらしく、僕も最初はハマった。

Cellにすれば、パラメータに全てのクラスを扱える。
しかし、Cellではパラメータにクラスの制約がないのは不便。
そこで、Cell,Cellを使って、パラメータに使えるクラスの範囲に制約をかける。

一般的に PECS という呪文が存在し、上限付き境界ワイルドカード型をProducerと呼び、下限付き境界ワイルドカード型をConsumerと呼ぶことがあるらしい。
Producer - 値の生成専門
Consumer - 値の受取専門

PECS(Producer extends and Consumer super)とは、Javaのジェネリックスプログラミングにおいて、ジェネリッククラスのメソッドに柔軟性を持たせるための原則である。基本は以下の通り。
メソッドが値を取得するコレクション(Producer)は型にextendsをつける
メソッドで値を設定するコレクション(Consumer)は型にsuperをつける

Javaジェネリクス:PECSって何? - Qiita

java - What is PECS (Producer Extends Consumer Super)? - Stack Overflow

JavaジェネリックスのPECS原則、extendsとsuperの勘所 -- ぺけみさお

Genericsの型推論は、ダイヤモンド演算子<>を記述すると、下記が推論される。
* 変数への代入 =>例: var a = new ArrayList<>();
* メソッドの戻り値 =>例: return new ArrayList<>();
* メソッド呼び出しの引数 =>例: execute(new ArrayList<>());

ComparableとComparatorの違いも注意。

ComparableとComparatorの違いは何か: プログラマの思索

【11】 第8章 アノテーション
【12】 第9章 例外とアサーション
【13】 第10章 ローカライズ
は省略。

【14】 第11章 モジュール・システム

JavaのモジュールシステムでSPIとDIを実現するやり方: プログラマの思索

Javaのモジュールシステムの考え方をまとめてみた: プログラマの思索

Javaのモジュールシステムは複雑性をより増している: プログラマの思索

【15】 第12章 Java SEアプリケーションにおけるセキュアコーディング
は省略。

| | コメント (0)

より以前の記事一覧