はじめに
ベータ版リリース後の次の大きな機能として、
任意テキスト音声再生機能
ユーザーがアプリでミーアに話させたいフレーズを再生時刻とともに自由に入力すると、そのフレーズを指定した時刻に音声再生する機能
を、ここ2週間開発していた。
アレクサの音声リマインドのような機能である。
実際に利用したユーザーから、下記のリクエストがきたので、拡張性も高そうだし開発しようとなった。
文言を自由にカスタマイズ&時間指定まで出来るモードが欲しいです。
学校に行く前に忘れ物がないか確認してくれるようにリマインドとして使ったり、ことわざや雑学などを入力して勉強用としても使えそうです。
当初は、1ヶ月くらいかかるだろうと想定していたものの、結果的には半分くらいの日数で開発を終えることができ(現在PRレビュー待ち)、それ自体は良かったのだが、今回大きい機能を開発してみての振り返り(マインドセットと、どう開発を進めていくのが効率的か)を備忘録として記載しておこうと思う。
実際に開発した内容:アプリで任意テキスト入力したものを音声再生
まず、実際に開発した内容を、テスト形式で記載しておこうと思う。
- 今までは、こちらが作成したデフォルトのフレーズ(5つの性格と4つの方言)からユーザーはどれか一つを選んでそのフレーズタイプに保存されているフレーズを再生できるだけだったが、アプリでミーアに喋らせたいフレーズを再生時刻とともに入力することができ、その時間になるとミーアがフレーズを話す
- 自分が作成したフレーズは公開非公開を選ぶことができ、公開した場合は、他のユーザーもあなたが作成したフレーズを取り込むことができる。Slackの絵文字取り込みのようなイメージ
- フレーズを作成したら、音声合成されるとともにフレーズの内容を元に、感情ID(喜怒哀楽その他)が付与されて、その感情にマッチする目の画像が音声再生時に表示される。
基本的には、任意のフレーズを作成するCRUD機能ではあるが、そのフレーズに対して、再生スケジュール(日時と時刻)を設定したり、公開非公開ができて、公開フレーズからの取り込みもできるようにするという点で、複雑度が上がった。
表示(Get)
・あなたのフレーズ
自分が作成したフレーズと、公開フレーズの取り込みの両方が表示される スケジュールを設定している場合には、サブテキストにスケジュールが表示される 公開フレーズを取り込みした後に、その公開フレーズを作成した他人が後から公開フレーズを非公開化した場合には、取り込んだ公開フレーズは編集できなくなり、エラー文言がサブテキストに表示される。削除はできる
・公開フレーズ
公開したフレーズが表示される。
・無限スクロール
下にスクロールすることで20件ずつスクロールされる作成(Create)
・フレーズテキストを作成し、公開非公開を設定し反映される
→user_phrasesレコードにのみ新規レコードが作成される・フレーズテキスト+スケジュールを作成
再生日時と再生時刻のどちらか片方のみを作成することはできない スケジュールを設定したら反映される。・expression_id:作成したフレーズを元に非同期でexpression_idが付与される
・voice_path:作成したフレーズを元に、非同期で音声合成されS3にアップロードされ、voice_pathが付与される変更(Update)
・フレーズテキストのみの変更 フレーズテキストを変更できる スケジュールを追加できる
・フレーズテキスト+スケジュールの変更 スケジュールを変更できる スケジュールを削除して、フレーズテキストのみ保存はできない→この場合は、一旦フレーズを削除して作り直す削除(Delete)
・フレーズテキストのみ:user_phrasesテーブルからレコードが削除される
・フレーズテキスト+スケジュール:user_phrasesテーブルとphrase_scheduleテーブルの両方からデータが削除される公開フレーズの取り込み(Copy)
・公開フレーズを取り込むことができる
・取り込んだ公開フレーズは、あなたのフレーズとして表示される。この場合、phrase_scheduleは追加できるが、フレーズテキストは編集できないデバイス(ESP32)
・スケジュールを定義したフレーズ:再生時刻にフレーズが目の表情と共に音声再生される
・スケジュールを定義していないフレーズ:話す時間のstartからendの間のtalk frequency間隔で音声が再生される。phrase type(性格・方言)と競合しないように、2分ずらして再生
実際に開発した内容の一部は、下記記事で記載した。
大きい機能を開発しての振り返り
過去にも、もしかしたら同じレベルの複雑で、かつ大きい機能開発したことがあったかもしれないが、今回開発した機能もなかなか手がかかるものだった。
まず取り掛かる
以前に、こちらの記事でも記載したが、 重たいタスクはどうしても後回しになりがちなので、重たい腰を上げてとりあえずやってみるのが重要。
このタスク、重たいなと身構えてしまっているタスクを重たく感じる理由は、タスクの見通しが立っていなかったり、実行可能な工数にまで分解できていなかったりという状態のために、全体としてなんとなく大きく見えてしまっているということがほとんどであり、実際に始めてみるとそこまで重たくなかったりすることもある。
逆に、想像以上に途中からやるべきことが増えて、重たくなるケースも無きにしも非ずだが。
集中して取り組む
他の細かい開発の方が、すぐに終わるので、仕事をやった感じがあるのだが、 すべての仕事はマルチタスクではなくて、シングルタスクでできるだけやった方が最終的な効率が良いため、今回は他の細かい開発は全て後回しにして大きい機能を集中的に取り組んだ。
途中で結構バグが出たり、進んだり進まなかったりしてなかなか大変ではあったが、一歩一歩登山している感じ。
基本的には、午前中が頭がスッキリしていてパフォーマンスが良いので、重たい開発は午前中に行い、午後も引き続き行うこともあるが、他の細かいタスクを午後行うようにした。
開発前しながら、機能とテストをブラッシュアップ
開発前にすべての設計や使用を抜け漏れなく、作成できるのが理想ではあるが、複雑な構造や処理の場合、もちろんエンジニアの力量にもよるが、最初の設計の段階で全てを見通す事は不可能に近いと思う。
ごく少数のスーパーエンジニアなら、たとえ複雑な機能だったとしても、頭の中で事前に全て思い描いて、最短距離でコードを実装できるかもしれないが、少なくとも自分はそうではないので、実際の開発を進めながら、途中で気づいた追加の機能やテストを都度追加していく形で開発した。
DB設計だけ、一緒に開発しているエンジニアと相談しながら、まず最初に決めた。
途中で気づく機能や実装にはさらに2つに分かれて
- 実際に開発するうちに、この機能もあった方がより良いのでは?と追加の機能を思いつく場合
- 最初の開発で考慮漏れだった場合
今回の場合、1つ目に関しては、途中で「フレーズに対して公開非公開をできるようにして、公開フレーズに関しては他のユーザーが作成した面白いフレーズも取り込めるようにしたら面白いんじゃないか?」となり、途中から機能追加した。
2つ目に関しては
- 作成したフレーズがたくさんになった場合、無限スクロールもしくはページング機能を追加して20件ずつ取得するように処理する
- 作成したフレーズに対して、目の表情もマッチさせないといけないので、専用のexpression_idを追加しないといけない
- フレーズだけではなく、フレーズのスケジュールを任意で設定できるようにしたため、フレーズのみ作成・フレーズ+スケジュールを作成・フレーズのみ作成して事後的にスケジュールを追加などといったケースを場合分けで想定しなければいけなくなった
などが挙げられる。
今回に関しては、最初フレーズのCRUD機能のテストコードとAPIを開発したものの、途中からフレーズスケジュールや公開フレーズの取り込みなども考慮しないといけないことがわかったので、その後は試行錯誤しながら機能開発を進め、その後動作確認をして想定しうるすべてのパターンをクリアしたのちに、コードをリファクタするとともに、最後にテストコードを仕上げるという流れになった。
まとめ
今後も同じレベルの、もしくはそれ以上の重ための開発が出てくると思うが、その時に、この記事を振り返って、「後回しにせず、午前中に集中的に取り組み、開発しながら当初の考慮漏れも都度潰していく」ようにしたい。