最新の Web サイトの複雑さは、過去数年間で大幅に増加しました。高品質の業界標準設計に対する需要の高まりにより、フロントエンド開発者が直面する課題はさらに深刻になっています。
現在、フロントエンド アプリであっても、開発プロセスを合理化するためにいくつかのアーキテクチャ上の考慮事項が必要です。 前回の記事では、サイド プロジェクトに取り組みながら、フロントエンド アプリケーションにクリーン アーキテクチャ アプローチを実装した経験を共有しました。
この記事では、同じプロジェクトでの私の経験に基づいて、アトミック設計アプローチをさらに深く掘り下げることを目的としています。その長所と短所について説明し、さまざまなシナリオでの有用性を評価します。
まず、デザイン システムの概念を見てみましょう。デザイン システムは、チームが複数のプラットフォームにわたって一貫したユーザー インターフェイスを設計および開発できるようにする、再利用可能なコンポーネント、ガイドライン、原則の包括的なコレクションです。
これらはデザイナーと開発者の両方にとって唯一の信頼できる情報源として機能し、製品の視覚的および機能的側面が確立されたブランド アイデンティティと一致し、遵守されていることを確認します。デザイン システムの実装例を調べることに興味がある場合は、以下を検討することを検討してください。
デザイン システムのトピックをさらに深く掘り下げたい場合は、この記事をチェックすることをお勧めします。このトピックについては詳細に説明されていますが、この作業の範囲内では必要のない詳細についても説明します。
アトミック デザインは、デザイン システムの基盤に基づいて、再利用可能なコンポーネントとガイドラインの編成と構造化を合理化する方法論です。ブラッド フロストによって考案された Atomic Design は化学からインスピレーションを受けており、ユーザー インターフェイスを最も基本的な構成要素に分解し、より複雑な構造に再構築します。
これを化学に例えた図を示します。
化学反応は化学方程式で表され、多くの場合、原子要素がどのように結合して分子を形成するかを示します。上の例では、水素と酸素がどのように結合して水分子を形成するかがわかります。
本質的に、アトミック デザインは設計システムの自然な進化であり、柔軟でスケーラブルなコンポーネントを作成するための体系的なアプローチを提供します。アトミック デザインの原則を適用することで、この方法論のモジュール性によりシステム内のコンポーネントとパターンの保守、更新、拡張が容易になるため、チームは設計システムをより効率的に管理できます。
複雑に聞こえるかもしれないと心配する場合でも、心配する必要はありません。次のセクションでは、私が開発したアプリの実例を使用して、これらの原則を適用する方法を説明します。これにより、理解しやすく、独自のプロジェクトに実装することが容易になります。
アトミック設計では、コンポーネントを 5 つの異なるレベルに編成し、それぞれが前のレベルに基づいて構築されます。これら 5 つのレベルを詳しく見てみましょう。
アトム: ユーザー インターフェイスの最も基本的な構成要素。アトムは、ボタン、入力フィールド、見出しなどの個々の HTML 要素を表します。これらは最小の機能単位であり、これ以上分解することはできません。
分子: 分子は、2 つ以上の原子が官能基に結合することによって形成されます。たとえば、検索フォーム分子は、検索入力アトム、ボタン アトム、およびラベル アトムで構成される場合があります。分子は、プロジェクト全体で再利用できる単純なコンポーネントを表します。
生物: 生物は、複数の分子や原子を組み合わせて作成される、より複雑な構成要素です。これらは、ヘッダー、フッター、サイドバーなど、ユーザー インターフェイスの個別のセクションを表します。生物はページの全体的なレイアウトと構造の形成に役立ちます。
テンプレート: テンプレートは基本的に、生物、分子、原子を使用して構築されたページ レイアウトです。これらは、実際のコンテンツを指定せずにページ上のコンポーネントの構造と配置を定義し、さまざまなコンテンツ シナリオの青写真として機能します。
ページ: ページは、実際のコンテンツとデータを備えた、完全に実現されたテンプレートの最終的なインスタンスです。これらは、ユーザーが最終的に表示し操作するものを表し、コンポーネントとレイアウトがさまざまなコンテンツ タイプやユースケースにどのように適応するかを示します。
フロントエンド開発のためのアトミック デザインについて十分な情報に基づいた視点を築くために、私はアプリケーションを作成する旅に乗り出しました。 6 か月間にわたり、このプロジェクトに取り組みながら貴重な洞察と経験を得ることができました。
したがって、この記事全体で提供される例は、アプリケーションに関する私の実践的な経験に基づいています。透明性を維持するために、すべての例は公的にアクセス可能なコードから派生しています。
リポジトリまたはWeb サイト自体にアクセスして、最終結果を調べることができます。
Reactでコーディングされた例を使用することに注意してください。この言語に詳しくなくても、心配しないでください。コードの核心的な詳細に焦点を当てるのではなく、アトミック デザインの基本的な概念を説明することを目的としています。
リポジトリ内のコンポーネントをより深く理解するには、ディレクトリ/client/presentation
の下にコンポーネントを見つけることができます。アトミック設計手法と一貫した命名を維持するために、この場所にatoms
という新しいディレクトリを作成しました。この新しいディレクトリには、オンボーディング プロセス全体を構築するために必要なすべての小さな部分が含まれています。
原子の完全なリストは次のとおりです。
atoms ├── box ├── button ├── card ├── card-body ├── card-footer ├── container ├── divider ├── flex ├── form-control ├── form-error-message ├── form-helper-text ├── form-label ├── heading ├── icon ├── input ├── list ├── list-icon ├── list-item ├── spinner ├── tab ├── tab-list ├── tab-panel ├── tab-panels ├── tabs └── text
これらの原子名はChakra UIパッケージに基づいているため、よく知られているかもしれません。それらのほとんどには、アプリケーションのデフォルトの一致スタイルがすでに含まれているため、このレベルで説明する特にユニークなものはありません。それを念頭に置いて、 molecules
直接議論することができます。
この段階では、アトミック設計プロセスがより興味深くなり、その真の力が明らかになり始めます。基本アトムの定義は時間のかかる単調な作業であったかもしれませんが、アトムを使用して新しいコンポーネントを構築するのはずっと楽しくなります。
分子を定義するために、 /client/presentation
ディレクトリ内にmolecules
ディレクトリを作成しました。必要な分子の完全なリストは次のとおりです。
molecules ├── available-notion-database ├── full-screen-loader ├── input-control ├── onboarding-step-layout └── onboarding-tab-list
実際、わずか 5 つの分子だけで、目的を達成するのに十分なコンポーネントが得られます。ここは、他のアトム上に構築された共有レイアウトを含めるのにも理想的な場所であることに注意することが重要です。たとえば、 onboarding-step-layout
、オンボーディング プロセスの 5 つのステップすべてを通じて一貫した外観を維持するために利用されます。
他のコンポーネントは次のとおりです。
available-notion-database : 取得したユーザーのデータベースの詳細を表示するために使用されます (ユーザーは複数のデータベースを持っている可能性があるため、ステップ 4 で 1 つを選択できるようにしています)。
コンポーネントは UI に次のように表示されます。
import { FC } from 'react'; import { Flex, Spinner } from '@presentation/atoms'; import { FullScreenLoaderProps } from './full-screen-loader.types'; export const FullScreenLoader: FC<FullScreenLoaderProps> = ({ children, ...restProps }): JSX.Element => ( <Flex alignItems="center" bg="gray.50" height="full" justifyContent="center" left={0} position="fixed" top={0} width="full" zIndex="9999" {...restProps} > <Spinner /> {children} </Flex> );
ここにはロケット科学はありません。これは、すでに定義されているflex
アトムとspinner
アトムの単なる組み合わせです。
input
グラウンドでアクションが発生しているかどうかを示す、 form-label
、 form-control
、 form-error-label
、およびspinner
備えた入力アトムのラッパー。コンポーネントは UI に次のように表示されます。
より多くのピースが準備できたので、デザイン パズルでより大きなブロックの定義に進むことができます。
このセクションでは、オンボーディング プロセスの各ステップを表示する各コンポーネントを作成します。
物事を明確にするために、作成された生物のリストを示します。
organisms ├── onboarding-step-one ├── onboarding-step-two ├── onboarding-step-three ├── onboarding-step-four └── onboarding-step-five
名前は一目瞭然であり、誤解があってはならないと思います。すべてをどのように組み立てるかを説明するために、1 つのステップのコードを例として示します。もちろん、さらに詳しく確認したい場合は、私のリポジトリにアクセスしてください。
export const OnboardingStepFour: FC<OnboardingStepFourProps> = ({ onBackButtonClick, onNextButtonClick, }): JSX.Element => { const { hasApiTokenData, isSetApiTokenLoading, setApiToken, setApiTokenError } = useSetApiToken(); const handleInputChange = debounce(async (event: ChangeEvent<HTMLInputElement>) => { const result = await setApiToken(event.target.value); if (result) { onNextButtonClick(); } }, 1000); return ( <OnboardingStepLayout subtitle="Paste your copied integration token below to validate your integration." title="Validate your integration" onBackButtonClick={onBackButtonClick} > <InputControl isRequired errorMessage={setApiTokenError || undefined} isDisabled={isSetApiTokenLoading || hasApiTokenData} isLoading={isSetApiTokenLoading} label="Integration token" name="integrationToken" placeholder="Your integration token" onChange={handleInputChange} /> </OnboardingStepLayout> ); };
このコードは、オンボーディング プロセスのステップ 4 を表示する役割をすべて担っています。あなたが抱く唯一の懸念は、生物にリクエストを行うことについてだと思います。これは許容されますか?すべてに当てはまる唯一の答えはありません。これらの懸念には「状況による」と答える必要があります。それはあなたの構造に依存します。
分子または生物内に API 呼び出しを含めることがアプリケーションのコンテキストで意味があり、コンポーネントが過度に複雑にならない場合、それは許容可能な解決策となる可能性があります。プレゼンテーション コンポーネントがデータ取得やビジネス ロジックと密接に結びつきすぎないように注意してください。維持やテストがより困難になる可能性があります。
私のシナリオでは、このコンポーネントは 1 か所で使用されており、そのシナリオで API 呼び出しを実行するための他のソリューションはより複雑で、必要以上に多くのコードが生成される可能性があります。
この段階では、UI の詳細ではなく、コンポーネントの構造と配置に焦点を当てます。テンプレートは、状態管理をどこに置くべきかを特定するのにも役立ちます。これは通常、テンプレートを使用するページ コンポーネント内にあります。
提供されたコード例には、テンプレートとして機能するOnboarding
コンポーネントがあります。
import { FC } from 'react'; import { Flex, Heading, TabPanels, Tabs, Text } from '@presentation/atoms'; import { OnboardingTabList } from '@presentation/molecules'; import { OnboardingStepFive, OnboardingStepFour, OnboardingStepOne, OnboardingStepThree, OnboardingStepTwo, } from '@presentation/organisms'; import { OnboardingProps } from './onboarding.types'; export const Onboarding: FC<OnboardingProps> = ({ activeTabs, createNotionIntegrationTabRef, displayCreateNotionIntegrationTab, displaySelectNotionDatabaseTab, displayShareDatabaseIntegrationTab, displayValidateIntegrationTab, displayVerifyDatabaseTab, selectNotionDatabaseTabRef, shareDatabaseIntegrationTabRef, validateIntegrationTabRef, verifyDatabaseTabRef, }) => ( <Flex direction="column" overflowX="hidden" px={2} py={{ base: '20px', sm: '25px', md: '55px' }}> <Flex direction="column" textAlign="center"> <Heading color="gray.700" fontSize={{ base: 'xl', sm: '2xl', md: '3xl', lg: '4xl' }} fontWeight="bold" mb="8px" > Configure your Notion integration </Heading> <Text withBalancer color="gray.400" fontWeight="normal"> This information will let us know from which Notion database we should use to get your vocabulary. </Text> </Flex> <Tabs isLazy display="flex" flexDirection="column" mt={{ base: '10px', sm: '25px', md: '35px' }} variant="unstyled" > <OnboardingTabList activeTabs={activeTabs} createNotionIntegrationTabRef={createNotionIntegrationTabRef} selectNotionDatabaseTabRef={selectNotionDatabaseTabRef} shareDatabaseIntegrationTabRef={shareDatabaseIntegrationTabRef} validateIntegrationTabRef={validateIntegrationTabRef} verifyDatabaseTabRef={verifyDatabaseTabRef} /> <TabPanels maxW={{ md: '90%', lg: '100%' }} mt={{ base: '10px', md: '24px' }} mx="auto"> <OnboardingStepOne onNextButtonClick={displayCreateNotionIntegrationTab} /> <OnboardingStepTwo onBackButtonClick={displayVerifyDatabaseTab} onNextButtonClick={displayShareDatabaseIntegrationTab} /> <OnboardingStepThree onBackButtonClick={displayCreateNotionIntegrationTab} onNextButtonClick={displayValidateIntegrationTab} /> {activeTabs.validateIntegration ? ( <OnboardingStepFour onBackButtonClick={displayShareDatabaseIntegrationTab} onNextButtonClick={displaySelectNotionDatabaseTab} /> ) : null} {activeTabs.selectNotionDatabase ? ( <OnboardingStepFive onBackButtonClick={displayVerifyDatabaseTab} /> ) : null} </TabPanels> </Tabs> </Flex> );
このOnboarding
コンポーネントは、原子、分子、生物を組み立てて、オンボーディング プロセスのレイアウトを作成します。状態管理とタブ ナビゲーション ロジックがこのコンポーネントから分離されていることに注意してください。必要な状態関数とコールバック関数が props として受け取られるようになり、より高レベルの「ページ」コンポーネントが状態とデータの管理を処理できるようになります。
この関心事の分離により、テンプレートはレイアウトと構造に重点を置きながら、状態管理が適切なレベルで処理されるようになります。
最後に、最終結果としてステップ 4 を示したいと思います。
前の説明のコンテキストでは、「ページ」コンポーネントはOnboarding
テンプレートを使用し、オンボーディング プロセスの状態管理を処理します。この特定のページ コンポーネントのコードはここでは提供されていませんが、私のリポジトリで見つけることができます。前述したように、ページ コンポーネントのコードには特別なことは何もありません。これは主に、状態を管理し、それをOnboarding
テンプレートに渡すことに重点を置いています。
アトミックデザインが実際にどのようなものかを見てみましょう。このアプローチの長所と短所を見てみましょう。
アトミック デザインには、モジュール性、再利用性、保守性などの明らかな利点が数多くありますが、最初に考慮する価値のあるいくつかの欠点もあります。
初期設定と複雑さ: アトミック設計には綿密に計画された構造と組織が必要ですが、最初に設定するのは時間がかかり、困難な場合があります。また、特にそのような詳細なアプローチが不要な小規模プロジェクトの場合、コードベースがさらに複雑になる可能性があります。
学習曲線: アトミック設計に慣れていない開発者にとって、この方法論の学習曲線は急勾配になる可能性があります。さまざまなレベルとそれらがどのように組み合わされるかをしっかりと理解する必要があり、初心者にとっては圧倒されるかもしれません。
オーバーヘッド: アトミック デザインの実装には、多数の小さな特殊なコンポーネントの作成が含まれる場合があります。これにより、特にコンポーネントが 1 つの特定のコンテキストでのみ使用される場合、これらのコンポーネントの管理と保守におけるオーバーヘッドが増加する可能性があります。
オーバーエンジニアリングのリスク: 再利用可能なモジュール式コンポーネントの作成に重点を置くと、開発者が広範なアプリケーションに集中する代わりに個々のコンポーネントの改良に多くの時間を費やしてしまう、オーバーエンジニアリングの潜在的なリスクがあります。
コミュニケーションとコラボレーション: アトミック デザインの成功は、デザイナー、開発者、その他の関係者間の明確なコミュニケーションとコラボレーションにかかっています。共通言語の確立や方法論の理解に失敗すると、実装において混乱や不一致が生じる可能性があります。
ただし、このアプローチには、すでに述べた独自の利点があります。それらについてさらに詳しく話しましょう。
スケーラビリティ: 設計を最も基本的な要素に分解することで、コンポーネントの複雑さを構築する作業がより管理しやすくなりました。原子の作成にはいくつかの課題がありましたが、これらの原子に基づいてコンポーネントを作成するのは非常に楽しかったです。
効率: 原子、分子、生物を再利用できるため、新しい機能の設計と開発に費やす時間が大幅に削減されます。基本コンポーネントが確立されたら、既存の要素を組み合わせるだけで新しいインターフェイスを作成できます。
一貫性: 前のポイントから直接得られます。同じ原子、分子、生物が複数のテンプレートやページで使用されるため、ユーザー インターフェイスは統一されたままとなり、ユーザーにシームレスなエクスペリエンスを提供します。
ドキュメント: アトミック デザインは本質的にドキュメントをサポートします。原子ベースの構造は、コンポーネントを構築および使用する方法についての明確な視覚的なガイドとして機能します。これは、新しいチームメンバーをオンボーディングする場合に特に役立ちます。
保守性: アトミック デザインの最大の強みの 1 つは、アトミック デザインが設計システムの保守性にどのように貢献するかです。すべてを原子的な部分に分解することで、あらゆる変更や更新を原子レベルで行うことができ、システム全体に伝播することができます。たとえば、ボタンの色を変更することにした場合、この変更を原子レベルで 1 回行うだけで、このボタンが使用されているすべての分子、生物、およびテンプレートに反映されます。これにより、長期にわたって設計システムを更新および保守するプロセスが大幅に簡素化されます。
結論として、アトミック デザインは両刃の剣のように思えるかもしれません。初期設定と学習曲線の点で少し気が遠くなりますが、その潜在的な利点は最初の苦労に値します。そして、覚えておいてください、最も恐るべき剣でさえ、熟練した騎士の手にかかれば無害であるということを!