rhanda | 元銀行員Web系エンジニアの日記

実務未経験からWeb系受託開発企業に転職したひよっこエンジニアが覚えたことや日々の感情を残すブログ

『Webを支える技術』読みました

エンジニアとして成長していくにあたって、RESTの考え方に習熟していきたいと思った時に、「そもそもWebとは」みたいなことへの知識もあると、より理解が深まるよと上司に紹介していただきました。
特に自分は学生時代もあまりPCに触れたことがなく知識がほぼ0であったため、何か新しいことが得られればと思い読んでみました。

構成

1章 Webとは何か
2章 Webの歴史
3章 REST Webのアーキテクチャスタイル 4章 URIの仕様
5章 URIの設計
6章 HTTPの基本
7章 HTTPメソッド
8章 ステータスコード
9章 HTTPヘッダ
10章 HTML
11章 microformats
12章 Atom
13章 Atom Publishing Protocol
14章 JSON
15章 読み取り専用のWebサービスの設計
16章 書き込み可能なWebサービスの設計
17章 リソースの設計



メモ

アーキテクチャスタイル

別名「(マクロ)アーキテクチャパターン」とも言い、複数のアーキテクチャに共通する性質、様式、作法あるいは流儀を指す言葉で、例えばMVCやパイプ&フィルタ、イベントシステムなどがある。
パターンという言葉からデザインパターンが想像されることもあるが、いわゆるデザインパターンは別名「マイクロアーキテクチャパターン」とも言い、アーキテクチャスタイルよりも粒度の小さいクラスなどの設計様式を指す。

REST

RESTは数あるアーキテクチャスタイルの中でも、特にネットワークシステムのアーキテクチャスタイルである。ネットワークシステムのアーキテクチャスタイルで最も有名なのはクライアント/サーバであり、そしてWebはクライアント/サーバでもある。(RESTはクライアント/サーバから派生したものでもある。)

RESTとはつまり以下6つを組み合わせたアーキテクチャスタイル

  • クライアント/サーバ
  • ステートレスサーバ
    • サーバ側でアプリケーション状態を持たない
  • キャッシュ
    • クライアントとサーバの通信回数と量を減らす
  • 統一インタフェース
    • インタフェースを固定する
  • 階層化システム
    • システムを階層に分離する
  • コードオンデマンド
    • プログラムをクライアントにダウンロードして実行する

アドレス可能性

RESTfulなWebサービスの性質として最も重要なもの。
これは「URIさえあればリソースを一位に指し示すことができる」と言う性質であり、URIのこの性質がなければ接続性と統一インタフェースを実現できない。

接続性

リソースをリンクで接続することで1つのアプリケーションを構成するという考え方。
RESTの基幹をなす思想。

統一インタフェース

URIで指し示したリソースに対する操作を、統一した限定的なインタフェースで行うアーキテクチャスタイルのこと。
例えばHTTP1.1ではGEtやPOSTなど8個のメソッドだけが定義されており、通常はこれ以上増えない。
インタフェースの柔軟性に制限を加えることで全体のアーキテクチャがシンプルになり、またインタフェースを統一することでクライアントとサーバの実装の独立性が向上する。

URI

http:yohei:pass@blog.example.jp:8000/search?q=test&debug=true#n10
このURIは以下のように分けられる

  • URIスキーム:http
  • ユーザ情報:yohei:pass
  • ホスト名:blog.example.com
  • ポート番号:8000
  • パス:/search
  • クエリパラメータ:q=test&debug=true
  • URIフラグメント:#n10

変わらないURIこそが最上のURI

1998年当時、URIが変更になることは日常茶飯事であった。
しかしながらこれはWebの根幹を揺るがす問題で、Webとはそれぞれのリソースに他のリソースへのリンクが埋め込まれたハイパーメディアシステムである中で、リンクが切れてしまうことはそれが機能しないことを意味するからだ。

URIを変わりにくくするためには

  • プログラミング言語に依存した拡張子やパスを含めない
    • 言語を変えたら使えなくなる
  • メソッド名やセッションIDを含めない
    • メソッド名が変わった瞬間、またログインし直すたびに使えなくなってしまう
  • URIはリソースを表現する名詞にする
    • URIとHTTPメソッドは、名詞と動詞の関係にある。URIは全体として名詞になる様に設計すべき

HTTP

名前こそハイパーテキストの転送用プロトコルだが、実際にはHTMLやXMLなどのハイパーテキストだけでなく、静止画・音声・動画・JavaScriptプログラム・PDFや各種オフィスドキュメントファイルなど、コンピュータで扱えるデータであれば何でも転送できる。
HTTPはRESTの重要な特徴である統一インタフェース、ステートレスサーバ、キャッシュなどを実現している、Webの基盤となるプロトコルである。

べき等性と安全性

HTTPメソッドはその性質によって以下の様に分類できる。

メソッド 性質
GET、HEAD べき等かつ安全
PUT、DELETE べき等だが安全でない
POST べき等でも安全でもない
べき等とは

「ある操作を何回行っても結果が同じこと」を意味する数学用語。
例えばPUTやDELETEを同じリソースに何回発行しても、必ず同じ結果(リソースの内容が更新されている、リソースが削除されている)が得られる。

安全とは

「操作対象のリソースの状態を変化させないこと」を意味する。
リソースの状態に変化を与えることを「副作用」と言うので、安全は「操作対象のリソースに副作用がないこと」とも言う。
例えばGETには副作用がないので、GETを同じリソースに何度発行しても、リソースの状態は変化しない。

ステータスコードの意味と分類

  • 1xx:処理中
    • 処理が継続していることを示す。クライアントはそのままリクエストを継続するか、サーバの指示に従ってプロトコルをアップデートし再送信する。
  • 2xx:成功
    • リクエスト成功を示す。
  • 3xx:リダイレクト
    • 他のリソースへのリダイレクトを示す。クライアントはこのステータスコードを受け取った時、レスポンスメッセージのlocationヘッダを見て新しいリソースへ接続する。
  • 4xx:クライアントエラー
    • 原因はクライアントのリクエストにある。エラーを解消しない限り正常な結果が得られないので、同じリクエストをそのまま再送信することはできない。
  • 5xx:サーバエラー
    • 原因はサーバ側にある。サーバ側の原因が解決すれば、同一リクエストを再送信して正常な結果が得られる可能性がある。

キャッシュ

HTTPの重要な機能の一つ。
サーバから取得したリソースをローカルストレージ(ハードディスクなど)に蓄積し、再利用する手法のこと。
ローカルストレージにキャッシュしたデータそのもののこともキャッシュと呼ぶことがある。
クライアントが蓄積したキャッシュは、そのキャッシュが有効な間、クライアントが再度そのリソースにアクセスしようとした時に再利用する。

HTML

Hypertext Markup Lnaguageの略。
マークアップ言語とは、タグで文書の構造を表現するコンピュータ言語である。また、マークアップ言語でマークアップした構造を持った文書のことを「構造化文書」と呼ぶ。

Atom

タイトル・著者・更新日時といった基本的なメタデータを備えたリソース表現のためのフォーマット。
Atomは多様なアプリケーション用の拡張が用意されたフォーマットでもある。
例えば、ポッドキャストによる音楽配信や、写真管理、検索エンジンなどのアプリケーションは、XML名前空間の仕組みを使ってAtomに独自の要素を追加している。

JSON

JavaScript Object Notationの略で、データ記述言語である。
その名の通りJavaScriptの記法でデータを記述できる点が最大の特徴で、記法はJava Scriptだが、そのシンプルさから多くの言語がライブラリを用意しているため、プログラミング言語間でデータを受け渡すことができる。

Webサービスでは、ブラウザがJavaScriptを実行できるために相性が良い、XMLと比べてデータ表現の冗長性が低いなどのメリットから、Ajax通信におけるデータフォーマットとして活用されている。

Webサービス設計において大切な考え方

  • なるべくシンプルに保つ
    • 設計が複雑になったり機能が無駄に増えてきたら、1段階メタな視点で全体を考え直す。
      やり方を変えることで削除できる箇所があるかもしれない。
      全体をシンプルに保つことは、設計バランスを考える上で最も重要。
  • 困ったらリソースに戻って考える
    • HTTPメソッドでは実現できない機能があると感じたら、それが独立した別リソースで代替できないかを考える。
      検索機能を実現するSEARCHメソッドをHTTPに追加するのではなく、「検索結果リソース」をGETする、と考えることが重要。
  • 本当に必要ならPOSTで何でもできる
    • 更新にはPUTを用いるべきだとしても、例えばバッチ処理の様に複数リソースが対象となった時点で、PUTを使うのは諦めてPOSTを用いる方が賢明である。



まとめ

プログラミング学習を始めた頃から、Railsに触れ始めた頃からRESTという言葉やリソースを大切にする考え方に触れることは多くありましたが、そもそもそれはWebの成り立ちにも起因することで、Webが発展してきた経緯があったということを知りました。

自分がこれまで学んできたことは、どちらかといえば表層の方にすぎず、より根底に近いHTTP、URIなど開発の基礎とも言える箇所を新たな角度から学ぶことができたのではないかと感じています。

自分のコードが初めて世に出ました

コードが初めて世に出た

ついに自分がコードを書き、リリースされる経験をしました。 正直そこまで実感はないというのが率直な感想です。


そう感じる主な理由は、新規サービスなどではなく、既に走っているサービスの一部改修であったために「リリースされた!」という印象が強くないことかと思います。
いつも通り作業をして、コミットしてPRを出して、レビューをいただいてクライアントにも確認いただいて、main のブランチへ push をする。を淡々とこなしたという感覚です。


CTOは、「バグや障害対応の業務が発生し始めると、自分の携わったコードが世に出ている感覚も強くなったりするよ」と仰っていたので、また新しい感想を持つタイミングがきたら、このブログを読みながら気持ちの違いを記録に残してもみたいなと思っております。



プロジェクトに入った話

先月の頭、銀行を退職してからちょうど1年のタイミングに実案件にアサインしていただきました。


既存のアプリケーションに対して、新機能を追加実装する受託案件で、
「規模もそこまで大きくないので、勉強する気持ちでたくさんのことを吸収して成長してほしい」
と最初に言って頂いていたので、知らないこと全てに触れていく気持ちで臨みました。


開始当初の作戦会議mtgで実装方針を定めて設計をし、やるべき課題に対して issue を立ててタスクの割り振りをし、スケジュールを確認しながら作り上げ、引っかかることがあれば方向修正しながらより良いものに仕上げていく。という様な進め方で日々の業務に取り組んでいきました。


間も無くテストも終えてリリースを迎えることになりますが、初プロジェクトで

  • 案件の一連の流れや立ち回り方
  • 設計
  • クライアントとのmtgやコミュニケーションの雰囲気
  • 当然ながらコーディングの知識

等々、それなりに多くのことを経験できたのではないかと思っています。


多くの先輩に良質なアドバイスを頂ける職場で、設計からコーディングから結合テストまでをこんなに早い段階で経験することができ、自分は非常に恵まれていると再認識しております。
プログラミングスクールを使っての勉強から転職活動、研修を経てついにエンジニアとしての仕事ができるようになって非常に感慨深い思いです。

一方で先輩方の凄さと自分の未熟具合も感じて、自分も時間が経過したときに同じ様になれているだろうかと不安を覚える、そんな日々でもありました。


まとめ

自分は自分のペースで、できる努力を地道に積み重ねて、日々昨日の自分を超え続けられる様に進んでいきたい所存です。🔥
明日からも頑張ろう

Rubyプログラム実行時に、コマンドライン引数を取得できるようオプションを作成

先日カレンダープログラムの作成に取り組みました。 その中でオプション設定や、それに係るエラーメッセージの表示を初めて行ったので、メモとして残すものです。



最終的に作ったコード

require 'optparse'

option = {}

OptionParser.new do |opt|
  begin
    opt.banner = "Usage: calender [options]"
    opt.on('-y year') {|v| option[:year] = v}
    opt.on('-m month') {|v| option[:month] = v}

    opt.parse!(ARGV)
  rescue OptionParser::InvalidOption => e
    puts "calender.rb:\s#{e.reason=('illegal option')}\s#{e.args.join(' ')}"
    puts opt.help
    exit
  rescue OptionParser::MissingArgument => e
    puts "option requires an argument\s#{e.args.join(' ')}"
    puts opt.help
    exit
  end
end

ひとつひとつ振り返る

rescue等の例外補足は置いておいて、オプションを使うためのコードはこの辺り

require 'optparse'

option = {}

OptionParser.new do |opt|
  opt.banner = "Usage: calender [options]"
  opt.on('-y year') {|v| option[:year] = v}
  opt.on('-m month') {|v| option[:month] = v}

  opt.parse!(ARGV)
end

例えば以下のようにすれば出力することで、コマンドライン引数を取得できていることがわかります。

p option[:year]
p option[:month]

% ruby test.rb -y 2021 -m 9

"2021"
"9"

オプションを作成

  opt.on('-y year') {|v| option[:year] = v}
  opt.on('-m month') {|v| option[:month] = v}

ここで-y-mのオプションを取り扱えるようにしています。(onメソッドリファレンス
今回はカレンダーのプログラムで年と月を扱いたかったので、最初にハッシュを作っておいて、それぞれyearmonthのキーの値にするようにしました。


また、このonメソッドの箇所では引数に関する設定が可能。

  • 引数を取らない場合
# コマンドラインにオプションを入力した場合は、 true を引数としてブロックを評価する。
on("-x"){|boolean| ...}
  • 引数を取る場合(本件の書き方)
# 'year'の部分は任意の文字列
on("-x year"){|val| ...}
  • 引数が必須ではない場合(上の書き方は必須)
# [ ] をつける
on("-x [year]"){|val| ...}


その他

opt.parse!(ARGV)

opt.parse!(ARGV)

Optionparser#parseは与えられたargvからオプションを取り除いたものを返す。
parseメソッドリファレンス

試してみたところ、これを書いていないと引数だけでなくオプション自体も要素として入っておりました。
今回は、オプション指定時に引数を入力し忘れた場合に例外を補足したい(OptionParser::MissingArgument)と考えており、オプションが入ってしまうと例補足することができなかったので、記述しました。

# 引数を入力し忘れた時
# parse!した場合
% ruby 02.calendar/calender.rb -y 

irb(main):001:0> ARGV
=> [] 


# parse!しなかった場合
% ruby 02.calendar/calender.rb -y 

irb(main):001:0> ARGV
=> ["-y"]


opt.banner = str

opt.banner = "Usage: calender [options]"

banner=メソッドは、--helpオプションを指定した時に表示されるサマリの最初に表示する文字列を指定することができます。 今回は例外補足時にUsage: calender [options]と表示したかったのでここで記述して、rescue節のputs opt.helpで出力するようにしておりました。


感想

カレンダー全体のプログラムについても、振り返ってまとめてみたい。

『リーダブルコード』読みました

読んだきっかけ

研修としてのアプリケーション開発で沢山のコードレビューを頂くなかで、

「この書き方の方がぱっと見で何がしたいかわかりやすい」
「この変数名だと誤解を招く恐れがある」

といったアドバイスをたくさん頂きました。
「機能的に要件通り動作するかどうか」にしか未だ考えが及んでいなかった私は、よりコードのクオリティへの考えが必要だと感じ、ベースとなる知識を得るために本書を手に取りました。

構成

1章 理解しやすいコード
2章 名前に情報を詰め込む
3章 誤解されない名前
4章 美しさ
5章 コメントすべきことを知る
6章 コメントは正確で簡潔に
7章 制御フローを読みやすくする
8章 巨大な式を分割する
9章 変数と読みやすさ
10章 無関係の下位問題を抽出する
11章 一度に1つのことを
12章 コードに思いを込める
13章 短いコードを書く
14章 テストと読みやすさ
15章 「分/時間カウンタ」を設計・実装する



メモ

命名で相手に意図を伝える

最善の名前とは誤解されない名前である。
命名においては明確な単語を使い(Getではなく状況に応じてFetchDownloadを使うなど)、読み手が自分の意図を正しく理解できるかどうかを重視する。


コメントで意図を伝える

コードを読めばすぐにわかることをコメントで説明しない。
コードを読んだ人が「質問しよう」と思うところを予想してコメントをつける。

自分も開発の中で以下の様にコメントで補足してみました。
(動作確認用データを作る単純なrakeタスクですが、、、)

task tasks: :environment do
  puts "\n== 動作確認用のタスクを100件作成しています =="
  # seedで作った最初のユーザーと紐付けて作成する
  user = User.first
  raise "\n-- seedでユーザーデータを作成してから実行してください--" unless user

  # 適当に100件
  100.times do |n|
    user.tasks.create!(
      name: "タスク#{n}",
      created_at: Time.current + n.days,
      due_on: Time.zone.today + n.days,
      status: Task.statuses.keys.sample,
      priority: Task.priorities.keys.sample
    )
  end
  puts "\n== 動作確認用データ100件の作成が完了しました =="
end


制御フローを読みやすくする

行数を短くするよりも、他者が理解するのにかかる時間を短くする
こちらも自分の開発の中で取り入れてみました。
とても実効の流れが追いやすく、戻り値もわかりやすくなると感じました。

# 修正前
def current_user
  @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end
# 修正後
def current_user
  return unless session[:user_id]

  @current_user ||= User.find(session[:user_id])
end


オブジェクト思考プログラミング

データと操作をクラスという単位にグルーピングし、クラスに対応するオブジェクトと呼ばれるものを生成して利用するもの。


テストを整理する

整理するための指針
  • 新しいテストを簡単に追加できる様にする
  • 既存のテストをシンプルで理解しやすい状態に保つ
  • テストを見返す度、内容の把握に頭を悩ませずに済む様にする
良いコードを書いて保守しやすいテストを作るための武器
  • スペースの入れ方
  • 適切な命名
  • 重複の排除
テストを整理しておくことで得られる効果
  • バグの起きている箇所を特定しやすくなる
  • テストのパターンを見つけやすくなる
  • 漏れているテストケースを見つけやすくなる
助けになる2つの考え方
  • テスト対処を絞り分離すること。一度に多くの内容をテストしようとしないこと
  • にているテストをコンテキストによってまとめ、頭を使わずとも理解できる様にしておくこと


モックとは

自動テストで、実際のオブジェクトを置き換えて使うダミーのオブジェクトのこと。

常に本物のオブジェクトを使ってテストすれば良いのでは??

それは正しい考えで、本物を使えば本番と違う動作をしたりしないし、コードも読みやすく、今書いてある通りに動くため、テストのために特別な準備も必要ない。
しかし実体を呼び出すことが問題となる場合もあり(ユニットテストからの外部サービス呼び出しが高コストだったり遅かったりするケース etc)、モックを導入してオブジェクトを外から操作したり監視したりできる様にしておくと、テストのための設定や準備を柔軟に、また強力に行える様になる効果がある。


TDD(テスト駆動開発

プロダクションコードの追加より前にテストを書くというプラクティス。

TDDのステップ
  1. 失敗するテストを書く
  2. テストを成功させる
  3. リファクタリングする
TDDの利点
  • オーバーエンジニアリングを防ぐ
    • 最初に失敗するテストを書いて、必要性が示された時のみプロがクションコードを追加するため、過剰な作り込みを防止できる
  • 設計が改善され、テストされたコードになりやすい
    • 最初か設計とテストについて考えることになるため、保守しやすいシンプルさを保ち、読みやすいコードを生み出せる様になる
  • 複雑な内容を扱いやすい
    • 新しいプロジェクトや機能に取り組み始めたばかりの時は、確認すべきことやうまくいかないことが多く、疲弊することも多々ある。TDDでは一度に1つのテストだけに集中するため、問題を単純化し、目の前の課題にフォーカスできる。

新機能の追加時やバグを修正する時、実際に作業をする前に「何が成功なのか?」を常に考えることで、成功の定義が明確になり、スコープが限定され、本当に重要なことに集中できる。




まとめ

「読みやすいコードを書くこと」は機能的に優れたコードを作る。

本書では、より良いコードを書くための具体的な手法がいくつも示されていましたが、それに加えてその手段を使うための考え方が非常に勉強になったと感じました。

コードの可読性を上げることは、アプリケーションの機能とはそれ程深い関係がなく、+αのクオリティの様な問題だと思っていました。
しかし、

  • 読みやすいということは、レビューもしやすくなる。
  • 理解するまでの時間が短ければ、その後開発を進める上でも「ここはどうなってるんだっけ」の時間を減らすことができる。

といった様に、開発コストを削減できることを知りました。

加えて設計やテストのしやすさにも繋がって、最終的にはバグも少なく、機能的に優れたコードが出来上がるということを学びました。

どの階層・どのオブジェクトにこの仕事をやってもらい、この情報を知っている状況を作るのかということを鑑みた命名や設計ができる様、今後も勉強していきます。

RubySilver受験記

先日Ruby技術者認定試験(Silver)に合格しました。
自分もいくつかの合格記を参考に学習をしたので、記録も兼ねて残してみたいと思います。 どなたかの参考になりましたら幸いです。





前提(スキルレベル)

  • 2020年9月に前職を退職し、6ヶ月のプログラミング学習を経て2021年5月にWeb系受託開発企業へ転職
  • ポートフォリオ開発でRailsは少し触れていましたが、生Rubyの使用経験はわずか
  • 以前に『ゼロからわかるRuby超入門』を一周で体系的に学習
  • 後述するRExの模試の最初の結果は44点でした



学習に使用したもの



学習時間・やったこと

総学習時間は約4週間、30時間程度でした。

RubyExamination(REx)

スクリーンショット 2021-07-18 18.56.20.png 毎回問題が変わる、解説付きの問題集です。(GitHubアカウントの連携が必要) 主にここで学習をしていました。コンスタントに70点以上を取れた時に、どういう間違い方を狙われているか等、大体の出題傾向や学習すべきことがわかってきた気がします。


[改訂2版]Ruby技術者認定試験合格教本(Silver/Gold対応)Ruby公式資格教科書

公式テキストです。主に巻末の問題集(練習問題30問、模試1回分)を使用しました。


模擬問題集PDF(Silver試験用)

PDFと書いてありますが、GithubGistのページへ移行しています。 RExとは違う問題を解きたくて使用しました。


Rubyがミニツク

問題が幅広く、解説も充実しているので理解が深まります。 試験1週間前くらいに取り組見ましたが、もっと早く手をつければよかったと感じました。



試験結果

スコアは84点(合格ライン:75点)でした。50問中、確信を持った解答ができなかったのが10問程度ありましたが、ある程度選択肢を絞り込むことはできるので、いくつか拾えていたのではないかと思います。

BAF1EDCA-5F63-4A89-BD1E-507D4019FB48_1_105_c.jpeg





まとめ

模擬試験は30分程度で解いていましたが、本番では何度も見直しをして結局60分ぐらい使ったと思います。
特に

  • いくつ選択する問題なのか?
  • 出力結果として問われているのはメソッドの返り値なのか?
    • 破壊的・非破壊的を判断する必要の有無が変わる

は見直しでカバー可能なポイントだったと感じています。

【Rails】MVCとは

先日、セレクトボックスで扱いたいデータの配列をモデルに定義する際に「選択肢を日本語表示したい」と思ったことから、キーを日本語名にしたハッシュを作成しました。

しかしながらモデルは「データを扱う役割」です。

「ビューでこう表示したい」や「日本語にしたい」など、モデルの仕事には関係のない、モデルが関知すべきでない都合を持ち込んでしまうのはNGであると学んだ出来事がありました。

Railsの各機能についての知識が不足しすぎていると感じ、その後調べたことのアウトプットの一環として記録するものです。



1. MVC(Model-View-Controller)とは

MVCは、アプリケーションの役割を分割して理解しやすくするためのデザインパターンの一つ。Railsはこのデザインパターンに従うルールになっているようです。

2. Modelとは

モデルとは、ActiveRecordと呼ばれるRailsの機能を介して、アプリケーションのデータベースと情報のやりとりを行うRubyのクラスのことを言う。 モデルは主にデータをどう扱うかを記述する役割であると言えそうです。

ActiveRecordとは

3. Controllerとは

コントローラはリクエストの意味を理解し、適切な出力を行なうための責任を持ちます。

入力されたURLからルーティングに従ってアクションを呼び出す役割。

4. Viewとは

実際のWebページにまとめる役割を担います。

コントローラによって実行されたアクションを受け、最終的にHTMLの形式で返す役割。

Railsの大前提

Railsでは「この機能はこう扱われるだろう」という想定がなされている

Railsは、最善の開発方法というものを1つに定めるという、ある意味大胆な判断に基いて設計されています。Railsは、何かをなすうえで最善の方法というものが1つだけあると仮定し、それに沿った開発を全面的に支援します。言い換えれば、ここで仮定されている理想の開発手法に沿わない別の開発手法は行いにくくなるようにしています。この「The Rails Way」、「Rails流」とでもいうべき手法を学んだ人は、開発の生産性が著しく向上することに気付くでしょう。


設定より規約が優先される(Convention Over Configuration):

Railsでは、Webアプリケーションで行われるさまざまなことを実現するための最善の方法を明確に思い描いており、Webアプリケーションの各種設定についても従来の経験や慣習を元に、それらのデフォルト値を定めています。このようにある種独断でデフォルト値が決まっているおかげで、開発者の意見をすべて取り入れようとした自由過ぎるWebアプリケーションのように、開発者が延々と設定ファイルを設定して回らずに済みます。

私は他のプログラミング言語を扱ったことがないので比較はできませんが、Railsはそれぞれの機能がどのような役割を担うのか意図を持った作成がなされており、リリース後の保守面を考えても、その意図に則った開発を心がけると非常に可読性も高いコードが目指せるのではないかと感じました。



まとめ

「ルーティング」「アクション」「ビュー」といった言葉自体は、Progateの学習などで知っていました。しかしながらRailsは非常によしなに多くのことを処理してくれるため、仕組みがそもそもあまりわかっておりませんでした。

エンジニアになってコードレビューを頂くようになってから、それがわかっていないと自分で意図を持ったコーディングができないと感じました。 (「なぜこのように書いたのですか〜?」と聞かれても曖昧な返答しかできない)

簡素ではありますが、今回記載したことでも知っていれば「〇〇だから〜〜いうふうに思ったんです」という考えぐらいはできたのではないかと感じました。 特にRailsは開発方法が定められているフレームワークだと知ったので、今後は各機能の役割や、用意された経緯を踏まえたコーディングを心がけたい所存です。

(冒頭のセレクトボックスについては、モデルには扱いたいデータの配列のみを定義し、helpers/application_helpr.rbにハッシュを定義して解決しました)

参考

https://railsguides.jp/

https://ja.wikipedia.org/wiki/Model_View_Controller

【Rails】gemを使わないで手軽にenumをi18nに対応させて日本語化する

不用意にgemを追加すべきでない場面もあるかと思い、学習を兼ねて取り組んでみました。 また同じようなやり方をしている記事も見当たらなかったので、記録として残すものです。



前提

今回は簡単なタスク管理アプリケーションを想定し、Taskモデルに["waiting", "doing", "done"]の3つを持つステータスカラムを列挙型で実装し、それをi18nでlocalizeして、[未着手, 着手中, 完了]で日本語表示しようとしています。

enum status: { waiting: 0, doing: 1, done: 2 }

結論

以下のようなコードになりました。

ja.yml
ja:
  activerecord:
    models:
      task: タスク
    attributes:
      task:
        id: ID
        name: タスク名
        created_at: 登録日時
        updated_at: 更新日時
        status: ステータス
        statuses:
          waiting: 未着手
          doing: 着手中
          done: 完了
セレクトボックスの選択肢を日本語表示
<%= f.select :status, options_for_select(Task.statuses.map { |k, _v| [t("activerecord.attributes.task.statuses.#{k}"), k] }) %>
タスク詳細画面での表示
 <%= t("activerecord.attributes.task.statuses.#{@task.status}") %>

↓日本語での表示ができました↓

スクリーンショット 2021-06-16 21.06.06.png

スクリーンショット 2021-06-16 21.24.13.png

translateメソッド

t("activerecord.attributes.task.statuses.#{@task.status}")の先頭ttranslateメソッドの別名メソッド(Railsガイドを参照)で訳文を参照します。

config/application.rbなどでconfig.i18n.default_locale = :jaと使用するロケール(言語)を設定しておくと、ロケールに合致する辞書ファイル(今回はja.yml)が選択され、activerecord→attributes→tasks→tatusesと順番に参照されて、今回は#{@task.status}waitingを登録しておいたので、この書き方で未着手が表示されています。

定数リスト取得メソッド

モデルファイルのenumに記載している複数個の定数リストを取得するメソッドのことで、モデルクラス.enumカラム名の複数形という形で使用します。(こちらを参照)

irb(main):001:0> Task.statuses
=> {"waiting"=>0, "doing"=>1, "done"=>2}


セレクトボックスの日本語表示を実装している箇所では、Task.statusesで取得したハッシュに対してmapメソッドを使用し、その後の#tメソッドで翻訳されたステータスと、そのままのステータスが入った配列の配列を作成しています。

irb(main):007:0> Task.statuses.map{ |k, _v| [I18n.t("activerecord.attributes.task.statuses.#{k}"), k] }
=> [["未着手", "waiting"], ["着手中", "doing"], ["完了", "done"]]

それをoptions_for_selectの引数に渡すことで、日本語での表示を実装しました。



まとめ

enumi18n対応が複雑みたいな記事を読んだことがあったので、とっつきづらいのかなあと思っていましたが、仕組みを理解した上で書いてみると思いの外手軽だったので、むやみにgemを追加することなく実装できて良いのではないかと感じました。

参考記事

https://railsguides.jp/i18n.htmlhttps://pikawaka.com/rails/enum