テックキャンプ卒の弱々エンジニア日記

エンジニアとして働く中での学びをちょっとでも記録していきます。

パイプラインアーキテクチャ (ソフトウェアアーキテクチャの基礎11章)

こんにちは、Tochiです。

前回に引き続き、パイプラインアーキテクチャについてまとめていきます!

11章 パイプラインアーキテクチャ

パイプラインアーキテクチャは「パイプとフィルター」アーキテクチャとして知られている。 Unizターミナルシェル言語の背後にある基本原則がこのアーキテクチャに親しんでいる。

ちなみにこちらもおすすめ www.ohmsha.co.jp

パイプラインアーキテクチャトポロジーはパイプとフィルターから構成される。

パイプはフィルター間の通信チャネルを形成する。 一方向かつポイントツーポイントとなっており、あるソースからの入力を他のソースに出力する。

フィルターはぞこ完結型で他のフィルターからは独立している。 フィルターは4種類に分けられる。

  • プロデューサー: 処理の開始点。ソース
  • トランスフォーマー: 変換器。入力をうけて変換を行い出力パイプに送る
  • テスター: 入力を受け1つ以上の基準について検査。
  • コンシューマー: パイプラインフローの終了点

これらを用いたパイプラインアーキテクチャは、シンプルな一方向の処理を進めるタスクで用いられる。 例えばEDIツールは、このパイプとフィルターを使って、あるドキュメントタイプから別のドキュメントタイプへの変換を構築する。 そういう意味でアプリケーションロジックをフィルターで分割しているという意味では技術によって分割されたアーキテクチャといえる。(アーキテクチャ量子は1つになる)

このアーキテクチャは、モジュール性と組み合わさったシンプルさと、全大的なコストが強み。 モノリシックゆえの、複雑さがなくシンプルで理解しやすい。維持・構築のコストも比較的低い。 また、他のフィルターに影響を与えることなく、変更や置き換えが可能。

ただし、レイヤードアーキテクチャと同じで弾力性やスケーラビリティはかなり低い。 (この理由はレイヤードアーキテクチャと全く同じ)

まとめ

正直このへんはパイプラインアーキテクチャとして勉強するより、UNIXの考え方や思想を学んだ方が理解がしやすいと感じた。

レイヤードアーキテクチャ (ソフトウェアアーキテクチャの基礎10章)

こんにちは、Tochiです。 ソフトアーキテクチャの基礎10章の振り返りをアウトプットしてきます。

10章 レイヤードアーキテクチャ

レイヤードアーキテクチャ

レイヤードアーキテクチャはn層アーキテクチャと呼ばれ最も一般的なアーキテクチャスタイル。 システム設計する組織にとっては、コンウェイの法則が働くため各層がUI開発チームやバックエンドチームなどにうまくフィットしている。

makitani.net

そのため、レイヤードアーキテクチャの各層には、アーキテクチャにおける特定の役割と責務が明確にある。

プレゼンテーション層はユーザインターフェースとバックエンドとの通信ロジックに責務があり、データをどのように取得するか知る必要はないし ビジネス層はリクエストに関連した特定のビジネスルールの実行に責任があるので、どのように表示されるかを知る必要はない。

この「関心ごとの分離」は、技術によって分割されているので 開発者は特定の専門的知識を活かしてドメインの技術側面に集中することができる。

一方でこの全体的なアジリティの欠如が欠点。 ドメインで分割されたアーキテクチャとは対照的に、ある顧客ドメインはプレゼンテーション層やビジネス層、ルール層、サービス層、データベース層に散らばっているため、顧客ドメインへの変更が困難。ゆえにドメイン駆動設計のアプローチと相性が悪い。

層の分離

各レイヤーは閉鎖レイヤーと開放レイヤーに分けられる。

  • 閉鎖レイヤー
    • リクエストがレイヤーを上から下に移動していくさいにレイヤーをスキップせずに直下の層をしていかないといけないもの
  • 開放レイヤー
    • 開放レイヤーでは直接他のレイヤーを経由することなく直接そのレイヤーに到達することができる

レイヤー間のコントラクトが変更されないように、あるレイヤーの変更を他のレイヤーのコンポーネントに影響させないようにする(層の分離)には、他レイヤーの内部操作については全く知識をもたないようにすべし。

開放レイヤーのような直接的なコンポーネントへのアクセスができるようになると、他レイヤーとの相互依存性が高まり変更が困難となる高コストなアーキテクチャとなってしまう。

ただ、特定のレイヤーを開放レイヤーにしたほうが合理的なことがある。 たとえば、ユーティリティクラスのようなものはサービス層を新たに設けるなどをするのが好ましい。

考慮事項

アーキテクチャシンクホールアンチパターンには気をつける。 これは、層が具体的な処理を持たずに下のレイヤーに流してしまうだけとなっている状態を指す。 簡易的なリクエストの場合はインスタンス化と処理だけが行われ、無駄なメモリ消費が発生してしまう。

このアンチパターンは、少なくともいくつか発生するが80:20の法則で、20%のまでは許容してもよいだろうと。 80%に近づいて来たらそれは、アーキテクチャが不適切だということっぽい。

まとめ

レイヤードアーキテクチャは、予算と時間に厳しい制約がある中では優れた選択肢。 シンプルで低コストなアーキテクチャで小規模アプリケーション開発を用意にする。 また要件が定まってない状態の場合も、このアーキテクチャは優れた選択肢になる。

ただし、弾力性とスケーラビリティは非常に評価が低い。 モノリシックなデプロイメントとアーキテクチャのモジュール性の欠如によって、 アプリケーションはあるポイントまでしかスケールできない。

また耐障害性をサポートしてないという点も考慮にいれるべき。

エンジニア歴3年の2023年振り返りまとめ

こんにちは、Tochiです。

2021年7月からエンジニアとしてキャリアをスタートさせてから 毎年いろいろなことがありましが、2023年は特に変化の大きかった1年だったと思います。

2024年に良いスタートを切るためにも改めて今年一年を振り返ってみたいと思います。

唐突なメンバーの退職から始まった2023年1月

「〇〇さんは実は先週を最後に退職となりました。」

代表から告げられたメンバーの退職。 そんな始まりの2023年でした。

当時社員10名しかいないなかでの退職は、 なかなか辛いものがあった記憶していました。

しかも、雰囲気的に「辞めた」というより「辞めさせられた」という感じで

社内の雰囲気が一気に暗くなったということを鮮明に覚えています。

理由はともあれ、仲間が減ることのストレスはかなり強いのだと知りました。 (後日談ですが本人と食事に行った際に、いろいろ聞きましたがほぼクビだったようです。)

一方、自身の仕事としてはある企業のカスタマイズ案件を担当しており 関わっていたプロダクトのほぼ全ての機能を改修するなど、割と重いタスクをこなしていました。

当時の職場は、特に上司のような存在やテックリード的な存在がおらず(それっぽい人はいても機能していなかった) プロジェクトオーナー制という形で基本的に自分の判断でタスクを進めていました。

初めはそれなりにやりがいを持っていたのですが、入社当時から感じていた「jQueryを頑張る意味とは?」や「本当に正しいアプローチで実装できているのかな?」など 自身の中の疑問が強くなっていった時期でもありました。

資格取得に励んだ2月

1月に感じた疑問は日に日に強くなりました。 ただ、運良く近くにインフラに強い方がいらっしゃったので、、、

  1. もしインフラ関連の資格を取れば、インフラ関連のタスクを任せてもらえるようになる。
  2. アプリ側にテックリード的な方はいないが、インフラならこの方に教えてもらいながら成長できるかも
  3. よし、まずは資格を取ろう!
  4. もし転職する際も、これはきっといい方向になるはず!!!

といった安易な考えでAWS SAAやLPIC-1を取得するため勉強しました。(合格もできた!)

ただ、急にアプリ開発をやめてインフラのタスクに専念するなど そんなわがままは通用せず、、、

結局ただの資格ホルダーになっただけの2月になりました。

結局第一次転職活動に突入した3月

結局、年収の低さや技術スタックの古さ、今後のキャリアが見えないなど 職場に対する不安や疑問がかなり大きくなってきたため、一旦自分の市場価値を知るためにも転職活動を開始しました。

カカク〇〇さんや、その他有名企業にたまたま合格できたですが いまいち技術的にも年収的にも納得がいく結果にはならず自体することになりました。 (結局、安い年収でそれなりに学習意欲のある26歳であれば採用されやすいのだなと思いました)

ただ、この転職活動で分かったのは

  • まだ経験と自信が足りてない
  • 今の職場でやりきれてないことが多い??

ということが自分の中ではっきりしたため、今の職場で残り続けようと思いました。

ちなみに、年収交渉強めにでたらかなり増えました(笑)

家族に不幸があった4月

家族に不幸があり、なんとなく何もやる気が起きなかった1ヶ月。

本当に記憶がないです。

人生初のRuby Kaigi に参加した 5月

一人で長野県松本市までRubyKaigiに参加しました。

感想は、「業務役立たねえなあ」というのが本音の部分。 一方で、「え!!!!!エンジニアなった3年であの人登壇者なってるやん!」という衝撃もありました。

自分がキャリアのことばかり考えている一方で、 真摯に技術と向き合い、自分と向き合い、好きなことに没頭している同世代のエンジニアを見て自分のレベルの低さに嫌気がさしたのを覚えています。 ちょっとRubyが使えるだけなのに、「完全に理解した!」と思っている自分が井の中の蛙状態だったことに気付かされた良い経験でした。

ちなみに、RubyKaigiでツイッターとかで繋がっている方とお会いできたり普通に楽しかったです。松本市最高!!

人生を変えた新メンバーの入社 6月

6月(正確には5月)に待望の新しいメンバー、しかもエンジニアが入社してきました。 エンジニア歴5年で、フロントがかなり強くスキルがとても高かったのです。

しかし、この人物が私のこの一年を大きく変えました。

そう、「ブリリアントジャーク」でした。

www.vanstation.com

「クソコード」といったり、人のコードを嘲笑ってみたり。

遅刻はしたり、寝坊したり、さぼったり、、、、でも技術力は高い。

元々良くも悪くも素直な私はこの方に強い影響を受けました。

1つは、この方の発言を聞いているうちに「あ、この会社の技術ってやばいんだ、、」とか「ずっとすごいと思っていたあの人、全然ダメなのか」など マイナスが情報が入るうちに、自身もジャークスのような考え方が身について来ました。そして、1月ごろに感じていた職場への不安や疑念が自分の中で確信に変わりました。

ただ、この方のおかげで新規事業側がReactやモダンな技術も使った開発ができそうだったので 一旦すぐの転職はやめました。

実際、この方からReactのおすすめの勉強本などを教わったりしたので 一定良い刺激もあったのですが、いかんせん口が悪すぎて日々のストレスがやばかったです。

なお仕事の方はかなり順調で、 Vue.jsを用いて新規画面を開発したタスクが自分としてはかなり納得感が強く、 「なんだ、やればできるじゃん」みたいな根拠なき自信を持てるようになった感覚がありました。 のちに、この感覚はよくない方向へ向かっていきます、、、、(次へ)

徐々に組織崩壊していった 7月・8月

6月のタスクの成功で、7月・8月もかなり責任重大なタスクを振っていただいきました。 なんとなく「一人前のエンジニア」として認められたような感覚があったので、次も成功するぞ!とモチベーション高く仕事していました また、密かに転職を考え初めてもいたので、自己学習の一環でTSやReact、Next.jsなどモダンな技術を触れるようにしていました。

ここまで聞くと順調と思われますが、、、、徐々にブリリアントジャークが牙を向きます。

まず初めは、私とブリリアントジャーク(以下、ジャークさんと書きます)で口論になってしまったこと。 6月のタスク成功のせいで「俺は1人前のエンジニアなんだ!先に所属していたのは自分なんだ!」という間違った自信があったためか その方にPRレビューで「クソコード」「笑える」などと揶揄されて口論になってしまいました。 仕事場で口論なんて、、、なんて情けないんだと、反省するばかりです。

次に、フルリモートでやっているシニアエンジニアの方とジャークさんの対立。 もとより、シニアエンジニアの方も気難しい方ではありました。 ジャークさんが社内でコーディングガイドラインや設計レビューなど 諸々進めてくださっていたのですが、それがシニアエンジニアの方からすれば、強引な押し付けに見えてしまったようで ここでも対立が生まれてしまいました。

厄介だったのは技術力が高いが故に、ビジネスサイドからはそれなりの評価を受けていたし 実際に新規事業を推し進めていたということもあり、「あいつやばい」という雰囲気よりも「まあ、ジャークさんはそういう キャラ だから」という流れになってしまい仕方ないよねみたいな風潮になりました。

こうして、徐々に人間関係が非常に悪くなっていきました。

「相手にリスペクトをもって仕事をする」

自信がいつしか、自惚れへ変わって、自分の考えが正しいとすら思っていた私の人生最大の暗黒期でした。 もちろん100%自分だけが悪いとは思えませんが、リスペクトを持って接することや、相手の背景にあるものを理解しようとする姿勢があれば 問題はもっと少なくできたのではないかと反省しています。

社会人4年目にして、仕事で最も重要なことに気付かされました。

痛みと引き換えに大きな収穫を得ました笑

まっじで余談ですが、というか全然関係ないですが、、

この時期に1LDK60平米の広い賃貸に引っ越せたので生活水準が大きく上がった時期でもあります。

もう一度挑戦したいと決意 9月・10月

痛みを伴いつつも、大事なことを学び、

ある程度スキルも付いて来たなと思えたのがこの時期でした。

そして思いました。

「今こそ環境を変えてもう一度チャレンジしたい」と。

今の職場に残るという選択肢も最後まで悩みました。

それでも、この職場で得た経験・知識がどこまで通用するの知りたい、それこそ井の中の蛙になってないか知りたいという欲求に抗えませんでした。

そして転職活動を開始。

それなりに順調に選考が進み、第一企業に行くことができました!!

有給ライフでタイ旅行と勉強 11月

新しい職場は12月入社と決まり、 11月は有給消化の期間でした。

GraphQLやNext.jsなど知らない技術のキャッチアップに時間を当てつつも タイ・バンコクに旅行に行ったりかなり充実した1ヶ月でした。

最高の上司と職場との出会い 12月

待ちに待った新しい職場へのジョイン!!! この1ヶ月は本当に濃かった。

新しい技術を吸収してぐんぐん知識が増えたり、 「学びは消化しない・ストックしよう!」と教えてくだった上司をきっかけにブログアウトプットを開始したり、 「内部実装やドキュメントに頼る癖つけてね」ということでGithubで内部実装みたり、 優秀なインターン生に負けまいと、勉強時間倍増したり、 社内の色々なエンジニアと交流・勉強会したり、、、 本当に今までのエンジニアライフとは全く違う最高の時間を過ごせました。

とりわけ新しい技術のキャッチアップは大変ながらも面白かったですし、 輪読会に参加してみたり「事業や仕事関係なく、エンジニアライフって楽しいのか!」と初めて思えた時間だったかもです。

まとめ

振り返ってみると激動の2023年でした。

反省することが多かった1年ではありましたが、 それでも大きく成長するためのバネになると信じて2024年も頑張っていきたいと思います!!!!

【LeetCode】わかっていても使えない再帰関数

こんにちは、Tochiです。 LeetCodeをしていて苦戦していた問題の答えを見ていたときに膝から崩れ落ちたものがあったので アウトプットしてきます。

問題

2 つのソートされたリンクリスト list1とlist2の先頭 が与えられます 2 つのリストを 1 つの並べ替えられたリストにマージします。このリストは、最初の 2 つのリストのノードを結合して作成する必要があります。 マージされたリンク リストの先頭を返します。

例 1:

入力: list1 = [1,2,4]、list2 = [1,3,4]

出力: [1,1,2,3,4,4]

例 2:

入力: list1 = 、list2 =

出力:

例 3:

入力: list1 = 、list2 = [0]

出力: [0]

制約:

  • 両方のリストのノード数は [0, 50]の範囲内です
  • -100 <= Node.val <= 100
  • list1とは両方とも降順ではないlist2順にソートされます。

回答

これを特には再帰的なアルゴリズムを即座に考えられないとまずいです。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function mergeTwoLists(l1: ListNode | null, l2: ListNode | null): ListNode | null {
  if (l1 === null) { return l2 }
  if (l2 === null) { return l1 }

  if (l1.val < l2.val) 
       { l1.next = mergeTwoLists(l1.next, l2); return l1 } 
  else { l2.next = mergeTwoLists(l1, l2.next); return l2 }
}

答えを見たらそれはそうだとなるのですが、 この再帰アルゴリズムを即座に思いつくのって中々できなかったりする。 大学とかだとこの辺しっかり学ぶが、久しく忘れていた。。

再帰アルゴリズムを利用しないとなると。。

自分が最初に考えていたのはこんな感じ。

function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null {    
    const dummyHead = new ListNode();
    let ptr = dummyHead, p1 = list1, p2 = list2;

    while (p1 && p2) {
        if (p1.val < p2.val) {
            ptr.next = p1;
            p1 = p1.next;
        } else {
            ptr.next = p2;
            p2 = p2.next;
        }
        ptr = ptr.next;
    }
    ptr.next = p1 ?? p2;

    return dummyHead.next;
};

普通にこれでも正解ではあるが最適解ではない。 実際、ランタイムはめっちゃ遅い。

まとめ

この辺のアルゴリズムについてはもう一度勉強し直す。。

ソフトウェアアーキテクチャの基礎 第一部まとめ

こんにちは、Tochiです。 前回、「ソフトウェアアーキテクチャの基礎 第一章まとめ」というテーマでブログを書いたのですが、 その後、章末ごとにブログを書けず、第一部を読み終えてしまったので一気に簡単にまとめていきたいと思います。

第二章 アーキテクチャ思想

アーキテクトらしく考え、アーキテクチャの観点で物事を見るための側面を4つを紹介している

アーキテクチャと設計の違い

アーキテクトは、ビジネス要件を分析してアーキテクチャ特性(~~ility)を抽出・定義し、問題領域に適したアーキテクチャパターンやスタイルを選択して システムの構成要素(コンポーネント)を作ることに責任をもつ。 一方、開発者はコンポーネントごとのクラス図やユーザインターフェースとなる画面を作成し、コードを責任・テストすることに責任をもつ。 アーキテクトの考えは往々にして開発者に確実に引き継がれるというわけではないので、メンタリングやコーチングする機会を提供する必要がある。

実体験に置き換えると、私の上司が概念設計とコンポーネント設計をし、それを自分らが実装・開発するといった具合かな。 メンタリングやコーチングはいわゆるコードレビューや1on1を通じて、アーキテクト(上司)と開発者(自分)が双方向のコミューニケーションができるようにする感じですかね。

② 技術的な幅

「アーキテクトは技術の幅、開発者は技術の深さを必要とされる」 知識には、

  • わかっていること
  • わかっていないとわかっていること
  • わかってないとわかっていないこと

の3段階ある。 開発者はこの「わかっていること」の深を深くすることが求められ、アーキテクトは「わかってないとわかっていること」の幅を広げることが重要視される。

それはそうって感じ。 意思決定する上では、知っていることのを幅は広い方がいいし、多少わかってないと思っていてもそれがわかっていれば調べるだけ。 INDEXはたくさんあった方が意思決定はしやすいのだろう。

トレードオフを分析する

アーキテクチャとはGoogleで見つけられないものだ」 技術的なものかどうかに関わらず、あらゆるソリューションのトレードオフを検討し、最善のソリューションを決定することがアーキテクト。 結局アーキテクチャは全てトレードオフ。 何を選択するべきかは企業文化やビジネスドライバーなどあらゆる変数によって時と場合によるので正解も不正解もない。

ビジネスドライバーを理解する

システムの成功な必要なビジネスドライバーを理解し、それをアーキテクチャ特性に変換することがアーキテクトに求めらる。 それには、事業ドメイン知識をある程度もち、ステークホルダーと健全かつ協力的な関係を築く必要がある。

第三章 モージュル性

モジュールの定義と計測方法について。 いまいちピンとこなかった章。

凝集度・結合度・コナーセンスの考え方について述べている。 コナーセンスって初めて聞いた。コナーセンスは変更容易性に着目した結合度の測り方で、その定義を簡単に言うと、コードベースにある2つのコンポーネント(関数やクラスやモジュールなど)にコナーセンスがあるというらしい。

qiita.com

かなり概念的な話だったので、「ふーん、そういう計測方法があるんだね」で流した。

第四章 アーキテクチャ特性

ドメインの機能に直接関連しないがソフトウェアが満たさないといけないこと(アークテクチャ特性)を定義し、発見・分析するのがアーキテクトである。 非機能要件という呼び方は、ネガティブな印象を抱くし、品質特性だと設計事後に行う品質評価の印象が強いのでアーキテクチャ特性と呼びたいらしい(筆者曰く)

アーキテクチャ特性は、以下3つの特性を満たす

  • ドメインによらない設計に関する考慮事項を明らかにするもの
    • アプリケーションが何をすべきかのか明らかにして、システムが成功するために必要な運用と設計の基準を明らかにするのがアーキテクチャ特性。要件を「どう」実装するかと「なぜ」その方法が選ばれたかに関心をもつ。これには明示的な特性と暗黙的な特性がある。(例: 「技術負債にならない」という特性は、要件文書に記されない暗黙的なもの)
  • 設計の構造的な側面に影響を与えるもの
    • 例えば、「セキュリティ」である。これをアプリケーション内で決済するかサードパーティで実装するかで大きく構造が変わってくる
  • アプリケーションの成功に不可欠なもの

アプリケーションはすべてのアーキテクチャ特性を持つこともできない。(セキュリティとパフォーマンスはほぼ確実に影響しあってしまう) そのため、アーキテクトはアーキテクチャ特性を一部しかサポートしない(選択しない)。

また、アーキテクチャ特性が多すぎると、あらゆるビジネス上の問題を解決しようとする汎用的なソリューションになるが、 そうしたアーキテクチャは扱いづらい設計となる、よって最善のアーキテクチャではなく 少なくとも最悪ではないアーキテクチャを狙っていく必要がある。

繰り返しになるが、結局はトレードオフなんだよっていうことを筆者な述べているのかな?? アーキテクチャのリストが本には記載してあったが、ユーザビリティまで言及していてアーキテクトの奥深さを感じた。。。

第五章 アーキテクチャ特性を明らかにする

アーキテクチャ特性をたくさんサポートするような「汎用アーキテクチャ」はアンチパターン。 サポートするアーキテクチャの数にこだわらずに、設計をシンプルに保つ気持ちが非常に重要。

その中で、サポートするアーキテクチャの優先順位を選んでもらうことは時間の無駄。なぜならステークホルダー全員の同意を得られることはほぼあり得ないから。 (これはめっちゃ共感。営業はパフォーマンスで経営はセキュリティといいだしたら、それこそ困ったことになる)

それよりも最も大事な特性を3つだけ選んでもらうことがいい。

ちなみに、明示的なアーキテクチャ特性もある。 たとえば、大量なアクセスに耐えられる弾力性など。

本章で、アーキテクト・カタに関する話があったがこれはかなり参考になった

qiita.com

いずれにせよ、この章で一番大切なメッセージは 「アーキテクト・開発者・ドメインアナリストが協力して最善の方法を決定すべき」ということ。 象牙の塔のアーキテクトアンチパターンになったら終わりってことですね。。

アーキテクチャに間違った答えはない。高くつくものがあるだけだ。」 この名言、本当にゾワっとする。

第六章 アーキテクチャ特性の計測と統制

この章はアーキテクチャ特性の計測と統制について焦点を当てている。

アーキテクチャ特性というのは非常にあいまいな言葉で、この言葉について共通の定義を持ちたい。 だから計測によって定義してこうぜって話かな。。?この章はマジでピンとこず

計測としては以下3種類があるとか。

  • 運用面の計測
  • 構造面の計測
  • プロセス面の計測

統制としては、 - 適応度関数を用いて循環依存の発見 - レイヤーの規約違反の発見

ん〜〜ちょっとわかるかも。 テストカバレッジとかESLintとかでimportの禁止したりとかそういうことを言っているのかな〜。。。。

結局のところ、アーキテクチャ特性について各組織で明確な基準を持って、 メンバー間の認識のギャップを埋めようせって感じだと思われる。。

第七章 アーキテクチャ特性のスコープ

アーキテクチャ量子と粒度という新しい考え方。 高度な機能的凝集性と同期的なコナーセンスをもつ、独立してデプロイ可能なアーティファクトということらしい。

運用上の関心ごとについて、スコープを絞ってみることで 早期に課題を発見できる。この時に使うのがアーキテクチャ量子と粒度の話みたいだが、、 結局、アーキテクチャ特性はある範囲の機能を実現するための「アプリケーション群」 + 「依存データストア」に対して定義されるので、 それぞれのドメインのコンテキストごとにアーキテクチャ特性を定義するという、まあ考えてみればそうだよねって感じの主張が並んでいる。

第八章 コンポーネントベース思考

コンポーネントはモジュール化されるアーキテクチャの基本構成である。

アーキテクチャの最上位分割として、 レイヤードアーキテクチャとモジュラーモノリスを比較している。結局これもトレードオフの関係にある。

この章で印象的だったのはコンポーネント発見の方法としてのアクター/ アクションアプローチ。 アプリケーションでアクティビティを実行するアクターと、そのアクターが実行する可能性のあるアクションを特定する

これは結構無意識化でやっていたと思う。 このアプリを使うユーザはなぜ使うのか、どう使いたいのか、実際どう使うのか。 そういったことを考えると自然とコンポーネントは分けようとなる。やっぱり概念設計って大事だなーと思った

まとめ

これで第一部は終わり。 まだ浅い理解でしかないが、それでも得られるものはデカかった気がする!!

bulletproof-reactに則った処理の流れ

こんにちは、Tochiです。 ようやく新しい環境にも慣れてきた今日この頃です。

社内で適用しているbulletproof-reactの使い方が徐々にわかってきたので 復習を兼ねてアウトプットしていきたいと思います。

bulletproof-reactとは

bulletproof-reactはReactアプリケーションのベストプラクティスの宝庫です github.com

概要としては、こちらが非常にわかりやすいので参考にしてください

zenn.dev

今回作りたいもの

今回作りたいものとしては、 シンプルな投稿の一覧画面と検索ボックスを作っていく感じになります。

本記事ではあくまでbulletproof-reactに焦点を当てたいので 細かい実装に関しては割愛しています。

一覧について

まず一覧の大まかな作りとしては以下のような形です。

設計方針 一覧

ディレクトリ構成はbulletproof-reactに則って、features/posts/配下に下記のような形で配置しています。 必要に応じて、utilsディレクトリなんかも置いてもいいかもです。

features/posts/
|
+-- api                         # exported API request declarations and api hooks related to a specific feature
|
+-- components        # shared components used across the entire application
|
+-- features               # feature based modules
|
+-- hooks                  # shared hooks used across the entire application
|
+-- providers           # all of the application providers
|
+-- types                 # base types used across the application
|
+-- index.ts

featuresはルーティングベースでディレクトリ分けを行うので、 もし/usersに関しての機能をまとめたい場合は、同じように/features/usersディレクトリを作成します。

なお、GraphQLを利用を今回は前提としています(Apolloを利用しています)が、この辺は割愛しますのでご了承ください。

コードとその説明

1つづつ解説していきます。

まず、リクエストするGraphQLのクエリを定義していきます。 このクエリは、features/posts/posts.graphqlで定義します。

query Posts {
  posts {
    nodes {
      id
      name
    }
  }
}

このGraphQLの定義は、GraphQL Code Generatorを使うことで /lib/graphql/index.tsにコードが生成されます。(usePostsQueryなどが使えるようになります)

次にProviderコンポーネントを定義します。 今回はpostsデータは一覧コンポーネントと検索コンポーネントにまたがって利用したいものなので 定義されたフックを用いてProviderコンポーネント使う必要があります。 providers/posts.tsxに定義していきます。

# typeの定義とは割愛してます。


const PostContext = createContext<PostContext>({....})

export const PostsProvider = ({children}: Props) => {

   const [posts, setPosts] = useState([])
   const [refetch, { data, loading }] = usePostsLazyQuery()

  useEffect(() => {
    if (queryLoading) return

    if (data) {
      setPosts(data.posts)
    }

    setLoading(false)
  }, [data,loading])

 return (
    <PostsContext.Provider
      value={{
       posts,
        refetch: handleRefetch
      }}
    >
      {children}
    </PostsContext.Provider>
  )
}

export usePostsContext() = () => useContext(PostsContext)

ここで定義したProviderコンポーネント/app/posts/page.tsxで利用します イメージこんな感じです↓

<PostsProvider>
    <SearchForm />
    <Table/ >
</PostsProvider>

こうすることで、SearchFormコンポーネントでも投稿データを受け取れます。(いちいちリクエストを送らずにすみます)

ここまできたらあとはcomponents/table.tsxを作ってあげるだけです。

export const Table = () => {
  const { data, loading } = usePostsContext();

  if (loading) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      {data.posts.map(post => (
        <div key={post.id}>{post.name}</div>
      ))}
    </div>
  );
};  

以上、ざっくりですがこんな感じでコンポーネントとロジックを定義していってあげます。

補足

検索フォームについてはhooksを使いますが基本的な考え方は同じです。 超ざっくりイメージd

設計方針 検索

まとめ

bulletproof-reactを使うと、各ディレクトリの役割が明確に決まっているために どこに何が書かれているかがわかりやすくコードを非常に書きやすいというメリットを感じました。

また、自由度が高いために生じる複雑性といったものもルールがあるがゆえに シンプルに記載するような意識が働いてコードが複雑化することも防いでくれるのではないかと思いました。

ソフトウェアアーキテクチャの基礎 一章まとめ

こんにちは、Tochiです。 先日上司からお薦めされた「ソフトウェアアーキテクチャの基礎」という本を読み始めたので、 記録用にブログでまとめていきたいと思います。

www.oreilly.co.jp

第一章

第一章はイントロダクションになっているので若干ふんわりしたまとめです。

1.1 ソフトアーキテクチャの定義

システムの構造とは、そのシステムを実装するアーキテクチャスタイル(マイクロサービス・レイヤードなど)を指す。

アーキテクチャ特性とは、システムがサポートしなければならない「イリティ(ility)」を指す。 (可用性・信頼性・テスト容易性・スケーラビリティ・セキュリティ・アジリティ・耐障害性・弾力性・回復性・パフォーマンス・デプロイ容易性・学習容易性)

アーキテクチャ決定は、システムをどのように構築すべきかのルールで、例えば、レイヤードアーキテクチャでいうビジネス層とサービス層だけがDBアクセスできるというルールを決定することです。

設計指針は、いわゆるガイドラインアーキテクチャ決定とは異なる。

1.2 アーキテクトへの期待

ソフトウェアアーキテクトには8つの期待がある。

  • アーキテクチャ決定を下すこと
    • チームや部門の技術的な決定を導くためのあー着てくや決定や設計指針を定義すること。
    • 例: 「フロントエンドにリアクティブベースのフレームワークを使う」など
  • アーキテクチャを継続的に分析すること
    • 現在の技術環境を継続的に分析し、改善を提案することが期待されている
    • 3年前の定義が今日時点でどのくらい存続力があるかをビジネスと技術の両方から評価すること
  • 最新トレンドを把握し続ける
    • 先を見据えた判断をするために業界の動向や最新技術にキャッチアップ
  • 決定の順守を徹底する
    • アーキテクチャ決定や設計指針の順守を徹底すること
    • アーキテクトが定義し、文書化し、伝達したアーキテクチャ決定や設計指針にチームが従っているかを継続的に検証する。
  • さまざまなことに触れ、経験している
    • 様々な技術・FW・プラットフォーム・環境に触れていることが期待されている
  • 事業ドメインの知識を持っている
  • 対人スキルを持っている
    • アーキテクトにはチームワークやファシリテーション・リーダシップなど卓越した対人スキルを持ち合わせていることが期待されている。
  • 政治を理解し舵取りをする
    • アーキテクトには企業の政治的風土を理解し、政治を舵取りする能力が求められる

この章で個人的に印象的だったのは、「アーキテクトが下すほとんど決定は反発される」という部分。 アーキテクチャ決定はコストや作業量(時間)の増加の面から、PdMやPM・ビジネスサイドなどのステークホルダーから反発を受けますという旨の内容だったが、まさに似たようなことを前職で経験したなあとおもった。

1.3 アーキテクチャと交わるもの

この10年間で、ソフトウェアアーキテクチャの範囲は、ますます多くの席にや観点を含むようになってきている。

1.3.1 エンジニアリングプラクティス

プロセスは、チームの形成や管理・ミーティングの進め方・ワークフローの整理の仕方などを意味する。 つまり人がどのように組織化され、どのように相互作用するのかメカニズムを指す。

エンジニアリングにおけるプラクティスとは再現性のある効果を示す、プロセスに依存しない手法を意味する。例えば継続的インテグレーションなど。 このエンジニアリングプラクティスにフォーカスを当てることは重要だが、我々は「未知の未知」の領域に対してあらじめ設計することはできない。 よって、必要とされるのは「進化的なアーキテクト」であり、それを実現するにはアジャイルなエンジニアリングプラクティスを採用することが望ましい。

1.3.2 運用とDevOps

かつては運用とソフトウェア開発は別の機能として捉えられてきたが、いまや多くの運用上の関心ごとをアーキテクチャと組み合わせるようになった。

1.3.3 プロセス

ソフトウェアアーキテクチャとソフトウェア開発プロセスは直接関係がないとされる公理もあるが、、、、、、

チームがソフトウェアを開発するプロセスはソフトウェアアーキテクチャに多くの面で影響を与える。 例えば、アジャイルでの開発のPJのアーキテクトははイテレーティブな開発を前提にしていたりする。

1.4 ソフトアーキテクチャの法則

第一の法則は 「ソフトウェアアーキテクチャトレードオフがすべてだ」

第二の法則は 「どうやってよりもなぜの方がずっと重要である」

ソフトウェアアーキテクチャトレードオフの関係にあり、そう中で「なぜ」それを選択したかを考察する必要がある。