0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python / Flask】TDDとGitHub Actionsで構築する、Mac System 7風レトロ英語タイピングアプリ開発記

0
Posted at

1. はじめに

約30年前に親しまれていたMac版『Typing Tutor』のオマージュとして、レトロな世界観を持ちつつモダンな開発手法を取り入れた英語タイピング学習Webアプリケーション「Typing Tutor」を自作しました。

本記事では、ただタイピングアプリを作るだけでなく、テスト駆動開発(TDD)による堅牢なバックエンド実装からGitHub Actionsを用いたCI(継続的インテグレーション)パイプラインの構築、そしてCSS変数を用いた90年代Mac(System 7)風UIテーマの実装までの流れをまとめています。


2. アプリの概要と技術スタック

主な機能

  • リアルタイム打鍵判定 & WPM/正確率計算: ミス時に止まる Strict モードと、そのまま進む Free モードに対応。
  • レトロ&モダン UI テーマ機能: 90年代クラシックMac(System 7)風デザインとModern Darkテーマのワンタップ切り替え(localStorage 保存)。
  • オンスクリーンキーボード & 指位置ガイド: 次に打つべきキーと推奨する指の位置をリアルタイムでハイライト表示。
  • 練習スコア履歴(Practice History): 過去のタイピング結果(WPM、正確率、日時)をブラウザ内に自動記録。

技術スタック

  • バックエンド: Python 3.11+, Flask (RESTful Web API)
  • テスト / 品質管理: pytest, GitHub Actions (CI)
  • フロントエンド: HTML5, CSS3 (CSS Variables), JavaScript (ES6+, Fetch API)
  • 開発環境: PyCharm (venv)

3. テスト駆動開発(TDD)によるバックエンド設計

アプリの信頼性と品質を高めるため、コアロジックはすべて pytest を用いた TDD(テスト駆動開発)プロセスで実装しました。

① 課題テキスト管理(app/text_manager.py)

レベル(1: ホームポジション / 2: 単語 / 3: 英文)およびカテゴリ(デフォルト / IT用語 / 名言)に応じたテキストをランダム取得するロジック。

② 打鍵判定エンジン(app/evaluator.py)

Strict モード(誤打鍵時にインデックスを進めずエラーカウント)と Free モード(誤打鍵でも進行)を判定するコアロジック。

# test_evaluator.py のテストケース例
def test_evaluate_strict_mode_correct():
    result = evaluate_keystroke("python", 0, "p", "strict")
    assert result["is_correct"] is True
    assert result["current_index"] == 1
    assert result["is_completed"] is False

③ スコア計算モジュール(app/calculator.py)

入力文字数・エラー数・経過時間から WPM (Words Per Minute) と正確率(Accuracy %)を正確に算出するロジック。

全モジュールの単体テストおよび Flask API(app/api.py)の統合テストを作成し、ローカル環境で全テストケース(15件以上)のパス(PASSED)を確認してからフロントエンド開発へ移りました。

4. GitHub Actions による CI パイプライン構築

コードを GitHub へ push するたびに、自動的にクラウド環境上で pytest が実行される CI パイプラインを構築しました。

.github/workflows/test.yml を配置し、Python 3.11 環境のセットアップから依存ライブラリのインストール、全テスト実行までを自動化しています。

name: Python Test Suite (CI)

on:
  push:
    branches: [ "main", "master" ]
  pull_request:
    branches: [ "main", "master" ]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - name: Check out repository code
      uses: actions/checkout@v4

    - name: Set up Python 3.11
      uses: actions/setup-python@v5
      with:
        python-version: "3.11"
        cache: 'pip'

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

    - name: Run pytest test suite
      run: |
        pytest -v

これにより、手元のコード変更によって既存機能が破損していないか(デグレが発生していないか)を常にリポジトリ上で可視化できるようになりました。

5. フロントエンドUI & レトロテーマの実装

バックエンド API と連携するフロントエンド(index.html, style.css, main.js)を構築しました。

① CSS変数による System 7 レトロテーマの実現

style.css 内で :root のモダンテーマ変数に加え、[data-theme="system7"] 用のスタイルを定義。モノクロ調の色使い、カチッとした黒枠線、Chicago/Genevaフォント風の装飾を適用することで、90年代MacのGUIを忠実に再現しました。

[data-theme="system7"] {
    --bg-color: #7f7f7f;
    --card-bg: #dddddd;
    --panel-bg: #ffffff;
    --text-color: #000000;
    --font-family: 'Geneva', 'Chicago', 'Monaco', monospace;
}

[data-theme="system7"] .container {
    border: 2px solid #000000;
    box-shadow: 4px 4px 0px #000000;
    border-radius: 0;
}

② オンスクリーンキーボードガイド

入力対象の文字に応じて、リアルタイムで画面上の該当キー要素を検索し、next-key クラスを付与して強調表示。併せて推奨する指の位置(Left Index など)を表示する学習サポート機能を実装しました。

③ localStorage を活用した履歴機能

タイピング完了時、APIから計算・取得した WPM と Accuracy を localStorage に保存。過去の練習記録(最大20件)をテーブル形式で描画・管理する機能を構築しました。

6. おわりに

単なるUI構築だけでなく、TDDによる設計・テスト実装 ➔ CIによる自動化 ➔ APIと連動するフロントエンド構築 という一連の開発サイクルを回したことで、非常に保守性の高いプロダクトとして完成させることができました。

今後は成果物のデスクトップアプリ化(PyInstallerやElectron)や、タイピング結果のグラフ可視化なども視野に入れてアップデートを続けていきたいと思います!

GitHub Repository: mysweetlatte201051/TypingTutor

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?