awyaki portfolio

LLog詳細ページ

February 23, 2024

最終更新:February 23, 2024

アプリ制作に至った経緯

まず、筆者自身が「学習したことをタイミングよく繰り返し復習すること」が苦手であるという課題を抱えていました。

筆者はかなり好奇心が旺盛でいろんなことを並行して勉強してしまう傾向にあります。特に一度勉強したことを復習するよりかは自分にとって新しい知見を得ることが楽しく優先してしまいがちです。「これではよほど記憶力がよくない限り勉強したことがなかなか定着しない」ということは日々感じていました。特に試験などという強制的に復習を促すシステムがない独学ではなかなか復習をする時間をとりづらいということがありました。

そこでこのような復習をすることに関する自身の課題感から『独学大全』という書籍を購入し、なにか参考になる方法はないか探しました。

そこで出会ったのが「ラーニングログ」という方法でした。ラーニングログとは「手帳などに勉強範囲に対応するブロックを書き、勉強したらそのブロックを塗りつぶしていく」という方法で学習の進捗を記録し、その道のりを振り返るのに活用するというものでした。

この方法に出会ったとき「この方法で学習することをアプリでサポートできないか」と思い至りました。アプリで「ラーニングログ」を作れば学習を記録すると同時に「記録から復習のタイミングを自動で計算し知らせる」ということもできより強力に学習をサポートできるのではないかと考えました。

以上が LLog を作成するに至った経緯です。

主な機能と使い方

現在 LLog には主に次のような機能が実装されています。

以下では LLog を使用するための一連のワークフローと共に用語の解説をしていきます。

1. コンテンツを作成する

「コンテンツ」は LLog 内で学習の進捗を管理するための最も大きな単位です。基本的には一つの書籍を一つのコンテンツに対応させることで書籍の学習状況を管理するという使い方が想定されています。(必ずしも書籍である必要はありません。ネット記事などをコンテンツとして管理しても問題ありません。)

例えば筆者は最近"Computer Systems: A Programmer's Perspective"という書籍を購入したので、LLog を使ってこの書籍で学んだことを記録していきたいと考えました。このように考えたタイミングがコンテンツ作成のタイミングです。

コンテンツ作成UI

上の画像のようにコンテンツを作成する際には「コンテンツのタイトル」と「作成するブロック数」を入力することが求められます。

ここで「ブロック」とは LLog において学習の進捗を管理するための最も小さな単位であり、コンテンツを書籍に対応させた場合はページに対応させる使い方ができます。

例えば"Computer Systems: A Programmer's Perspective"は合計で 2568 ページありますので 2568 ブロック作成します。ページとブロックを一対一で対応させることで 1 から 10 ページ学習したときには「1 から 10 ブロック学習した」ということを LLog に記録することができます。もちろん対応関係をページにする必要はありません。ページに対応させる他にも「章を 1 ブロックに対応させる」という使い方もできます。

以下の画像はブロックを俯瞰で見るための画面のスクリーンショットです。後で詳しく説明しますが、ブロックの色の濃淡を見ることで優先して復習すべきブロックがわかるようになっています。

ブロックを俯瞰してみるためのUIの画像

2. ノートを作成する

コンテンツを作成すると下の画像のような UI を使用してノートを取ることができるようになります。このノートはマークダウン形式で記述できます。ノートはブロックと結びつけることができ「どの範囲を勉強したのか」という情報を持たせることができます。以下のスクリーンショットのノートでは 247 番目のブロックが登録されています。

ノート作成画面の画像

ノート作成画面の画像

3. ログを作成する

ノートを取るとそのノートの内容をもとに「ログ」を作成することができるようになります。ログを作成することで LLog の学習進捗管理機能を最大限活かすことができます。ログは「学習の記録」であり「学習した範囲・内容と共にその学習をいつ行ったかを記録するもの」です。

ログを作成すると元となったノートに登録されているブロックの「レベル」が最大の 5 に変更されます。ブロックのレベルは 0 から 5 の 6 段階ありレベルがあがるほど「そのブロックに対応する内容を記憶している可能性が高いこと」を示しています。

ログの作成はノートを取った直後に行うものなのでその内容を記憶している可能性は高いはずですからログの作成直後にはブロックのレベルが最大になるということです。

4. ログを使って復習をする

Logs ページでは今まで作成した全てのログを見ることができます。このページではログとそのログのブロックのレベルを俯瞰して見ることができるようになっています。ログ作成時にはレベルが 5 だったブロックは時間経過とともにレベルが下がるようになっており、「レベルが低いブロックを持つログの内容は復習を優先的に行うべきである」ということを意味しています。

このページでどのログを復習すべきかを確認したらそのログの内容を復習します。ここでポイントなのはログから新しいログを作成することができるということです。ログの内容を復習してログ作成ボタンを押すと同じ内容でログが作成されブロックのレベルは最大になります。

Logsページの画像

なおブロックのレベルの下がり方は「そのブロックを何回学習したか(そのブロックを含むログを何回作成したか)」に依存しています。1 回だけしか取り組んでいないブロックはレベル 5 から 1 に下がるのに 1 日しかかかりませんが、2 回取り組んだブロックはレベル 1 まで下がるのに 3 日かかります。取り組み回数が増えるほどレベルが下がるまでの時間が長くなるという仕組みです。(レベル 0 は「まだ取り組んでいない」という意味なのでレベルが下がるのは 1 までになります。)

基本的にログを中心に使うことで学んだことを復習していくような使い方になるかと思います。

以上が LLog の大まかな使い方の説明です。

使用技術とその選定理由

LLog のプロジェクトは 「React と TypeScript を中心に昨今の Web フロントエンド開発で使用されているライブラリ、言語、ツールなどの使い方を学ぶ」という目的がありました。また、以前から React を勉強しており、より実践的、本格的な形式で使い方を学ぼうというのも目的の一つでした。 したがって、まず第一に利用しようと考えていたのは React と TypeScript でした。他の技術に関しては React と TypeScript を使用することを念頭に、React と TypeScript と相性がよく初学者でもサポートが受けやすい技術かどうかという視点から選定を行いました。

こだわり

UI のこだわり

『誰のためのデザイン? 増補・改訂版 認知科学者のデザイン原論』で学んだことを念頭に UI の設計を行いました。具体的にこだわった部分やその背景にある思考などは拙著『個人開発アプリとその UI デザイン』をご覧ください。

特に自分的にこれは面白い設計だと考えているのは『ログ作成のときにログのタイトルを必ず要求する』という設計です。先述した通り LLog は「ノートを取りログを作成する」という流れで使用されます。ログ作成時にログのタイトルを要求することで強制的に学んだ内容を抽象化させることで記憶に残りやすくなると考えこのような設計にしました。

ソフトウェア設計と実装のこだわり

LLog 開発前には Atomic Design を試しうまくいかなかったということがありました。Atomic Design では UI コンポーネントの小さい順に atoms、molecules、organisms、templates、pages などと分類してコンポーネントを整理しようという方法でした。しかしながら「コンポーネントの大きさでの分類する」というのは分類のための分類であり、ドメインの関心とはほとんど関係のない分類になっているように思いました。

このような背景から LLog では Atomic Design を採用せず、自分でディレクトリ設計を手探りで試すことにしました。ここで試したのは以下のようなディレクトリ設計です。(後に『反省点・改善すべき点』言及するようにこの設計がベストだとは考えていません。)

components/
    Component1/
        index.tsx
        styles.ts
        hooks/
            ...
        # Components1を構成するコンポーネントをcomponentsに格納する
        components/
            Components1-1/
                index.ts
                styles.ts
                ...
    Component2/
        ...
layout/
    Layout1/
pages/
    Page1
    Page2

上述のように筆者は「分類のための分類」に違和感を持っていたため LLog では「分類のための分類」を極力排し責任ごとに分類することにしました。また 「コンポーネントはさらに複数のコンポーネントから構成される」という構造をそのままディレクトリ構造に反映させました。これにより「このコンポーネントはどの分類か」を考えることなくコンポーネントを作成できるようになり、また、どのコンポーネントがどこにあるか予測しやすくなると考えています。

反省点・改善すべき点など

ディレクトリの設計

React のコンポーネントの整理の仕方に迷いました。特に renderer ディレクトリ直下の components ディレクトリには雑多なコンポーネントが特段整理されずに入り乱れる巨大なディレクトリになってしまいました。Icons があるのに兄弟に CloseIcon があったり、ルールが決められておらずどこに何があるのか予測しづらい設計になっているように感じます。「関心の分離」を徹底することで、機能のまとまりごとにコードを整理していくのが良いのではないかと考えています。

例えば、Notifier コンポーネントと NotifierContextProvider はユーザーがログの作成やノートの保存などの操作を行ったことを通知する機能を提供するものですが、二つのコードは components ディレクトリ直下に他のコード(ContentMenu や Forms など)と一緒に置かれています。Notifier と NotifierContextProvider は互いに強く関係するコードなので、それを示すためにも二つのコードはさらに細く分類された notifer ディレクトリに格納するのがよいかもしれません。また、機能と純粋な UI パーツを分ける意味で features ディレクトリ、ui ディレクトリを作ると良さそうだと感じました。

// 現状のディレクトリ構成
renderer
    // componentsという括りにあらゆるコンポーネントが直接置いてあるのは大雑把すぎる
    components
        CloseIcon
        Forms
        Header
        Notifier
        NotifierContextProvider
// 改善案
renderer
    // 純粋なUIとアプリの機能でディレクトリを分ける
    features
        notifier
            Notifier
            NotifierContextProvider
        Forms
    ui
        icons
            CloseIcon
        Header

コメント、issue の書き方

プロジェクト初期の頃に書き出した issue について、情報量が足りず後から見返して何を言っているのかわからないということがありました。改善案を以下に書き出します。

コードフォーマッターの導入と設定

このプロジェクトの後にグローバル環境に Prettier を導入しました。その結果、LLog のコードに変更を加え保存するごとにフォーマットされてしまい。コードが中途半端にフォーマットされてしまうことになりました。今後のプロジェクトでは初めから Prettier などのコードフォーマッターを導入するのがよいと感じました。

テスト

今回のプロジェクトではテストを書いていません。現状大きな仕様変更やリファクタリングを行っておらず、ソフトウェアが壊れるといったことはありませんが(テストを書いていないので壊れていることが検知できていない可能性はあります)、今後行う予定のリファクタリング作業で「テストを書けばよかった」と実感するのではないかと考えています。今後、リファクタリング作業と合わせてテストコードを追加していきたいと考えています。

追記:2024/3/5 に ESLint および Prettier を導入し、すべてのコードにフォーマットを適用しました。

今後やりたいこと

今後はまず開発環境のアップデートを行いたいと考えています。現在、モジュールバンドラーとして Webpack を使用していますが、これをより高速であるとされている Vite に置き換える作業を行うつもりです。実際にどれくらいビルド時間が改善したのかパフォーマンスの計測も同時に行いたいと考えています。

追記:2024/3/26 Webpack から Vite へのリプレイスが完了しました。今後はリファクタリングを行う予定です。また、ページング機能を新たに実装したりノート検索機能を強化していきたいと考えています。

主なアップデートの記録

以下は Webpack と Vite でそれぞれ 5 回ビルドを行ったときビルドにかかった時間の平均値です。

WebpackVite(electron-vite)
16430 ms4028 ms

ソースや最終的なビルド結果が異なるため単純に比較することはできませんが約 4 倍の改善となりました。