エンハンス開発する人がつらくなるコードの例その1:やたらと反転しているBoolean値

りまりま団のもふもふです。「エンハンス開発で泣かないようにするために」というテーマで技術書典8に参加しようとしていましたが、参加を取りやめました。そこで、出そうとしていた本の内容を(せっかく時間もできたので)ブラッシュアップしつつブログ記事にしようと思います。

まえがき:エンハンス開発は楽しいけどひやひやする

もふもふちゃんは昨年8月に、toB向けの自社サービスを運営する会社の正社員になりました。今はVue.jsを使ったWeb画面の不具合改修などの保守・改善と新規機能の追加開発を仕事として取り組んでいます。これらの業務はエンハンス開発と名前がついていますので、もふもふちゃんは自社サービスのエンハンス開発をしていることになります。

今まではSIやSES企業で働いており、基本的に「サービスリリース後は運用保守部隊に引き渡す」業界で働いてきました。保守をしなくて良いのは楽ですが、実際に自分が作ったものが本当に良いものだったのかを知る機会はありませんでした。0から新規サービスを開発することも学びがありますが、実際どうだったのか、保守する人に迷惑をかけていないかわからないことに寂しさを感じることもありました。

今関わっているサービスは既に別の人が開発を行い、もふもふちゃんが転職したときには既にサービスインしているものでした。アプリケーションはVue.js(2系)とTypeScript、Vuex・Vue Routerをつかって開発されており、スタイルはBootStrapVueでつけられていました。1

どうやら短期間かつリリーススケジュールがシビアだったようで、コンポーネントへのテストは記載がなく、画面の仕様はデザインカンプと実際の動作からデバッグしないとわからない状態でした。2時間が無いとこういう取り組みは後回しになってしまうんですね。そこを責めてもしょうがないと思います。だって開発スケジュールが最優先じゃないですか…。

頼みの綱は実際のコードですが「わ、わ、わからん…!!!」となることがあり、仕様 is 動作の状態なので変更を入れるたびにデグレしていないか心配になっていました。最近は仕様がわかってきたので単体テストの整備や仕様書の記述をやっています。

開発事情を知らない人が「わからんので困る!」となるコードの周辺をいじくる心理的ハードルはすごく高く、「わからんので触らないようにしとこ」となってしまいがちです。ではどういうコードだと「わからん」となってしまうのか、困ったパターンを汎化して自分への戒めとしようと思いました。当たり前ですが実際の業務用コードではないです。基本パソコンは会社に置いて帰る派なので!

このシリーズに出てくるVue.jsのバージョンは2、Vue CLIでプロジェクトを作るときは以下のオプションを使用しています。

  • TypeScript
  • Vuex
  • Vue Router
  • SCSS
  • Jest
  • ESLint

例その1:アラートコンポーネントの表示を切り替える

特定の条件においてアラートを表示するMessageAlertコンポーネントを表示するMainPageというコンポーネントの動きがおかしいようです。チェックボックスがついているときはコンポーネントを表示したいのに、チェックボックスがついていないときにコンポーネントが表示されてしまいます。

実装されていたもの

MainPage.vueにアラート用コンポーネントがインポートされているようです。<template><script>部分を見てみましょう。

MainPage.vue

<template>
  <div id="main-page">
    sample-app
    <MessageAlert
      v-if="!displayAlert"
      :variant="info"
      :text="message-alert"
    />
    <div class="toggle-alert">
      <input
        id="toggle-message-alert"
        type="checkbox"
        v-model="displayAlert"
      >
      <label for="checkbox">Toggle MessageAlert</label>
    </div>
  </div>  </div>
</template>
import { Component, Vue } from 'vue-property-decorator';
import MessageAlert from './MessageAlert.vue';

@Component({
  components: {
    MessageAlert,
  },
})

export default class MainPage extends Vue {
  displayAlert: boolean = false;
}
</template>

コードから読み取れた実装内容

MainPage.vueに対する単体テストは存在せず、仕様書もありません。そこでコードと実際の挙動から動作を推測することにしました。

  • 表示切り替えは v-ifで実施
  • v-ifの条件がtrueならコンポーネントを表示する
  • v-ifの条件はdata : displayAlertで切り替えている

f:id:MofuMofu:20200216212909p:plain
チェックボックスがOFFのとき

f:id:MofuMofu:20200216212947p:plain
チェックボックスがONのとき

調べてみると、どうやらコンポーネント表示を切り替えているv-ifの実装が怪しいようです。 怪しい部分に注目してみました。

  <MessageAlert
    v-if="!displayAlert"
  />

これだとdisplayAlerttrueのときはv-iffalseが割り当てられてしまいます。 なぜならば!displayAlertの値が反転されているからです。 逆に、displayAlertfalseのときはv-iftrueが割り当てられます。 チェックボックスの<input>タグはONのときにtrue、OFFのときにfalseとなるため、v-ifの条件とチェックボックスの状態が揃っていないことが原因でした。そこで、!を削除する修正を行いました。

  <MessageAlert
    v-if="displayAlert"
  />

単体テスト(spec)も追加しました。

mainPage.spec.ts

import { shallowMount } from '@vue/test-utils'
import MainPage from '@/components/MainPage.vue'

describe('MainPage.vue', ()=> {
  it('displayAlertがtrueの場合、MessageAlertを表示しない', () => {
    const wrapper = shallowMount(MainPage);
    wrapper.setData({displayAlert: true});
    expect(wrapper.find(MainPage).html()).toContain('<messagealert-stub variant="info"></messagealert-stub>');
  });
});

わかりにくくて困る部分とその対策:v-ifの条件が反転されていると条件が追いかけづらい

v-ifのように、コンポーネントの表示切り替えを判定するための条件が!で反転されていると、どの条件ならコンポーネントが表示されるのか判断しづらくなってしまいます。コンポーネント表示を制御するためのBoolean値と、コンポーネントの表示条件を管理するBoolean値の状態が一致しないので、その分解読コストがかかってしまうのです。

MessageAlert.vueの表示条件はただのBoolean値の反転なのでとても単純でした。これがバリデーションを判定するメソッドの返り値だったら解読は難解になってしまいます。ちなみにANDまたはORで複数条件をパイプされてしまうともう理解できません。

これを防ぐためには、条件分岐の条件を反転しない工夫が必要です。v-iftrueで表示、falseで非表示、とルールが決まっています。これを制御するための条件制御もv-ifのルールに合わせておけば、条件制御の処理だけ確認すれば良くなります。フラグに関する処理はなるべく反転を避ける、これがエンハンス開発で泣かないようにするための工夫その1なのです。


…とまあこんな感じで書き溜めていきたいと思います。こうしとけば次のイベント参加のときに楽できるでしょ…だって記事を校正して組版すればいいじゃない!


  1. BootStrapとやかく言う人は多いですが、昔からあるサービスに別サービス追加となると、昔から使ってるBootStarpのスタイルに合わせるのが筋だよねみたいなことは思います。見た目もきれいだとおもうんですけどね〜。

  2. 転職するまでにも2つ程Vue.jsの開発プロジェクトに参加しましたが、どこもコンポーネントへの単体テストは記載していなかったので、単体テストを書いている会社はチーム運営も含めて優秀なのでは!!!と思うようになってきました。