Re:Tepa の企画からリリースまで

先日リリースした Re:Tepa の立ち上げからリリースまでの流れをご紹介します。

開発に至るまでの経緯はこちらで書いています。→

ちなみにRe:Tepa の開発環境は以下の通りです。

言語:JavaScript (TypeScript) フレームワーク:Electron、Vue (vue-cli) フォーマッター: Prittier リンター: eslint ユニットテスト: Jest e2eテスト: Spectron ビルド:Electron-Builder (テストやビルドなどは vue-cli-plugin-electron-builder を利用しています)

エディター: Visual Studio Code OS: Windows10 Pro

リリースまでの流れ

  • 技術選定
  • コンセプト
  • スケジュール
  • デザイン
  • 設計
  • 実装
  • テスト
  • ビルド
  • サイト作成
  • 配布 (リリース)

実装以降の内容は具体的なノウハウとかが書けそうなので別記事で書くとして、今回はさらっと触れる程度に留め、それ以外の工程を中心に書いていきたいと思います。

技術選定

技術選定、すなわち何を使って作るか。言語やフレームワーク、主要なライブラリーなどを調査して、決めていきます。

今回はベースとなる TepaEditor があり、作るものがデスクトップ向けのテキストエディターというのが決まっているので、それにあわせて決めていくことになります。

TepaEditor を引き継いで Delphi での開発も検討しましたが、情報量や開発環境としての活性度などを考慮して見送り。やはりいま一番使い慣れている TypeScript + Vue での開発としました。

デスクトップアプリ用のフレームワークは Vue を組み合わせての開発なので無難に(?) Electron を採用。 対抗馬だと React Native や NW.js、Cordova あたりでしょうか。

monaco-editor は今回のチャレンジ部分。情報量やサンプル量、扱いやすさで AceEditor、個人的な使い勝手の良さから CodeMirror を検討しましたが、普段使っているという信頼性の高さと開発の活発さ、逆に日本での情報量の少なさからあえて採用してみることにしました。

コンセプト

次に、作るもののコンセプトを考えます。

ビジネスだと商品の強みや方向性を決めるための大事なプロセスですが、趣味のレベルならコンセプトであればそこまで重く考える必要はないかもしれません。それでも何かボンヤリとでも置いておくと、良い意味での "縛り" が生まれるので良いと思います。

趣味の開発だと自分の好き勝手作れてしまうので、どんどん方向性が変わっていってしまいがちです。そして、油断するといつまでも開発を続けてしまい、いつまでたっても完成しない、なんてことも。そこにコンセプトという縛りを入れることで、どこまで作るかという線引きや、方向性が変わってきてしまった場合の軌道修正の目安とすることができます。

もちろん、その先のビジネスを見越してきちんと考えるのもよいですが、考え過ぎて進まないよりは先に手を動かしてしまった方がよい場合もあるので、そこはバランスで。

今回の Re:Tepa のコンセプトは次の 3つ。なんとなくいつも 3つ決めるようにしています。

  • Re: (ReMake, ReBuild, ReStart) →先に挙げた記事でも書きましたが、タイトルの Re が方向性を決めていて、一からの作り直し=過去に捕らわれない形で作ることにしています

  • 普段使い →テキストエディターというとプログラミング向けの用途にフォーカスしがちなので (前身の TepaEditor もそうでした。) そうではない用途をメインにするべく、普段使いできるエディターを目指していきます。

  • 見ただけで使える →プログラミング向けになるとどうしても高機能になって、設定や画面なども小難しくなってしまうので、なるべく直感的に、見ただけで使える UI/UX を目指します。

スケジュール

これも納期があるわけではないので (ないよね?) 縛りのようなものです。

今回は令和元年にはリリースしたいという目標があったので、最低限の機能セットで作ることにして大まかに約 1か月ほどの見積もりで 11月下旬にリリースを設定。

ただ、実際に進めていくと、monaco-editor の扱いで難航。ほかにも仕事の影響があったり、完全に同時並行で別のものを作り出してしまったりで徐々に延びて、最終的に 12月20日リリースとなりました。 (とはいえ、実質的な工数でいうと 1か月ちょいなので、当初の見積もからそこまで大きくはずれていませんでした。)

デザインの作成

デザインやロゴ、アイコンの作成はすべて Adobe XD で行っています。

Illustrator よりも手軽にベクトルデータを扱えるので、最近はもっぱら XD ばかりです。(凝ったものを作る時は Illustrator ですが...)

ロゴができるまでいじくった様子です。

なんとなく直線の組み合わせを比率で変えてみたり、R を書こうとしたけど曲線の表現がうまくいかなそうなのでやめたりしていたら、四角形と対角線で Re が表現できることに気付き、これをちょっとずらしたら上にシフトしていくイメージの 2重の三角形を表すことができてよさそう。これを画面の左におけば、最初に頭の中で浮かんだイメージ「画面の左上に斜めの要素」ができるとなって、今の形に収まりました。

そして画面のデザイン。

右側にドキュメント一覧を配置するというイメージはあったので、それを元にレイアウトを決めていきました。

ツールバーは必要最小限、検索窓も最近の (一周回って古くなりつつありますが) Web やアプリの流れに合わせて右上に配置してみました。

ちょっと通例と違うのは、新規作成とファイルを開くの場所。これはドキュメント一覧に作用する要素なので、ドキュメント一覧の上に配置しています。

そしてツールバーに配置しているのは今開いているドキュメントに作用する機能のみ、という整理です。(なので保存ボタンはツールバーのままです。)

メニューは最初は一般的なアプリメニューとしてタイトルバーの下に配置する形をとっていましたが、これもドキュメント一覧と同じ位置にして切り替える形にしました。

一般的なメニューは一回触ると閉じてしまうので、同じ操作を繰り返したい時に開きなおさなければいけなかったり、直前に行った操作がなんなのかがわかりにくかったりという点に不満があったので、この形に出来たのは自分の中では満足しています。が、実際に使われてみたらどうか、ですね。

設計

単純な Vue アプリケーションだけで見れば、Vuex に乗っかってコンポーネントを組んでいけばいいので楽ですが、今回はそれが Electron に乗っかり、かつ、monaco-editor という Vue の枠組みから外れた独自の世界が存在するため、ちょっと複雑です。

electron はともかく、monaco-editor はドキュメントや外部の情報量が少ないのでソースコードを掘り進めていく必要があり、構造を把握するのに四苦八苦。(そして気が付くと VSCode の世界にいたりして。)

最終的にはざっくりと以下のような構成になりました。

大まかな流れとしては UI からは Action または Command 経由で機能を呼び出し、Command が Service とやり取りして機能の実行、データを更新を行い、それを vuex 経由で UI に反映という流れになっています。(Command、Action は monaco-editor 内部にも存在しますが、それとは別物です)

実は当初、エディターエンジンの差し替えを考慮してエディター周りを抽象化させるレイヤーを挟もうとしていたのですが、取り回しが複雑になってしまう上にコード量が膨らんでしまいそうな気配がしたため、一旦見送ることにしています。

Action と Command の違いは、ユーザーが直接操作するかどうか。ユーザーが直接操作して呼び出すことができる機能の単位が Action で、これはメニューやツールバーのボタンなどがトリガーとなって呼び出されます。ただ、ここでは直接処理は行わず、Command のメソッドを呼び出す形にしてます。ちなみにこの Action は Delphi (のクラスライブラリー、VCL) に存在していた TAction を移植したようなものになっています。

Command は各種処理を実行できる単位でまとめたもの。 ユーザー操作が伴わない処理 (主にエディターの文字入力のような内部イベントがトリガーとなる処理) は UI から直接呼び出されることもあります。

Command からは各機能ごとに分かれた Service を呼び出し、実際の処理を行います。 Electron との IPC やネイティブコードの呼び出しなんかも Service が行います。ただちょっとこの辺りは体系づけられていなくて、Commandリッチになってる感があるので、もう少し整理が必要。

あとは処理結果を Vuex に渡して UI を更新、というのが一連のサイクルとなっています。 (ちなみに Vuex のアクションも Command 経由に統一。)

要は Vue (Vuex) のサイクルに Action、Command が挟まった形ですが、このレイヤーが Vuex と monaco-editor、Electron という異なる世界観の間の橋渡しを行うことで、うまく連携が行えるようになっています。

こうして振り返ってみると、実は TepaEditor の構成と同じような形になっていて、手癖のようなものを感じます。

実装~リリース

あとは粛々と設計に従ってテストを書きながら実装を進めていきます。

Electron と monaco-editor については、本格的に利用するのは今回が初だったので、利用方法を調べながらの開発となりました。

monaco-editor はドキュメントがあまり豊富ではないので、github 上のサンプルや issue、Stack Overflow での質問などを頼りつつ、最終的にはコードを掘っていくことになります。といっても、monaco-editor 単体としてのプロジェクトは存在せず、Visual Stadio Code と一体化しているので、気が付くと VSCode の処理を見ていたり、必要な部分だけを切り出そうとするといろんなものを引っ張ってくる必要があったりと、コードを辿るのも一苦労。最終的には必要最小限の機能を呼び出して拡張していく形をとっています。

一方の Electron は、ドキュメントもサンプル付きで揃っていて、まだあまり凝ったことをしていないこともあって特に躓くこともなく、スムーズに実装することができました。ただ e2eテストで Spectron を動かそうとウィンドウを無限に開く問題が発生し、Electron 6 では回避用パッチで逃げられたものの、7 にすると問題が再発してしまったため、今回は一旦 6 を用いています。

ちなみに普段の開発では WSL 上の Ubuntu を VSCode のターミナルから使っているのですが、今回は Electron 環境なので、VSCode のワークスペース設定でターミナルを Windows PowerShell に変更して使用しています。

まとめ

普段も大体このような流れで作っています。今回はデスクトップアプリでしたが、モバイルアプリ、Webサービスとかでも流れは同じようになるかと思います。

これがビジネスになると、コンセプト作成の部分が要件定義になったり、設計の部分が膨らんだり、チームでの開発環境を整えたり...と、もっと工程が膨らんでいきますが、趣味の個人開発はこのくらい気軽に進めていくのがよいのではないかと思います。

以上、よろしくお願いします。