Web Music の未来を創る
Web (ブラウザ) と音楽はどこまで融合できるか ? という問いにチャレンジする.
Web はコンピュータに欠かせないプラットフォームとなっており, 人間の創造である音楽とどこまで融合できるか ? また, Web Music にしかできないことはなにかを追求したい.
そのために, 3 - 5 年以内に達成することは, 以下の 2 つです.
特に, 前者においては, ソフトウェアの品質 (いわゆるきれいなコード) を実装できるスキルも必要であり, これは日常のコードレビューが最も効果高いと考えています.
よって, 仕事に求めることは以下の 2 つです.
https://nana-music.com から, リニューアル版 https://beta.nana-music.com/ の Web フロントエンドの技術選定, 設計から実装, 保守・運用をすべて一人で担当 (現在も, 機能追加, パフォーマンス改善, バグ修正など進行中).
これまでに経験したことのない最も大変なことであり, 前任者などが誰一人いなく, ドキュメントもなく, コードも断片的につぎはぎされたような状態 (リリースプロセスなどもなく, ほぼ放置状態) から, 仕様を把握して, 技術選定・設計をおこなうことでした. そのためには, 既存のコードをリーディングするには限界があり, リニューアルにあたっての MVP (Minimum Viable Product) を以下のように整理して (また, ビジネス的な理由上, 2023 年 10 月にローンチして, 2023 年 12 月末までにリニューアル版としてリリースする必要がありました), それを補完するために既存のコードや挙動をかいつまんで進めました.
また, MVP を意識して, UX 的なことは削ぎ落としたり (例えば, 検索では当初の予定では, さらにフィルタリングができる想定), デザインに時間を要するところはデザイナーと相談して簡素な UI に変更してもらう (例えば, カルーセルは横スクロールにしてもらうなど) などしてこれ以上削ぎ落とせば, nana の Web アプリケーションとして成立しないぐらいの実装コストを減らして, 実質 2 ヶ月の実装時間 (残り 1 ヶ月は QA 項目の作成, QA プロセスの主導) で MVP を実装し, リリースすることができました.
企業規模, また, 経営的にも人的リソースを確保できる状況ではないので,
上記の 2 点を意識しました. 具体的には, 既存の Web アプリケーションは Vue.js + Nuxt で実装されていましたが, 現状の Web フロントエンドの技術動向から React + Next.js の方がより枯れていると判断して, 既存資産は使うことをせずゼロベースで実装したり, API スキーマからの型生成もあくまで型定義のみを生成する薄いツール (openapi-typescript) を選定したり (クライアントコードまで生成すると生産性は向上するが, 将来ジョインするメンバーのスキルや経験によっては逆効果になりうるので), ツールで制約できないコーディング規約は作らないといったことです.
技術的理想に対して, 教条的になりすぎず, 後回しでよいことやあればよいぐらいのことはやらないようにしました.
openapi-typescript
で生成する)GMO PGマルチペイメントサービスを利用した, 各保険会社ごとの (マルチテナントごとの), Web でのクレジットカード登録・決済システムを実装
まず, クレジットカード決済に対する基本知識の習得を元に, GMO PGマルチペイメントサービスの決済フロー (例えば, 3Dセキュア2.0 対応と未対応での決済フロー (API リクエストのフローの違い) であったり, GMO が提供する SDK (クラインアント側での POST 処理の詳細の理解, 例えば, SDK では Fetch API などによる Ajax で Content-Type: application/json
による POST リクエストではなく, HTMLFormElement
による Content-Type: application/x-www-form-urlencoded
が決済フローとして実行されていることをトレースしたり, またそれに合わせて, 自社側の API 側のコードをリーディングして, レスポンスの Content-Type
を修正したり, 決済終了後の iframe
へのレスポンスから, 親フレームへの postMessage
で, 決済のウィンドウを閉じるなど, 非常に複雑な仕様を読み解きリリースまで問題なく遂行したこと, また, 一人での実装であったので, Web フロントエンドメンバーへの仕様・実装の共有をして, メンバーの誰もが, 最低限, 何を知っていればいいか, どこが実装において重要な点かを共有し, 属人化させずその後の追加対応などを他のメンバーに担当できるようにしました.
TIPSTAR のリニューアル (主に, デスクトップ版対応) にあたって, Web アクセシビリティを Lighthouse の計測で 40 から 98 まで向上させました
リニューアルに関わったメンバーは Web アクセシビリティにあかるいわけではなく, また, リニューアルも人数に対して工数がかなり多かったことから, できればこうありたい Web アクセシビリティの指摘よりは, マストな Web アクセシビリティを意識してコーディングしてもらえるように, レビューをとおして, 以下のポイントを主に重視しました.
button
を使うなど)alt
属性 (説明が必要ならつける, 隣接する場所にテキストがあったり, 装飾的な画像であれば不要)aria-label
, 装飾的な要素には role="presentation"
をつけるなど)下記のような挙動の特徴を発見しそれに対応する実装をした結果, Autoplay Policy のあるブラウザでもベストエフェオートな自動再生を可能にすることができました.
個別顧客用に新規動画プレイヤーを実装することになった案件で, 既存のプレイヤーは技術負債のかたまり (テストコードもなし) だったのでそれをそのまま使うことはせず, Storybook を利用しながら 1 つ 1 つの Vue Component の動作を確認しつつ, Atomic Design にそってリファクタリングしました. その結果, 既存のコードでは video.js にべったり依存していたのが, 容易に他のストリーミングライブラリ (hls.js など) に差し替え可能になりました.
Flux フレームワークである Flummox が開発停止になってしまい, そのままでは, React のバージョンアップに対応できないなどのリスクが生じたので, 別の Flux フレームワークを使い, アーキテクチャ刷新をすることになりました.
もっとも大きな理由は, Flummox から (Store
が複数, or 1 つという違いなどはあれ) 移行しやすいということでした. 移行のしやすさを最大の理由にしたのは, ビジネス制約上, リソースを大きく割くことはできなかったことがあげられます (実際, このアーキテクチャ刷新と同時並行して, 新機能の実装も進んでいました). 他の候補としては, MobX がありましたが, すでにあるプロダクトを刷新する (新規プロダクト実装ではない) ということから, メンテナンス性が高いという点でも Redux に分がありました (記述は MobX より冗長になりますが, その分自由度が少なく, 誰が実装しても同じようなコードになる). 実際, このメリットは大きく, リリース時期が迫るにつれ, より多くのエンジニアが参入しましたが, コストをほとんど要さずに, スムーズなジョインを可能にしました.
リリースが迫るにつれ, ディレクターやテスター (実機確認者), インフラ担当者, また, プロダクトのリブランドが最重要で動いていたこともあり, 様々な人と協調する調整力が要求されました. 結果としては, 最重要のリブランドのリリースに支障をきたすことなく, また, 既存のバグ以外は, 一切のバグなしという無事故リリースを実現することができました. また, 既存コードには, テストコードが存在しませんでしたが, Action / redux-saga (Web API との通信処理) / Reduer のテストコードも追加し, 以前よりいっそうメンテナンスの高い Web アプリケーションにすることができました.
生放送サービスに関わっていたときに, デスクトップでもリアルタイムで番組開始通知を受信できることで番組視聴数を向上させることを目的に実装. ちなみに, わたしが社会人エンジニアになってから, 1 人でまとまった機能を実装したはじめての実績となります.
Web Push に先立って, Service Worker の Cache を導入し, パフォーマンス改善, また, サービスの PWA 化などを実現しました. 特に工夫したこととしては, CircleCI でビルドされたタイムスタンプをキャッシュ対象のアセットのパスに使うことで, リリースしたときには必ず Service Worker の Cache が更新されるように自動化しました.
実装した当時は, Web Push 自体は普及初期ともいえ, ブラウザ自体にバグがあり (特に, Web Push 通知許可を求めるダイアログの表示や, 通知許可・通知拒否をしたときの挙動が必ずしも仕様に沿っていなかった. 例えば, 通知はブロックされるが, Notification.permission
の値が 'default'
(通知を許可している状態でも, 拒否している状態でもない) になるなど, 結果として, 通知状態と UI が整合しないということが最大の問題でした), それらの挙動を調べあげ, ユーザーが使用する上で問題のない, つまり, 通知状態と UI の整合が保たれた状態でリリースすることができました (FRESH! における Web プッシュ通知機能 〜実装編〜).
オーディオ技術のないエンジニアにも, ブラウザでオーディオを扱えるというコンセプトで実装し始めた Web Audio API ライブラリ. 現状, Web Audio API はある程度オーディオ処理を抽象化した JavaScript API ではありますが, (例えば, BiquadFilterNode
のようにデジタルフィルタの詳細を知らなくても 8 種類のデジタルフィルタが利用可能となっています. ところが, 本格的なオーディオ処理をするためには, 結局のところ, オーディオ技術が必要になります (例えば, フェイザーというオーディオ処理を実装するには, 基礎的なオーディオ技術をもとに, BiquadFilterNode
を組み合わせる必要があります) . XSound は, Web Audio API をさらに抽象化し,
以上 2 つを実現したライブラリとなっています. また, 将来に渡って, 破壊的な変更を最小限にできるように, ライブラリ・フレームワークに依存しない実装となっています.
XSound.app はライブラリの機能をほとんど網羅した Web アプリケーションです.
SharedArrayBuffer
の複雑な制限) や, I/O 関連の最適化は難しい. 例えば, Web MIDI API などは Working Draft のまま長い間仕様すら更新されていない). そのアイデアの試行錯誤を形にするきっかけやヒントを与えることが目的SoundModule
に必要なオーディオ処理を集約して, サブクラス (個別の音源, 例えば, オシレーターやノイズ, 楽曲データ, WebRTC からの音声など) において, 必要な処理を override, また, 個別に必要なオーディオ処理を実装 (例えば, ノイズサプレッサーなどは StreamModule
(WebRTC からの入力音をソースとするモジュール) でしか使わないので, SoundModule
では実装していない). これが基本設計であり, 結果として, テンプレートメソッドパターンになっている. 端的には,SoundModule
のオーディオ信号処理をもたせるSoundModule
のサブクラスをパース結果の音楽演奏情報にしたがって, 自動演奏を実行する (また, SoundModule
を継承しない).X
関数で取得する SoundModule
のサブクラス), 可能な限り同一の API (メソッド) を提供するsetup
(アプリケーション起動時に必要な初期化処理)ready
(再生前に必要な処理. スケジューリングなど)start
(再生)stop
(一時停止)param
(パラメータの取得・設定)module
(モジュールを取得して, アクティブ状態にしたり, パラメータを設定したりする)AudioNode
の複雑な connect
(モジュラールーティング) を抽象化する重要なメソッドSoundModule
に共通するオーディオ処理を集約して継承するSoundModule
が肥大化してしまっているので, サブクラスでボイラーテンプレートのようなコードや, ボイラーテンプレートのような単体テストがたくさんあるのは問題点としてあるAudioModule
と MediaModule
は同じような機能をもっているので, MediaModule
を AudioModule
のサブクラスにすることも考えたが, 継承の継承はさらに結合度が高くなる (モジュールの独立性が低くなる), また, 実装が増えても, アプリケーションコードには影響がない.MML
クラス)number[]
ではなく, Float32Array[]
に格納する)Float32Array[]
のトラックを, Float32Array
にフラット化/^.+Processor$/
で終わるクラスを識別し圧縮しないようにする).AudioWorkletProcessor
のサブクラスを定義して, toString
で文字列にして, Data URL で addModule
する.TypeScript など Web フロントエンド関連の技術と Web Audio API を理解しているだけではここまでの実装はできないと思う. 少なからず, オーディオ信号処理を大学院での専攻としていたことが活きている
モチベーションはその時々で変わってきたが, 12 年近く, 機能追加やバグフィックス, リファクタリングを続けて, また, Web フロントエンド技術のエコシステム (npm によるパッケージ管理, TypeScript による型システム・型検査, ドキュメントの自動生成や, ESLint による潜在的なバグの autofix など) をあわせてバージョンアップを続けてきたこと.
v1.x.x のリポジトリ のスター数と合算すると 200 を超えており, これはニッチな Web Audio API ライブラリというドメインにおいて, メジャーな部類に入ると言えます. 実際,
9 libraries to kickstart your Web Audio stuff で, 9 つの有用なライブラリの 1 つ取り上げられており,
XSound is a batteries-included library for everything audio. From basic management and loading through streaming, effects, ending with visualizations and recording, this libraries provides almost everything! It also has nice, semi-chainable API with solid documentation.
上記 2 点が評価されています.
また, 国内を代表するエンジニアの方からも評価を受けています.
* 業務での関連が高い順にソートしています