---
# System prepended metadata

title: インターンシップ開発体験：別紙 v3.5　移植プロジェクト

---

# インターンシップ開発体験：別紙 v3.5　移植プロジェクト

## rails→springの移植をしてみよう

開発に利用する言語やツール、フレームワークなどは、
- 参加するプロジェクトのメンバーや、組織の都合
- 用途への親和性

などで、決定されると思います。

開発体験のテーマとなっているアプリは、
- 過去の開発者が慣れ親しんだ言語、フレームワークであったこと
- 開発体験という目的を考慮すると、変更の反映確認が容易であること、文法が容易であること

といった理由から、rails、rubyが選定された、という背景があるとします。

ここで今回の開発体験では、
- 今回の担当メンバーがJavaの方が慣れている
- 現在の組織として、railsよりもspringを利用して開発体験はできないか検討したい

という状況、方針が出たとして、移植プロジェクトをやってみましょう。

---

### デモ

https://moneta3-5-rails.onrender.com

https://moneta3-5-spring.onrender.com

＃renderは無料枠だと、月間利用時間上限があり、上記デモは月の後半は停止してしまいます。その場合はソースから動作確認してください。

### ソース

https://github.com/monetstdev/moneta3.5

https://github.com/monetstdev/moneta3.5-spring

---

現状、移植プロジェクトのメンバーがデモの状態まで進めているようです。

- 移植プロジェクトの要件は、見栄え、ユーザ体験は一切変更しないこと。
- 取り敢えずsprigの移植先アプリは、紙芝居確認として、DBや業務ロジックは移植せず、見栄えを完全踏襲して画面遷移できるかを途中まで確認済。

上記のように報告を受けたのですが、果たして本当にちゃんと完全踏襲できているのでしょうか？
何をもって確認済としたのでしょうか？

間違い探しのように、見栄えが変わってしまっている箇所がないか探してみましょう。
また、目で見て探すのは、人間誰しも間違いや見逃しはあると思うので、何かしら機械的な検証ができないかも検討してみましょう。

## 移植の流れ

一般的に、言語やフレームワークを移植するとなると、色々と付随して検討、対応することが出てきます。

- 目的と完了の定義：何故移植する？今のままでは何がだめ？移植するとして、不具合温存の有無、機能同等か改修含むか。
- スコープ境界：何を移植し、何は残置/廃止/後回し？
- 非機能要件：性能目標、可用性、監視、運用。
- 切替方式：一括切替 / 段階切替
- データ移行方針：一括移行 / 段階移行 / オンライン移行など。

大まかな流れは例えば以下のような感じに考えられます。
1. 現状把握
2. 移行設計（機能/データ/非機能）
3. 骨格実装（ルーティング・認証・ORM・テンプレ）
4. 機能移植（小さな単位で反復）
5. テスト、リハーサル
6. データ移行、システム移行
7. 切替・監視強化・フォールバック

今回の移植先アプリは、上記ステップで言えば、3番途中、という状況です。

## アプリケーションの移植なら基盤は無関係？

アプリケーションの要件を満たすために基盤が設計、構築されるので、
例えば今回の場合、puma、sqlite、tomcat、postgresなど、関係する複数のAPサーバ、RDBMSの理解が必要になってきます。
他にも、今回はデモを公開するのにrenderというサービスを利用しています。こういった「アプリケーション以外」についての理解、対応が必要になります。

アプリケーションの移植なら基盤は無関係か？
そんなことはなく、ちゃんと要件を満たすことができるか、どうすれば良いか検討、設計、構築が必要です。

### 移植元アプリの思想は？
readmeより抜粋
```
# 改修の目的
- 初学者を想定し期間が短いことから、バッドプラクティスであってもコードの追いやすさ、理解しやすさを重視

# 3.0からの修正点
- htmlを使用（slim使わず、formタグ含めヘルパ使わず）
- パーシャルによる画面や部品の共通化を使用しない
- CSSファイルによるデザインの共通化は行わない。tailwind cssの標準項目のみ使用し、タグに直接記載する。
- ルーティングはベタ書き（resource等、ヘルパ使わず）
- モデルにコードを書かない
- コントローラに処理を全部書く
- コントローラのライフサイクル系、バリデーション系のヘルパを使用しない
- フロント処理のjavascriptは利用しない
```

詰まり、意図的にアンチパターンであっても、

- ファットコントローラのアーキテクチャとしている
- DRYとしていない

など、方針があって現在の実装となっていることが分かります。

## 図表

### mvcイメージ
```mermaid
%%{init: {'theme':'neutral'}}%%
flowchart TD

Client[Webブラウザ<br/>（ユーザー操作）]

Controller[Controller<br/>コントローラ<br/>処理の仲介]
Model[Model<br/>モデル<br/>データ・業務ロジック]
View[View<br/>ビュー<br/>画面の見た目]

%% フロー
Client -- リクエスト送信 --> Controller
Controller -- データの読み書き --> Model
Model -- データを返す --> Controller
Controller -- 表示内容を渡す --> View
View -- HTMLレスポンス --> Client
```

### ファットコントローライメージ
```mermaid
%%{init: {'theme':'neutral'}}%%
flowchart LR
  subgraph Client[クライアント]
    B[Webブラウザ]
  end

  subgraph Server[アプリケーションサーバ]
    R[Router / ルーティング]
    C[Controller / コントローラ]
    V[View,テンプレートエンジン]
  end

  subgraph Data[データストア]
    D[(RDB / NoSQL / ほか)]
  end

  B -- HTTPリクエスト --> R --> C
  C --> D
  C --> V
  V -- HTMLを生成 --> B
```

### 移植デモ環境イメージ
```mermaid
%%{init: {'theme':'neutral'}}%%
flowchart TD

subgraph Browser[Webブラウザ]
end

Browser --> C_Rails
Browser --> C_Spring

subgraph Rails["Ruby on Rails @ Render"]
  C_Rails[Controller<br/>app/controllers/*.rb<br/>例: users_controller.rb]
  M_Rails[Model<br/>app/models/*.rb<br/>例: user.rb, kouza.rb]
  V_Rails[View<br/>app/views/**/*.html.erb<br/>例: users/top.html.erb]
  DB_Rails[(DB<br/>ActiveRecord + schema.rb)]
end

subgraph Spring["Spring Boot @ Render"]
  C_Spring["Controller<br/>@Controller クラス<br/>例: UsersController.java"]
  M_Spring["Model<br/>@Entity + Repository<br/>例: User.java, Kouza.java"]
  V_Spring[View<br/>Thymeleaf<br/>src/main/resources/templates<br/>例: users/top.html]
  DB_Spring[(DB<br/>JPA/Hibernate + import.sql)]
end

%% Railsの流れ
C_Rails --> M_Rails --> DB_Rails
C_Rails --> V_Rails

%% Springの流れ
C_Spring --> M_Spring --> DB_Spring
C_Spring --> V_Spring
```

### ここまで利用した環境イメージ
```mermaid
%%{init: {'theme':'neutral'}}%%
flowchart TD

  subgraph Render["Render (Linux + Docker)"]
    Rails_Render["Railsサーバ<br/>(移植元アプリ)"]
    Spring_Render["Spring Bootサーバ<br/>(移植先アプリ)"]
  end

  subgraph Local["手元 開発端末"]
    Browser["ブラウザ / クライアント"]
      subgraph WSL["WSL (Ubuntu)"]
        Rails_WSL["Railsサーバ<br/>(移植元アプリ)"]
      end
    end

  subgraph EC2["AWS EC2 (Ubuntu)"]
    Rails_EC2["Railsサーバ<br/>(移植元アプリ)"]
  end

  Browser --> Rails_WSL
  Browser --> Rails_EC2
  Browser --> Rails_Render
  Browser --> Spring_Render
```

以上
