# インターンシップ開発体験:別紙 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 ``` 以上