りまりま団のもふもふです。「エンハンス開発で泣かないようにするために」というテーマで技術書典8に参加しようとしていましたが、参加を取りやめました。そこで、出そうとしていた本の内容を(せっかく時間もできたので)ブラッシュアップしつつブログ記事にしようと思います。
りまりま団は技術書典8の1日目に参加を予定していましたが、サークル参加を欠席することにしました。先ほど運営事務局さんにメールを送信しました。チェックつけて下さった方申し訳ございません。
— もふもふ (@froakie0021) 2020年2月15日
頒布予定だった原稿はいくつかに小分けしてブログにアップする予定です。
まえがき:エンハンス開発は楽しいけどひやひやする
もふもふちゃんは昨年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
で切り替えている
調べてみると、どうやらコンポーネント表示を切り替えているv-if
の実装が怪しいようです。
怪しい部分に注目してみました。
<MessageAlert v-if="!displayAlert" />
これだとdisplayAlert
がtrue
のときはv-if
にfalse
が割り当てられてしまいます。
なぜならば!
でdisplayAlert
の値が反転されているからです。
逆に、displayAlert
がfalse
のときはv-if
にtrue
が割り当てられます。
チェックボックスの<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-if
はtrue
で表示、false
で非表示、とルールが決まっています。これを制御するための条件制御もv-if
のルールに合わせておけば、条件制御の処理だけ確認すれば良くなります。フラグに関する処理はなるべく反転を避ける、これがエンハンス開発で泣かないようにするための工夫その1なのです。
…とまあこんな感じで書き溜めていきたいと思います。こうしとけば次のイベント参加のときに楽できるでしょ…だって記事を校正して組版すればいいじゃない!