4
0

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 3 years have passed since last update.

可読性・テスタビリティ・拡張性を高くif文を書く書き方

Last updated at Posted at 2020-09-11

先日、ペアプロしている際に、if文を書く位置をどうするかに、そこにif文を書くのではなく、別の書き方をしたほうが可読性が高いよという話をしていたので、if文を書く位置について普段考えていることをまとめます。
まず、自分が考えているのは、基本的に以下の2点です。reactで具体例を書いていきます。

  • 可読性・テスタビリティ高くため、if文によって処理が分岐する箇所を最低限の場所になるようにする
  • if文の中に処理は基本的に書かずに、分岐後の処理の詳細はメソッドに切り出す

if文の場所が複数箇所にあり、可読性が低いbad例

export const Bad: React.FC<{ isAdmin: boolean }> = ({ isAdmin }) => {
  return (
    <div>
      {isAdmin && <p>adminにはこれを見せるよ</p>}
      {!isAdmin && <p>userにはこっち見せるよ</p>}
      <p>両方に見せるよ</p>
      {isAdmin && <p>adminだけこの情報も見せるよ</p>}
    </div>
  )
}
  • adminなのか、userなのかロールによる条件分岐をずっと気にしなければ、ならないため可読性が低い

if文がまとまっており、可読性が高いbetter例

こちらの例ではadminなのか、userなのかロールによる条件分岐を気にするタイミングが、最初だけであるため、気にするタイミングが少なく可読性が高いです。

export const Better: React.FC<{ isAdmin: boolean }> = ({ isAdmin }) => {
  if (isAdmin) {
    return (
      <>
        <p>adminにはこれを見せるよ</p>
        <p>両方に見せるよ</p>
        <p>adminだけこの情報も見せるよ</p>
      </>
    )
  }
  return (
    <>
      <p>userにはこっち見せるよ</p>
      <p>両方に見せるよ</p>
    </>
  )
}

出し分けロジック、表示内容の詳細で責務が別れており、拡張性が高いgood例

better例と基本的には同じですが、別コンポネに表示内容の詳細は切り出すことで、拡張性が高くなります。
また、AdminComponent単体でテストをしたり、storybookを作ったりしやすくもなります。

const AdminComponent = () => {
  return (
    <>
      <p>adminにはこれを見せるよ</p>
      <p>両方に見せるよ</p>
      <p>adminだけこの情報も見せるよ</p>
    </>
  )
}

const UserComponent = () => {
  return (
    <>
      <p>userにはこっち見せるよ</p>
      <p>両方に見せるよ</p>
    </>
  )
}

export const Good: React.FC<{ isAdmin: boolean }> = ({ isAdmin }) => {
  if (isAdmin) {
    return <AdminComponent />
  }
  return <UserComponent />
}
  • Goodコンポーネントが持つ責務が、出し分けだけになるため、表示の複雑度が上がった際に対応しやすく、各種表示のロジックの詳細を別コンポーネントに分離することができる

if文が一箇所にまとまるため、テストがしやすい

bad例でのtestを書くと例えばこのようになり、「adminにはこれを見せるよ」と「adminだけこの情報も見せるよ」の2つが表示されており、「userにはこっち見せるよ」が表示されてないことをテストする必要があります。

  it('Bad admin', () => {
    const { container, asFragment } = render(<Bad isAdmin />)
    expect(container.textContent).toContain('adminにはこれを見せるよ')
    expect(container.textContent).toContain('adminだけこの情報も見せるよ')
    expect(container.textContent).not.toContain('userにはこっち見せるよ')
    expect(asFragment()).toMatchSnapshot()
  })

betterでのtestでは、「adminにはこれを見せるよ」が表示されており、「userにはこっち見せるよ」が表示されていないことをテストできれば、表示の切り分けが十分にテストできてるので、テストが簡単になります。
goodのコンポーネントも分けた状態も同様です。
また、場合によっては、good例の場合は、個別のコンポネはshallow mount(この例では、react testing libraryを使用してるためshallow mountはありませんが)したり、mockしたほうがテストは簡単にかけるかもしれません。

  it('Better admin', () => {
    const { container, asFragment } = render(<Better isAdmin />)
    expect(container.textContent).toContain('adminにはこれを見せるよ')
    expect(container.textContent).not.toContain('userにはこっち見せるよ')
    expect(asFragment()).toMatchSnapshot()
  })

今回は、reactを例に書いていますが、vueはもちろん、サーバーサイドの処理でも同様の考え方でif文の処理が分岐していくようにすると可読性が高く・テスタブルな処理がかけます。
条件分岐が複雑になりそうな処理を書く際は、この2つを意識してみてください。

  • 可読性・テスタビリティ高くため、if文によって処理が分岐する箇所を最低限の場所になるようにする
  • if文の中に処理は基本的に書かずに、分岐後の処理の詳細はメソッドに切り出す

また、例に使用しているコードの全体はこちらにも上げています。
https://github.com/YasushiKobayashi/samples/blob/master/src/react-if-sample/src/Main.spec.tsx
https://github.com/YasushiKobayashi/samples/blob/master/src/react-if-sample/src/Main.tsx

4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?