9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LPの作成でコンポーネント駆動開発(CDD)とテスト駆動開発(TDD)を体験した感想

Last updated at Posted at 2022-03-29

はじめに

最近、複数人での開発でどうやれば効率良く開発ができるかを自分なりに考えるようになりました。そんなときにStorybookを使ってのコンポーネント駆動開発(CDD)、テストを通すためのコードを書くテスト駆動開発(TDD)があることを知った。

「こんな手法があるのかやってみよう!!」と思い、やってみたがAtomやMoleculeの定義やOrganism以降でロジックを渡すなど、一人で作業をするとやることが多すぎて、頭の中がショートしてしました😅
WebサイトのPaddingやMarginも定義されていないとコードも思うように書くことができず、LP1枚を作るのに2日もかかってしまった。

LP1枚くらいならなんとかCDDとTDDで進めることができたので、コンポーネント駆動開発とテスト駆動開発を体験した際のメリットやデメリットを書いていきます。

コンポーネント駆動開発(CDD)を体験して感じたこと

Atom編

Webサイトのデザインが完成し、「さぁ、Atomの部品から作りますか!」と思いながら作業を開始するとAtomの部品を定義してなかったので、この時点で時間のロスが発生。デザインカンプと一緒に決めるべきでした。

私の場合はFigmaを使っているので、FigmaのフレームにAtomやMoleculeなどの名前にして部品を貼り付けていった方がわかりやすかったです。
スクリーンショット 2022-03-29 0.55.36.png

Storybookを使って、テキストやボタンなど色や文字の大きさなど作っていきます。Storybookのドキュメントに記載されていたコードだとファイルを行ったり来たりしないといけないので面倒でした。正直Atomの部品を作るときは自分が書きやすいコードの書き方で十分だと思います!私の場合はこんな感じでした!

コードの書き方については、個人によって色々あるので参考程度で見てください!

Button.tsx 公式ドキュメント

import React from 'react';

interface ButtonProps {
  primary?: boolean;
  backgroundColor?: string;
  size?: 'small' | 'medium' | 'large';
  label: string;
  onClick?: () => void;
}

/**
 * Primary UI component for user interaction
 */
export const Button: React.FC<ButtonProps> = ({
  primary = false,
  size = 'medium',
  backgroundColor,
  label,
  ...props
}) => {
  const baseButton = 'rounded-full font-bold';
  const sizeMode =
    size === 'small'
      ? 'py-1.5 px-4 text-xs'
      : size === 'medium'
      ? 'py-2 px-5 text-sm'
      : size === 'large'
      ? 'py-3 px-6 text-base'
      : '';

  return primary ? (
    <div>
      <button
        type='button'
        className={`text-white bg-blue-400 ${baseButton} ${sizeMode}`}
        {...props}
      >
        {label}
      </button>
    </div>
  ) : (
    <button
      type='button'
      className={`text-gray-600 bg-transparent shadow-inner ${baseButton} ${sizeMode}`}
      style={{ backgroundColor }}
      {...props}
    >
      {label}
    </button>
  );
};
Button.stories.tsx 公式ドキュメント

import { ComponentStory, ComponentMeta } from '@storybook/react';
import React from 'react';

import { Button } from './Button';

// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
  title: 'Example/Button',
  component: Button,
  // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
  argTypes: {
    backgroundColor: { control: 'color' },
  },
} as ComponentMeta<typeof Button>;

// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args
Primary.args = {
  primary: true,
  label: 'Button',
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: 'Button',
};

export const Large = Template.bind({});
Large.args = {
  size: 'large',
  label: 'Button',
};

export const Small = Template.bind({});
Small.args = {
  size: 'small',
  label: 'Button',
};
Button.tsx 自分の場合
import React from 'react';

export const Button: React.FC = ({ children }) => <>{children}</>;
Button.stories.tsx 自分の場合
import { ComponentStory, ComponentMeta } from '@storybook/react';
import React from 'react';

import { Button } from './Button';

export default {
  title: 'atom/Button',
  component: Button,
} as ComponentMeta<typeof Button>;

const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;

export const Small = Template.bind({});
Small.args = {
  children: (
    <span className='py-1.5 px-3 text-sm  bg-yellow-500 rounded-full shadow-md'>Button</span>
  ),
};

export const Default = Template.bind({});
Default.args = {
  children: (
    <span className='py-2 px-4 text-base  bg-yellow-500 rounded-full shadow-md'>Button</span>
  ),
};

export const Large = Template.bind({});
Large.args = {
  children: (
    <span className='py-2.5 px-5 text-lg  bg-yellow-500 rounded-full shadow-md'>Button</span>
  ),
};

å

Molecule編

Atomの部品が完了したら、次はMoleculeです。でも、Moleculeってどう部品がそうなのか?いまいちピンとこなかったです。
分かりやすかった例は、「CardはMoleculeの部品」がピンときました。

Moleculeの定義がAtomの部品とAtomの部品が一緒になったらMoleculeとして定義されるらしいです。よく見かける画像はこれですね!
atomic-design-product.jpeg

ここでCardや検索フォームの見た目を決めていきます。ここの作業はロジックを決める必要はないので、見た目の部品を作る作業なので個人的には楽しく早く終わりました😊

Organism編

次はOrganismです。

ここでの部品はPageHeaderやPageFooterなどの部品を作っていきます!やることはMoleculeと大して変わらないです。
文字のサイズや配置などがなかなか決まらず、MoleculeやAtomを行ったり来たりしてました。

Organismからロジックを組み込んでいきます。

ロジックについては書きませんでしたが、テスト同様Organismが一番作業時間が取られそうと感じる。バケツリレー問題に直面しそうなので、こういった所でReactのCustom Hooksを利用すべきという考えは納得です。

この辺りの知識の習得は時間がかかりそうです😅

Template編

TemplateではOrganismまで作成した部品をペタペタ貼って最終確認をしていきます。因みに一番苦戦した箇所でした。Organismの部品を貼り付けて確認をするとデザインが崩れているところがいくつかありました😓それらの修正をして、気になるところがあればまた修正してAtom〜Organismをまた行ったり来たりしました。Templateを実装しているときは、修正が多くイライラしました😅笑

Page編

最後にPageで表示させて問題がなければ完成です。ここで表示させたいデータをAPIやDBから持ってくるようになります。今回はLPの作成なのでAPIやDBからデータを引っ張ってくることはなかったので苦労しませんでした😊

コンポーネント駆動開発(CDD)のまとめ

Atom〜Templateまではデザインカンプ完成の段階で定義した方がスムーズに進める。LPだけならそんなに大変ではないんですが、ロジックを書くときやAPIやDBからデータを取ってくるロジックを描くときはバケツリレーの問題にあって、さらに複雑になるかもしれないです。

ファイルの管理はこのようにしたら管理しやすかったです。

component
│
┝Atom 
│  └─Button
│       ┝Button.tsx
│       └Button.stories.tsx
┝molecule(organism以降も同様)
     └─Card
         ┝index.tsx
         ┝data.tsx
         ┝type.tsx
         ┝Card.stories.tsx
         └Card.test.tsx

テスト駆動開発(TDD)を体験して感じたこと

Atomではテストを書かないので省略します。

Molecule編

TDDを体験して思ったことは書いたコードが想定通りの挙動をしていることやデザインが壊れないことを担保してくれるのはありがたかったです。当たり前ですが..笑

先にテストコードから書いて、テストコードが壊れないように組んでいくことには違和感がありましたが、「まぁ、慣れれば誰でもいける」と感じました。ですが、予めどういったデータが入ってくるかを知る必要があるのでその辺りの知識は必要かと感じた。

正直一人で行うのは地味に大変でした😅 ですが、複数人で行うと考えた場合は他人の作業の邪魔はしにくいと感じました。
理由はどこが崩れたかを確認でき、作った部品を壊されないメリットがあると感じた。デメリットとしては複数人で行うのはいいが、一人で行うと書くコードが多く時間がかかることです。

Organism編

Organismからロジックについてもテストコードを書くんですが、今回はLPの作成なのでロジックについては書かずに済んだのでMoleculeと同様でデザインが壊れないためのテストとデータが問題なく表示されるテストだけを書きました。

複雑なロジックの場合はテスト1つ書くのに時間は結構取られるなと予想ができた。カスタムフックも利用して再利用可能なフックも作らなければならないので、この辺りのドメイン知識も必要になってくる。

時間の大半はOrganismの作業が占めると感じました!

Template Page編

Organismと同様

テスト駆動開発(TDD)のまとめ

見た目のスタイルやデータが表示されるテストコードを書くことによって、どこに問題があるかを早期に発見できる。
Webサービスを運営する目的によってはテストコードは不要と感じました。利益が出ていないときにはテストコードを書くためのコストが取れる所は少ないと思う😅

個人的には目的に関わらずテストコードはこれからも書いていこうと思います!!

最後にテストは大事😁

最後に

今回はLPだけでしたが、CRUDの機能やAPIでのコンポーネント駆動開発(CDD)とテスト駆動開発(TDD)を体験して、どのようにすれば開発がスムーズにいくかをこれからも意識して考えていきます!!

また、Component PatternやCustom Hooksの理解も弱いなと感じたので、その辺りも重点的に学ばなければと新しい課題に気づくことができました😊

是非みなさんもコンポーネント駆動開発(CDD)とテスト駆動開発(TDD)を体験してみてください!

最後まで読んでいただきありがとうございました!

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?