実務:2次開発時のDBカラム等追加で注意すること

先日、2次開発で機能を追加するため、既に存在しているDBに
新しくカラムを追加するため、DB設計をしました。
その際、自分では全然考えてなかったことを指摘してもらえたので
注意点として記します。

①既にあるカラムはいじらない
普通に考えればわかるのですが、私はうっかりやりそうになりました。
もう既にデータが登録されているため、それを変えると
ものすごく大きな影響が出る可能性があるため、いじってはいけません。

②NOT NULL制約を気軽に使わない
新しく追加するカラムを必須入力とした場合、
既に登録されているデータに対しては、そのカラムの値を
どうやって補填するのか考える必要があります。
そして、その補填方法を例えば空文字とするなら、
そもそも本当にそのカラムは必須入力とする必要があるのか、
考えなければいけません。


そして、DB設計時にこれが浮上したから、またクライアントに確認することに…


これは、今回のブログテーマと離れるけど、
クライアントと要件を詰めるときに、話をしながら
その機能を設計や実装する時のことを想像する必要があり、
いかに詳細に想像できるかが、とても重要だと思いました。
わたしはまだ、クライアントの意図を汲むことに必死なので、
経験を積みながらこの力をつけたいです。

実務:要望を形にすることの難しさ(画面イメージの作成)

最近の実務では、実装はいったんストップで、
Adobe XDで画面のイメージを作成→お客様のフィードバック→修正、を行っています。

国語+日本語の先生の資格をもっているから、要望を理解することはきっと得意!
と思っていたけど・・・
そんなことはありませんでした。厳しい。

例えば今回私が担当したのは、検索条件の一覧にある項目を追加するというもの。
でも、お客様からは「○○という条件でも検索できるようにしてほしい。」だけで、
その項目をどのように今の画面に反映するかは、私が考えなきゃいけませんでした。

文言をどうするか、ラジオボタンで選択させるか、チェックボックスでチェックを付けるか。
最初は、チェックボックスで「〇〇を希望」という項目を追加することで、
「○○を希望している」人も検索できるようにする、という画面イメージを考えていました。

しかし、チームリーダーと相談した結果、
チェックボックスで「○○希望を含める」という項目を追加することになりました。


ここに落ち着くまでに、文言・表示位置・フォーム部品の種類など、3,4回修正がありました。


この新たに追加することになった「○○」という検索条件は、他の条件に付随するものだったから
「○○を含める」の方が自然なのでしょう。


たった1つの小さな要望であれど、既存機能とのバランス、その要望の目的、使用方法に
よく配慮する必要があります。


私が追加した、たった1つのチェックボックス
その奥深さを体感しました。


今はまだ言語の勉強で手一杯だけど、近々ユーザーの操作感とか導線の分かりやすさとか、
そういうものについても学習したいと思いました。

実務+インプット(リーダブルコード8章)+ポートフォリオ: 関数をスリムにすることへの気づき

実務でサービスインされているコードを眺める、という有難い時間をもてています。
そんな中まず気づいたこと、1つ1つののメソッドの記述がすごく短い!

例えば、JavaScriptで、上位項目のinput要素が選択されたとき、
その下位項目のinput要素もすべても選択済みにする、というメソッドがありました。

わたしが1から書くとすれば、

①上位項目のinput要素を取得する
②下位項目のinput要素を取得する
③上位項目のinput要素のcheckedの状態を取得する
④③で、checkedだったら下位項目全てをcheckedにする、
 checkedじゃなかったら、下位項目全てをcheckedにしない

という一連の処理を1つのメソッドで処理させようとします。
でも!実務で見たコードは違いました!!
①、②、③と④で3つのメソッドに分けていました!!


リーダブルコードにも、巨大な式を分割し簡潔さを目指すことの重要性が書かれていました。
というのも、式が長くなればなるほど複雑になり、理解するのに時間がかかるからです。

自分が1から書いていないコードを見た時、その重要性に身を以て気づきました。
「長かったら、ぜったい読めない・・・」って。

ポートフォリオリファクタリングするときに、必ず抑えるポイントとして心に留めておきます。

実務:migrationファイルを更新しても読み込まれない

DBにカラムを追加することになったので、マイグレーションファイルを更新しようとしましたが、
upをしても更新分が読み込まれません。

原因:一度upされたマイグレーションファイルは読み込まれない
解決:ある程度遡ってdownをして、その時点からupを実行する

ネットの情報で原因は分かったものの、downで遡ったのが浅く
「INSERTの列がカラムより多い」という旨のエラーが出てしまいました。
migrate:statusでマイグレーションの状況を確認すると、
ずいぶん前の地点でmigrationが失敗してしまっていることがわかりました。
その地点まで遡り(downして)、その後upをしたら、すべてのmigrationファイルが正しく読み込まれました。

実務:DBから登録したデータを確認できない

Javaの受託開発に開発メンバーとして参画することになり、
実務の中で困ったこと、その解決方法、悩みなども記述したいと思います。

まずいきなり困ってしまったこと、それはDBへの接続方法です。

①背景:ローカル環境でデータを登録した→DB上から登録できたかどうかを確認したい
②問題:mongoDBのGUIツールを確認しても、データが全然入っていなかった

③解決方法・学んだこと
主に、先入観の問題でした。
開発参画前に、「DBはmongoDBを使っている」と聞いていたので
mongoDBのGUIツールを確認していたのですが、データは見えません。
ログを見るとsqlが発行されていたので、
「あれ?mongoDBってNosqlのドキュメント指向DBだって書いてあったのに…」と
不思議に思っていました。
結局他のメンバーから、画面表示用のデータはpostgreSQLに登録している、と聞き
事なきを得ました。
先入観に惑わされないこと、ログを見てズレを感じたらよく調査すること、
単に手順書通りに開発環境を整えていくのではなく、
「なんのためにこれをダウンロードするのか?」
「なにに使うのか?」まで考えて手順を進めていくこと、を意識する必要があると思いました。

課題5:献立確認画面から入力画面に戻った時、「フォーム再送信の確認」が表示されてしまう

献立確認画面の「戻る」ボタンを押すと、ブラウザの履歴機能を利用して、入力画面に戻り入力内容を編集することができます。
しかし、この「戻る」ボタンを押すと、「フォーム再送信の確認」という画面が表示されます。


原因:(まだ理解不足のため、要更新)セッションを使っていると
自動でキャッシュ制御用のHTTPヘッダーが送られるため、クライアント側のキャッシュが使用できなくなるから、です。

「ページの有効期限切れ・フォーム再送信の確認」の対策 - enma-laravel


(なぜセッションを使うとキャッシュが使用できなくなるかというと、
処理の重複(この場合は、同じ献立を2回登録してしまうこと)を避けるためです。

(そもそもキャッシュは、閲覧ページの情報を一時的に保存する機能で、単にページを見ているだけのときは問題ないけど、
ECサイトで買い物カゴに商品を登録したり、とか、入力フォームにデータを入力したり、とか
データの更新(やりとり)があった場合、「戻る」ボタンを押しても「データを更新した」という事実は残っているので、
再び画面遷移をした時、「戻る」ボタンを押す前の「データを更新した」という事実に加え、
また新たに「データを更新した」という扱いにされてしまうようです。(データの重複)


でも、それはキャッシュの性であって、セッション関係なく発生してしまうことじゃないのかな、と思ってしまい、
なぜセッションを使うとこの画面が表示されるのか、単にキャッシュの問題じゃないのか、と消化不良な状態です。
キャッシュ・セッション・クッキーの違いについて、まだまだ勉強不足なので、
勉強後にまたこの辺りの内容を更新しようと思います。(2020/8/11)


対策:原因が二重登録を防ぐ、というのは確実なので、
これを防ぐための対策は、トークンを利用して画面遷移を管理する、ことです!
具体的には、入力画面でランダムな数字でトークンを発行してセッションに登録し、
かつPOST送信をし、確認画面でセッションに保存されたトークンの値とPOST送信されたトークンの値が同じかどうかで
画面遷移が正しい順番で行われているかを管理します。
つまり、入力→確認→入力画面という正しい遷移であれば、トークンは常に一致しており、
これによって一連の同様の処理の流れであることを認識できるようになります!

二重登録を防ぐだけでなく、今まではURL窓に「mypage_confirm.php」と入れちゃえば、
入力必須のデータが入っていなくても移動できてしまいましたが
それも防げるようになりました。

まだ理解としては半分ぐらいなので、内容に自信がありません・・・。

インプット:リーダブルコード(2章)

今まで、変数名や関数名は、それっぽい英語から命名するだけで、
その名前からいかに情報を伝えるかなんて、考えていませんでした。
自己学習だから、一人で開発することを前提にして
進めてしまっていたからですね・・・。

でも!実務になったら、他者がいるのは当たり前。
他者を意識したコードって、処理の内容が分かりやすい!無駄がない!
というコードだと思っていました。
しかし、名前付けが、他者を意識したコードへの大きな第一歩と言えますね!


第2章では、適切な名前を付けるには、
・語彙力
・名前を付ける変数や関数の役割に対する理解力
・他者への意識(誰からみても適当な名前か?)
が必要だと学びました。



例えば、わたしのポートフォリオからすぐに発見したこの2つ!


①getFoodInfo()
②getAllerginFood()


めっちゃ似てる!!(笑)
どんな違いがあるか分かりますか?


①は、すべてのアレルギー成分(14種類)をDBからとってくる関数です。
一方②は、ログインユーザがアレルギーをもっている成分を含んでいる献立を引っ張ってくる関数です。
ちょっと②の文は修飾語が多くて、分かりにくいですね・・・
(ちなみに、被修飾語は「献立」です!)
②の関数は、具体的には、
大豆が食べられない生徒に対して、大豆が入っている献立を知らせるための関数です。
こうやって考えると、①と②ではとってくるデータの中身が結構違いますね。


名前を付けるために、まず、各関数のポイントを考えると
①は、・DBから
   ・すべての
   ・アレルギー成分をとってくる
だから、getAllFoodComponentsFromDB とか?

また、②は、 ・DBから
       ・ログインユーザのもつ食品アレルギーと一致する
       ・すべての献立をとってくる
だから、getLoginUserAvoidAllMenusFromDB ????

本には、短くて情報が不足している名前よりは長い方が良いって書いてあったけど
これはどうなんだ??
長いと逆に読みづらくなる可能性もあるし、
名前付け初心者のうちは、実際に他の人にみてもらって
他者視点を養っていきたいと思います!


今回は以上2つを取り上げましたが、
全体的に変数名や関数名にFoodを多様していることに気づきました。
そのFoodは、献立なのか、食物成分のことなのか、を分けて、
さらに、それぞれを表す単語を統一する必要がありますね。