RubyエンジニアがJavaを学んでみた

# はじめに
今までRuby（Rails）を中心に開発していたのですが、Java（SpringBoot）をキャッチアップし始めたので、その所感について発信します。
言語・FWの違いは色々なサイトで紹介されているので、今回は実体験ベースで書いていきたいと思います。

:::note warn
あくまで個人の所感や体験談です。実際に学ぶ内容や過程は人それぞれです。
個人の目標に合わせて今回の投稿を参考にして頂ければと思います。
:::

# Javaを学ぼうと思ったきっかけ
理由は大きく分けて２通りあります。

## 事業目線
Ruby（Rails）はスタートアップなどで小規模なアプリを短期間で開発するのが得意だと思います。
なので「**自分（もしくはクライアント）が作りたいサービスをすぐ形にしたい**」という欲求が強かったと思います。

それが満たされてきた後に、「**自分が開発していくサービスは社会のどんなところで役に立つのだろう？**」と考えるようになってきました。

（元々インフラ系出身なので、**社会貢献度の高い仕事**にも関心があります）

そこで、より大規模なプロジェクトで広く採用されているJavaを習得することで、エンジニアとしてできることが増える。
あとは求人やプロジェクトの数も多いので、自分のキャリアにおける選択肢の幅も広がると思いました。

## 技術目線
後述の[RubyとJavaの違い](#RubyとJavaの違い)にも書きますが、**Javaのオブジェクト指向設計や静的型付けなど**のRubyとは異なる概念や設計思想を知り、プログラミング全般の理解を深めたいのもあります。

Rubyでは、ライブラリやFWを使うことで内部の処理をそこまで意識しなくても作れてた部分もあると思います。
そのRubyの**直感的に書ける柔軟性**というメリットの裏にあるRuby独特の曖昧さにモヤっとする時があります（これ、どういう仕組みなんだろう？みたいな）

そこでJavaをキャッチアップすることで**Rubyのオブジェクト指向プログラミング**もより深く理解できればと思っています。

# RubyとJavaの違い
## 設計思想
### Java
- **堅牢性と安全性**
Javaは**静的型付け言語**であり、コンパイル時に**厳密な型チェック**を行うことで、実行時エラーを減らし、堅牢なシステム構築を重視しています。
- **移植性**
Javaは「`Write Once, Run Anywhere（一度書けば、どこでも実行できる）`」という思想に基づいており、Java仮想マシン（JVM）上で動作することで、異なる環境でも同じように動作します。
- **大規模開発への対応**
Javaは、大規模なエンタープライズシステム開発で広く利用されており、高いパフォーマンスと安定性が求められる分野に適しています。
- **オブジェクト指向の徹底**
Javaは、オブジェクト指向プログラミングの概念を徹底的に追求しており、クラス、オブジェクト、継承、ポリモーフィズムなどを厳密に扱います。

```java
// 型宣言の例
String name = "太郎";
int age = 30;
```

### Ruby(Ruby on Rails)
- **プログラマーの幸福**
Rubyは、プログラマーが**楽しく、快適に**プログラミングできることを重視しています。
コードの可読性や柔軟性を高めるための機能が豊富に提供されています。
- **柔軟性と表現力**
Rubyは**動的型付け言語**であり、コードの**柔軟性と表現力**を重視しています。
プログラムの実行時に、型の整合性チェックを行います。
- **規約より設定**
Ruby on Railsなどのフレームワークでは、「`Convention over Configuration（規約より設定）`」という思想が採用されています。
これにより、開発者は定型的な設定を記述する必要がなく、ビジネスロジックに集中できます。
- **シンプルさと簡潔さ**
Rubyは、コードを**シンプルかつ簡潔に**記述できることを重視しています。
そのため、文法が柔軟で、冗長なコードを減らすことができます。

```ruby
# 型宣言の例
name = "太郎"
age = 30
```

## もしJavaとRubyを擬人化したら...？
これはあくまで僕なりの例ですが、以下のように捉えています。
- Java→`堅実で真面目な上司`
- Ruby→`仲の良い友達・親友`

<div style="display:flex;">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/90bade7b-096f-4c65-b174-8e1aec8e0d98.png"  width=30% alt="Java上司">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/0b9e0e0a-c3ff-428e-ae6f-1e73bdd22963.png"  width=30% alt="親友のRuby">
</div>

上記はあくまで特性であり、どちらが良い悪いかの優劣を判断するものではありません。
これによっても人との相性や向き不向きが分かれそうだなって思いました。

## プログラムの実行方法
### Java（コンパイル言語）
- 人間が記述したソースコードを、コンピュータが直接実行できる**機械語に変換**（コンパイル）します。この変換は、**プログラムを実行する前**に行われます
- Javaの場合、ソースコード（.javaファイル）は、Javaバイトコード（.classファイル）と呼ばれる中間言語にコンパイルされます
- コンパイル済みのプログラムは、**インタプリタ言語よりも実行速度が速いです**。なぜなら、実行時に毎回コードを解釈する必要がないからです
- **コードを修正するたびにコンパイルが必要**なため、開発サイクルが長くなることがあります。しかし、コンパイル時にエラーを検出できるため、**実行時のエラーを減らすことができます**

### Ruby（インタプリタ言語）
- プログラムを実行するたびに、ソースコードを**一行ずつ解釈しながら実行します**。コンパイルのような事前変換は行いません
- インタプリタ言語は、**コンパイル言語よりも実行速度が遅いです**。なぜなら、実行時に毎回コードを解釈する必要があるからです
- コードを修正してすぐに実行できるため、**開発サイクルが短く、プロトタイプ開発などに適しています**。しかし、**実行時にエラーが検出されることが多い**ため、テストが重要になります

![kinocodeコンパイル_P11-1-1024x500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/8c75894d-94d1-4d68-a033-869b30a9c3f2.png)
> 引用：[コンパイルとは？｜コンパイルとは何か、仕組みについて3分でわかりやすく解説](https://www.google.com/url?sa=i&url=https%3A%2F%2Fkino-code.com%2Fwhat-is-compile%2F&psig=AOvVaw0PJSbVODdVnNmCg4pEU44W&ust=1743385498988000&source=images&cd=vfe&opi=89978449&ved=0CBcQjhxqFwoTCLC6iqLXsIwDFQAAAAAdAAAAABAS)

## 文法の違い
### メソッドの定義
#### Java
```Java
    public static String greet(String name) {
      return "こんにちは、" + name + "さん！";
    }
```
`public static`は、クラスのメンバ（変数やメソッド）をクラス自体に紐付け、***インスタンス化せずにアクセス可能にする修飾子**です

#### Ruby
```ruby
    def greet(name)
      "こんにちは、#{name}さん！"
    end
```
「Rubyでは`public`を定義しなくても良いの？」と疑問に思った方もいるかもしれません。
そこでRubyのリファレンスマニュアルなどを確認してみました。

> デフォルトでは def 式がクラス定義の外(トップレベル)にあれば private、クラス定義の中にあれば public に定義します。これは Module#public、Module#private、 Module#protected を用いて変更できます。
[Ruby 3.4 リファレンスマニュアル  クラス／メソッドの定義　「呼び出し制限」より抜粋](https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#limit)

```ruby
def foo           # デフォルトは private
end

class C
  def bar         # デフォルトは public
  end

  def ok          # デフォルトは public
  end
  private :ok     # …だが、ここで private に変わる

  def initialize  # initialize は private
  end
end
```

Rubyでは、このような柔軟なオブジェクト指向モデルと動的型付けによって、publicなどを明示的に指定しなくても、**クラスメソッド、モジュール、トップレベルメソッド**を使用してJavaと同様の機能を実現しているのだと思いました。
（間違ってたら教えてください）

### クラスの定義
#### Java
```java
    public class Person {
      private String name;
      private int age;

      public Person(String name, int age) {
        this.name = name;
        this.age = age;
      }

      public String introduce() {
        return "私の名前は" + name + "、年齢は" + age + "歳です。";
      }
    }
```
コンストラクタは、クラスと同じ名前のメソッドとして定義されます。
*`コンストラクタ`：**オブジェクトの初期化**を行う特別なメソッドであり、クラスのインスタンス生成時に暗黙的に呼び出されます。

#### Ruby
```ruby
    class Person
      def initialize(name, age)
        @name = name
        @age = age
      end

      def introduce
        "私の名前は#{@name}、年齢は#{@age}歳です。"
      end
    end
```
Rubyでは、オブジェクトの初期化は、**initialize**という名前のメソッドでおこないます。
コンストラクタもこのinitializeで定義されます。
[Ruby 3.4 リファレンスマニュアル  ライブラリ一覧  組み込みライブラリ  Objectクラス  initialize (private)](https://docs.ruby-lang.org/ja/latest/method/Object/i/initialize.html)

## SpringBootとRailsの違い
こちらではJavaのFWである**SpringBoot**と、RubyのFWである**Ruby on Rails**を比較しています。

### MVCアーキテクチャの違い
#### SpringBoot
- MVCアーキテクチャを基本としつつも、Railsより柔軟な設計が可能です
- **RESTful API**の開発に重点を置いており、JSONやXMLなどのデータ形式を扱いやすいです

#### Rails
- MVCアーキテクチャを厳格に適用し、モデル、ビュー、コントローラーの役割を明確に分離します
- このフレームワークによって**RESTfulな設計に基づいたルーティング**が強力にサポートされています

### CRUD操作の違い
#### SpringBoot
**JPA（Java Persistence API）やMyBatis**などのORM（Object-Relational Mapper）により、データベース操作をオブジェクト指向で行えます。
- **Spring Data JPA**というライブラリを使うことで、リポジトリインターフェースを定義するだけでCRUD操作を実装できます

#### Rails
- **Active Record**というORMにより、データベース操作をオブジェクト指向で行えます
- scaffoldという機能で、CRUD操作のコードを自動生成できます

### テーブル・マイグレーション
#### SpringBoot(Java)
- **FlywayやLiquibase**などのライブラリを使用して、データベースのマイグレーションを管理することが一般的です
- SQLスクリプトまたはJavaコードでマイグレーションを記述し、データベースのスキーマを更新します

例：`V1__create_users_table.sql`
```java
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL
);
```

#### Rails
- **Active Recordマイグレーション**という仕組みを使用して、データベースのスキーマ変更を管理します
- マイグレーションファイルは、Rubyのコードで記述され、データベースの変更内容をバージョン管理します

`db/migration/20250201165640_create_users.rb`
```ruby
    class CreateUsers < ActiveRecord::Migration[6.1]
      def change
        create_table :users do |t|
          t.string :name, null: false
          t.text :email, null: false
          t.timestamps
        end
      end
    end
```

### MVCコード例
#### モデル（エンティティ）
##### SpringBoot(Java)
```java
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;

    @Entity
    public class Article {
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      private String title;
      private String content;

      // ゲッター、セッター、コンストラクタなどをこの下に記載
    }
```

*`エンティティ`：データベースのテーブルを**Javaオブジェクト**として表現したものです。
データベースのテーブルとマッピングされるオブジェクトであり、データベースとのやり取りを行います。
対してモデルは、アプリケーションの**ビジネスロジックやデータ処理**を担当する部分です。

[ドメイン駆動設計（DDD）](https://qiita.com/yu-saito-ceres/items/f73262cedcdd6e8e75c8)に従って、エンティティとモデルを分離することが可能です。

どちらを使用するかは、アプリケーションの設計と目的によって異なります。

##### Rails
```ruby
class Article < ApplicationRecord
end
```

Railsでは、**Active Recordパターン**というORM（Object-Relational Mapper）が、JavaのEntityに相当します。
**データベースのテーブルとモデルが1対1で対応**し、**モデル自身**がデータベースへのアクセスとデータの操作を行います。
つまり、Railsのモデルは、**データベースのエンティティとしての側面**と、**アプリケーションのビジネスロジックを担うモデルとしての側面**を併せ持っています。

[Railsガイド　1.1 Active Recordパターン](https://railsguides.jp/v6.1/active_record_basics.html#active-record%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

RailsはDDDを前提としたFWではないため、Javaのようにエンティティとモデルを明確に区別して実装するという概念が薄いかもしれませんね。

#### コントローラー
##### SpringBoot
- アノテーションを使用して、**URLとメソッドのマッピング**やレスポンスデータを**JSONまたはXML形式で直接返す**ことができます
- Java（特にSpring Boot）では、Railsのような独立したルーティングファイル（`routes.rb`など）は通常使用されません。代わりに、アノテーションを使用してルーティングを定義します

*`アノテーション`: コードに**メタデータ**（付加情報）を埋め込むことで、設定やコードの記述量を減らし、開発効率を向上させるための機能です。
@Controllerや@GetMappingなど、@から始まるコードです

```java
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.ModelAttribute;

    @Controller
    public class ArticleController {
      @Autowired
      private ArticleRepository articleRepository;

      @GetMapping("/articles")
      public String index(Model model) {
        model.addAttribute("articles", articleRepository.findAll());
        return "articles/index";
      }

      @GetMapping("/articles/{id}")
      public String show(@PathVariable Long id, Model model) {
        model.addAttribute("article", articleRepository.findById(id).orElse(null));
        return "articles/show";
      }

      @GetMapping("/articles/new")
      public String newArticle(Model model) {
        model.addAttribute("article", new Article());
        return "articles/new";
      }

      @PostMapping("/articles")
      public String create(@ModelAttribute Article article) {
        articleRepository.save(article);
        return "redirect:/articles";
      }
    }
```

##### Rails
- Rubyのクラスとして実装されます
- ルーティングによって、URLとアクション（メソッド）のマッピングが行われます
```ruby
class ArticlesController < ApplicationController
      def index
        @articles = Article.all
      end

      def show
        @article = Article.find(params[:id])
      end

      def new
        @article = Article.new
      end

      def create
        @article = Article.new(article_params)
        if @article.save
          redirect_to @article
        else
          render 'new'
        end
      end

      private

      def article_params
        params.require(:article).permit(:title, :content)
      end
end
```

#### ビュー
##### SpringBoot
- **Thymeleaf、JSP、FreeMarker**などのテンプレートエンジンを使用してビューを生成します（Thymeleafが使用されることが多い）

以下はThymeleafの例です。
```java
<!DOCTYPE html>
    <html>
    <head>
      <title>記事一覧</title>
    </head>
    <body>
      <h1>記事一覧</h1>
      <ul>
        <li th:each="article : ${articles}">
          <a th:href="@{/articles/{id}(id=${article.id})}" th:text="${article.title}"></a>
        </li>
      </ul>
    </body>
    </html>
```

##### Rails
- **ERB**（Embedded Ruby）というテンプレートエンジンを使用してビューを生成します
```erb
<h1>記事一覧</h1>
    <ul>
      <% @articles.each do |article| %>
        <li><%= link_to article.title, article %></li>
      <% end %>
    </ul>
```

## ドキュメント
### SpringBoot
- [SpringBoot](https://spring.io/projects/spring-boot)
   - Spring Bootの公式ドキュメントであり、包括的で詳細な情報を提供しています
   - <INS>自動設定、依存性注入、セキュリティなど</INS>、Spring Bootの強力な機能を最大限に活用するための情報が満載です
- [Spring Framework](https://spring.io/projects/spring-framework)
   - Spring Bootは**Spring Frameworkの上に構築されている**ため、Spring Frameworkのドキュメントも参考になります
- [Pleiades Spring Boot Tutorial](https://spring.pleiades.io/spring-boot/tutorial/)
   - Spring Bootの基本的な概念と使い方を日本語で解説するチュートリアルです
   - 初心者向けに、Spring Bootの概要から基本的な機能、Webアプリケーション開発までをステップバイステップで学ぶことができます
- [Spring Guides](https://spring.io/guides)
   - Spring Bootを含むSpringプロジェクトの様々なテーマに関する実践的なガイドを提供します
   - RESTful Webサービス、データベースアクセス、セキュリティ、クラウドなど、様々なトピックに関するチュートリアルが用意されています
### Rails
- [Ruby on Rails ガイド](https://railsguides.jp/)
  - Railsの公式ドキュメントであり、Railsの仕組みを体系的に学べる大型コンテンツです
  - Active Record、ルーティング、ビューなど、Railsの主要な機能について詳細な説明と実践的な例が豊富に掲載されています

- [Ruby on Rails API](https://api.rubyonrails.org/)
  - RailsのAPIドキュメントであり、各クラスやメソッドの詳細な仕様を確認できます
  - [Ruby on Rails ガイド](https://railsguides.jp/)と併用することで、Railsの機能をより深く理解できます
- [Rails Tutorial](https://railstutorial.jp/)
  - Webサービスを作りながらゼロからデプロイまでのWebサービス開発が学ベル大型チュートリアルです。（自分も初学者の頃お世話になりました🙇‍♂️）

:::note warn
Railsドキュメントは公式ドキュメントではないみたいです。
> [ねえ、知ってた？「Railsドキュメント」はRailsの公式ドキュメントではないんですよ、という話](https://qiita.com/jnchito/items/fe0462776bca49aed79b)
:::

# 学習を通して感じたこと
## 「食わず嫌い」はなるべくしない
Javaは型などの制約が多く、個人的に今まで敬遠していた部分もありました。
もっというと、初学者の頃は<INS>「フロントエンドは好きだったけど、バックエンドはあまり興味ありませんでした（←おい）」</INS>

でも今はバックエンドメインでやってますし、フロントエンド（Vue, React）もたまに書いたりしてます。

特別好きでなくてもなんだかんだで続けてみると、意外とハマったり愛着を持つこともあります。
いままで興味なかったことでも手を挙げてやってみると、新しい発見があったりもします。
だから**とりあえずやってみる**。今後続けていきたいかはその後で考える。

### プログラミング初学者がバックエンドへの関心を持つには？
WebページのUI（見た目）を考えるのは楽しいですし、すぐ目にみえる結果が出るのでとっつきやすいと思います。

それと同じくらい、以下のようなことを考えるとバックエンドへの興味も高まるでしょうし、より自分の視座が高まると思います。
[参考記事](#参考記事)をページの最後に紹介してあります。
- Webアプリケーションの仕組みを知る
- データベースの基礎知識（SQL、RDBMSなど）を学ぶ
- 興味あるバックエンド言語（Java、Python、Ruby、PHP、Node.jsなど）から始める（趣味からでも良い）

## 言語のキャッチアップをゲームに置き換えて考える
### リセマラしても同じレベルでつまづく
ポケモンの例で言うと、あなたが最初のジムリーダーに負けて挫折したとします。
それで違うシリーズでやり直したとしても、また同じ場所でつまづくかもしれません。

逆に、一つのシリーズで殿堂入りまでできれば、他のシリーズでも比較的楽にクリアできるようになるかもしれません（ゲームの仕様やポケモンは変わっても、やることは大体同じなため）

これをプログラミング言語のキャッチアップに置き換えるとします。
一つの言語やFWで基礎やMVCを学んでCRUDの実装などを覚え、1つの言語で開発できるようになれば、学習コストがかかりますが他の言語やFWでもできるようになるはずです（逆も然り）

だから多少時間がかかったとしても、自分が納得する目標に達成するまでやり続けることも大切だと思います。

:::note warn
あくまでも持論です。個人のスキルレベルやプロジェクト環境によって異なる場合があります。
:::

## 職人気質✖️ビジネス思考
自分の場合、家族が工業関係の仕事に就く人が多かった影響か、職人気質な思考もあるかもしれません。ちょっと古い思考かもしれませんが、「この道何十年」みたいに一つの仕事を極められる人は尊敬します。

とはいえ、現代のような変化の早い時代だと、一つの仕事だけでは取り残されてしまう。
やや職人気質な自分と、会社（社会）から求められることにどう折り合いをつけるかはよく悩みます。

そうして考えた自分なりの最適解が「**どのプロジェクトでも通用するスキルを持つエンジニア**」になること。

通用するスキルは何も、開発スキルに限ったことではないと思います。
<INS>コミュニケーション能力、問題解決能力、タスク管理</INS>、などビジネス的なスキルも含まれる。
それらをプログラミングと同じくらい職人的にこだわって考えてより良くしていくっていうのが、自分なりのモチベーションを保つ方法です。

## プログラミングも目的ではなく手段の一つ
RubyもJavaもPHPも、クライアントの要望を満たすサービスを作るための一手段であると自分に言い聞かせています。

なので「自分は今までRailsやってきたからRailsで開発したい」ではなく、
「**クライアントが求めているのはどんなサービスかな？**」
「**アプリを作るのに適切なフレームワークやアーキテクチャは何かな？**」
「**今、社内（プロジェクト）の課題に対して、自分はどのような立ち回りをするべきかな？**（自分本位になりすぎてないかな？なども内省）」
という目線も持ってやっていきたいと思います。

# おわりに
長期的にはRailsやJavaと特定の言語に限定せず、必要に応じて求められている技術をキャッチアップしていければと思います。
Javaはまだまだ初学者なので、今後も学び続けていきたいと思います。
最後まで読んで頂き、ありがとうございました。

# 参考記事
[Webアプリケーションとは？仕組みや開発の流れ、サービス例も紹介](https://www.sejuku.net/blog/1046)
[Webアプリケーションの全体像を掴む](https://qiita.com/tamago3keran/items/f470593926458b7ef52a)
[コンパイルとは？｜コンパイルとは何か、仕組みについて3分でわかりやすく解説](https://www.google.com/url?sa=i&url=https%3A%2F%2Fkino-code.com%2Fwhat-is-compile%2F&psig=AOvVaw0PJSbVODdVnNmCg4pEU44W&ust=1743385498988000&source=images&cd=vfe&opi=89978449&ved=0CBcQjhxqFwoTCLC6iqLXsIwDFQAAAAAdAAAAABAS)
[ふわっと理解するDDD ~ドメイン駆動設計~](https://qiita.com/yu-saito-ceres/items/f73262cedcdd6e8e75c8)
[Ruby on Rails ガイド](https://railsguides.jp/)
[Ruby on Rails API](https://api.rubyonrails.org/)
[Pleiades Spring Boot Tutorial](https://spring.pleiades.io/spring-boot/tutorial/)
[Spring Guides](https://spring.io/guides)