kent備忘ログ

お仕事と趣味生活と

10月の学習を振り返って

朝晩が寒く日中がいまだに暑かった10月ですが、学習を振り返りです。9月はRuby課題でのアウトプットが主体でしたが、10月は転じて主にSQLRailsに対するインプット月間となりました。

10月上旬

月の頭では、先月末から続いてSQLに関する以下の2冊の教材を読んでの学習でした。
  • スッキリわかるSQL入門 第3版

 SQLのクエリ文の基本から学び、データベースへの4つの命令パターンである取得(これが一番主で内容も重たいですが)、追加、更新、削除を各章に分け解説してます。
 章末毎にある問題集もボリュームが多く、クエリ文の作成を繰り返し学習出来ました。
また実在しているDBMS間での比較や違いを紹介していました。

  • 達人に学ぶDB設計

 初めに読んだ上記の本とは別の観点から、データベース運用について、概念設計・論理設計・物理設計と設計工程から解説していき、運用コストや運用方針に合わせたハードウェアの選定方法解説までありました。
論理設計ではテーブル設計におけるテーブルの段階を踏んだ正規化、ER図を用いたテーブル同士の関連性の可視化を学びました。後半では実務におけるDB設計のNGや望ましくない設計を紹介していました。

以下は典型的なクエリ文の例になります。

SELECT goods, MAX(price) AS max_price FROM sales_record
WHERE price > 1000
GROUP BY goods;

10月中旬~下旬

月の中頃からHTTP通信におけるRESTの概念について学びました。この次にRailsを学んだ際に気づきますが、既にRailsでは、ある程度RESTの概念に沿ったURI設計が備わっていることがわかりました。
続いて下旬に掛けては定番のRuby on Rails速習実践ガイド」を教材としてRailsでのWebアプリ開発について学びました。

 一度学んだRuby言語の復習から入り、Railsアプリのディレクトリ構造・MVCアーキテクチャの解説の後、基礎的なCRUD機能を備えたタスク管理アプリを作成しました。
次第に機能追加の解説に入り、ユーザアカウントとログイン機能の追加、ページネーションや画像アップロード機能を専用のgemライブラリを追加して実装する方法を学びました。

 同時に、実装したコードの自動テスト機能も追加し、Webアプリの動作に不具合がないかを人力ではなく、機械的に効率良く検証する方法も学びました。
後半では、実務の実態に応じた非効率な開発の注意点、Railsにおける開発時の守るべき点を学びました。

 これも例ですが、MVCの概念を前提にRailsアプリを実装していくと、以下ようなファイルから手をつけていくことになると思います。

routes.rb

Rails.application.routes.draw do
  root 'home#index'
  resources :users
  # get "users", to: 'users#index'
  # get "users/new", to: 'users#new'
  # post "users", to: 'users#create'
  # get "users/:id", to: 'users#show'end

users_controller.rb

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      session[:user_id] = @user.id
      redirect_to mypage_path
                           ⋮
end

index.html.erb

<h1>ログイン</h1>

<%= form_with scope: :session, url: login_path do |f| %>
  <div class="form-group">
    <%= f.label :name, 'ユーザー名' %>
    <%= f.text_field :name, class: 'form-control' %>
  </div>
  ⋮

10月30日に速習ガイドを読み終わり、31日から月の振り返り記事を書いているところですが、いよいよ来月からは本格的にRailsアプリ作成に取り組みます。今まで教材で学んだ事を忘れずにアウトプットできるよう心がけていきたいです。

「現場で使える Ruby on Rails 5速習実践ガイド」を読んで

今回は、「現場で使える Ruby on Rails 5速習実践ガイド」を読んだので、所感をまとめました。

良かったところ

 各章ごとにステップアップしていく感じでRailsアプリ自体の構成と、その実装コードをわかりやすく解説されていました。

 特に、他の教材では開始直後からMVCの説明に入り、各ファイルのコード記述が始まり、CRUD機能を備えたデモアプリ作成の流れになりますが、この書籍では、もちろんMVCの説明は入るのですが、いきなりアプリ作成から入るのではなく、Railsのファイル・ディレクトリ構成を含めた全体像の説明から入り、各機能の実装に移るといった流れで解説している為、全体のどの位置を解説しているか、分かりやすいと思いました。

 また一例ですが、データベース検索の際、RailsではSQLのクエリ文に対応したメソッドが用意されており、そのメソッドを使用しコードを実装良いのですが、本書ではクエリ文とメソッドの対応表が記載されている為、絞り込みにどのメソッドを使えば良いか一目でわかります。他にも、要所要所で使い分けごとに主要なコマンドが異なる場合は、一覧表を記載しています。
 その上、巻末にはアプリ開発の際に使用するRailsコマンドの一覧が掲載されており、逆引きのように調べる事ができます。  


学んだこと

第1章〜第2章

第3章〜第4章

  • 今回のwebアプリで使用するSlim・Bootstrapの導入
  • モデルとデータベースの実装
  • CRUD機能に基づいたコントローラとビューファイルの実装
  • クライアントから受け取ったデータの検証とモデルへの追加制限の実装
  • ユーザアカウント作成とログイン機能の実装
  • フィルタ機能を使用したコード重複の排除

第5章〜第6章

  • RSpec, Capybara, FactoryBotを使用したテストコードの実装
  • RailsにおけるRESTfulなルーティングについて
  • アプリ上での時刻の扱い方
  • 悪意あるユーザへのセキュリティ対策
  • アセットパイプラインについて

第7章〜第8章

  • データベース検索機能の追加
  • 確認メール送信機能の追加
  • ファイルアップロード機能の追加
  • CSV形式でのDBのインポート・エクスポート機能の追加
  • Ajaxを使用したサーバ通信の使用
  • YarnとWebpackerについて

第9章〜第10章

  • GitとGitHubについて
  • 複数人でチーム開発をする際の開発環境について
  • アプリケーションの複雑性に立ち向かう3つの鍵
    • その1、然るべきところにコードを書く
    • その2、上手に共通化する
    • その3、新しい構造を追加して役割を分担させる

難しかったこと

 第10章の「アプリケーションの複雑性に立ち向かう」から先の解説は、実務でアプリ開発をする中で、どのような形でコードを実装することがベストになるかを解説していますが、論点となるケースがチーム開発の中での考え方や、大規模なアプリを対象としている事がありました。
 現状、あまりアプリ開発をした事がなく、記載されているコードのイメージがしにくいですが、一方で、著者が述べていたように、「アップデート」と「複雑性」の2つの課題が生じる場合が十分にあることを念頭に、実務で行き詰まりそうになった際は、こういったケーススタディを読み返して問題解決の糸口にしたいと思いました。

本書も、Rails5を題材としてある為当たり前ですが、2023年現在主流となっているRails7で生じた疑問に関しては別途調べる必要があります。

その点に関しては同じく10章で著者も述べていた様に、Railsが元々3年程度という短いスパンで「アップデート」が繰り返されてきたという前提に立ち、近年執筆された書籍や、公式ドキュメントを参考にしたいと思います。

REST APIについて

Webアプリに限らず、今日のインターネット利用でほぼ無意識に利用されているHTTP通信、今回はそのHTTP通信を介して利用される「REST」な「API」について私なりに記事を書いてみたいと思います。

APIとは

APIとは自社サービスやその機能を第三者が再利用・拡張することができるようにしたインターフェースを指します。

  • これにより、自社サービスを元にした関連サービスの拡充が促進され、サービス自体の発展に繋がります。
  • 一方で第三者が自社のリソースを使用し易くなる為、リソースが圧迫される恐れがあります。この対策としては第三者のアクセスを一定的に制限するレートリミット対策が有効です。

このAPIをWebアプリ上で公開しているのが「Web API」になります。

RESTとは

RESTは「REpresentational State Transfer」の略で、分散型システムにおける設計ルールを定めたものです。

分散型システムというのは、サーバサイドにおけるwebの三層構造がよく例に挙げられ、

  • HTMLを生成するプレゼンテーション層
  • クライアントの要求や、データアクセスを相互に行うアプリケーション層
  • データの取得・管理を行うデータベース層

が相互に連携し合う中で、統一的な設計ルールを定めたものになります。

REST原則の中で特徴的なものは以下になります。

階層化システム
  • サーバサイド内の各システムの役割を決め独立させることで、各システムを効率よく使用することができる。
コードオンデマンド
  • クライアント側がサイトのコードをダウンロードして手持ちのローカル環境で実行できる事。これにより、サーバ側で新しいプログラムを随時構築することで、常に新しいコードをクライアント側へ提供可能。
統一インターフェース
  • URIで指定されたリソースへの操作を統一、動作を含まず限定的なインターフェースで実行可能。
ステートレス
  • 単一のリクエスト以外見る必要がなく、障害に強い。同時にリクエスト全体でサーバリソースを共有する必要がないので機能拡充が容易である事。
キャッシュ制御が可能
  • クライアント側に情報のキャッシュを持たせることにより、余分な通信が排除されリソースや拡張性が向上する。
上の原則を遵守して設計されたシステムをRESTfulなシステムといいます。このREST原則に沿って設計されたAPIが「REST API」と言えます。
REST原則沿った設計は、URIを使用したHTTP通信の中身であるHTTPリクエスト・HTTPレスポンスの内容を、統一された書き方で実装することにより実現されます。

URI設計

記述されたURIはリソースを表し、HTTPメソッドはそのリソースに対する操作を表します。
REST制約に沿ったURI・HTTPメソッドの例
  • リソースにmovieを指定し、HTTPメソッドを使用したCRUD操作例になります。
URI HTTP method
POST /movies POST
GET /movies/1 GET
PUT /movies/1 PUT
DELETE /movies/1 DELETE
REST設計では、URIの記述に重要なルールがあります。
  • URI自体は短く簡潔に
  • 単語の記述を省略形にしない
  • 全て小文字で記載すること
  • 単語同士を繋げる場合はアンダースコアではなく、ハイフンを使用すること
  • 単語は複数形を使用すること
  • (日本語のような)エンコードを必要とする文字列を使用しない
  • サーバ側のアーキテクチャ(使用プログラム言語の文法等)をURIに記述しない
  • クエリパラメータとパスパラメータの使い分け
    • クエリパラメータ(末尾にあるキーバリュー = 省略可能な場合に使用)
    • パスパラメータ(URI中に埋め込まれるパラメータ=一意なリソースを表す場合に使用)

また統一された設計ルールを使用するにより、実装時の間違いを防ぐことが容易になります。

達人に学ぶDB設計 徹底指南書を読んで

前回のSQL教本に続き、「達人に学ぶDB設計 徹底指南書」を読んだので、所感をまとめました。

良かったところ

 テーブル設計が前回の本より詳細にクローズアップされ、実務上の問題や論点を取り上げながらイラストや表を使用し、わかりやすく解説されていました。

 具体的には第1章から第5章までを使い、論理設計におけるテーブルの第1正規化〜第5正規化までを解説(一般的には第3正規化まで行えばほとんどのケースでカバー出来ます)
 物理設計に関しても、運用するテーブルやインデックスの大きさに応じたハードウェアの選定方法から、運用時のバックアップ体制の種類や方法などについても解説されています。

 各章末に掲載された練習問題も、DMLDDLに関する一問一答式ではなく、設問に提示されたテーブルの設計上の問題点や改善点を挙げることに論点を置いています。
 一方で既存のデータベース運用に見られる、作者からすれば考えつかない信じられないような設計や、設計者に依存してしまってバグが発生しやすい論理設計をパターン別に紹介しています。

また、これらの解説の中でとりわけ反復して挙げていることがあり、

だということです。
 これは実務においてもデータの整合性を優先させるか・データの検索や更新時の動作を優先させるかの妥協点を見出す上でヒントになると思いました。


学んだこと

第1章〜第2章

  • システム設計とデータベースについて
  • 3層スキーマDOAPOAの違い
  • 論理設計とエンティティの定義と正規化
  • 物理設計とテーブル・インデックス定義
  • ハードウェアのサイジングと運用時のバックアップ体制

第3章〜第4章

  • 正規化詳細解説(第1正規形〜第3正規形、第4正規形〜第5正規形)
  • ER図詳細解説(IE記法とIDEF1X記法)

第5章〜第6章

  • 相反する正規化とパフォーマンス(検索時と更新時)
  • インデックスと統計情報

第7章〜第8章

第9章


難しかったこと

 今回は前回と違い、クエリ文をひと通り理解しており、実務でSQLを扱ったことがある中級者以上向けになっています。
 書籍の冒頭から、前回難しいと感じていたテーブル設計の概要説明から始まり、概念設計・論理設計と正規化・物理設計へと踏み込んだ内容です。

 また、第6章から先は実務でデーターベースを運用する際、どのような設計で運用することがベストになるかを解説していますが、論点となるケースが利用者が何千・何万と存在する巨大なサービスのデータベースの場合も有りました。
 何も運用したことのない現状ではあまりイメージがピンとこないですが、一方で、実際に実務で行き詰まりそうになった際はこういったケーススタディを読み返して問題解決の糸口にしたいと思いました。

 その他に関しては、第1刷発行が2012年と10年以上前である為当たり前ですが、全編を通して物理設計がローカルでの環境構築が論点となっており、クラウド環境を利用した場合実務上の設計における解説が少ないです。
 基本的な考え方はローカルで環境を整える場合と変わらないと思いますので踏襲しつつ、近年執筆された書籍や信頼できるネット記事を参考にしたいと思います。

スッキリわかるSQL入門を読んで

学習の一環で 「スッキリわかるSQL入門 第3版 ドリル256問付き」を読んだので、所感をまとめました。

良かったところ

 SQL全般を扱った事がない人向けに、1から学習するように組まれており、初心者向けになっています。

 ただ、それだけで終わる内容ではなく、Ⅲ部・Ⅳ部と良い進めていく内に既存のデータベースを操作する以外にも、新規にデータベースのテーブルから作成する方法、実務におけるクライアントからの要望に基づく要件定義を定める方法まで解説されています。
 500ページ近いボリュームですが、解説文だけでなく、イラストや表を交えた説明の為、判りづらい箇所も丁寧に教える内容となっており、SQLを体系的に学べます。

 また、命令文や用語の説明だけでピンとこない場合も、各解説のサンプルコードが付属アプリの「dokoQL」記載されている為、そのコードを使ってハンズオンで学ぶ事が出来ます。 特に各章に設けられた例題は、学んだ事の理解度を試せます。

 その他、実在する各データーベースソフト毎の違いについても触れられており、同じ用語でも、一部の製品にはその機能がない旨や、使用する命令文の記述方法を製品毎に解説している為、どのソフトを実際に使用する場合でも、その仕様に沿った扱いを学ぶことが出来ます。
(特に巻末には相互のデータベースソフトの互換性や、各社の製品毎の違いを一覧表にしており、一目で比較することが出来ます。)


学んだこと

本書冒頭〜第8章まで

  • DMLによるSQLの基本操作、取得(SELECT文), 挿入(INSERT文), 更新(UPDATE文), 削除(DELETE文)解説
  • 式や演算子・関数・集計関数の解説
-- 第8章まで学べば下記のようなSQL文も書けます。

-- (例)今月初めて発生した科目を抽出したい場合

SELECT DISTINCT 科目 
  FROM 出納記録
 WHERE 科目
NOT IN (SELECT 科目 FROM 前月出納記録) 

(特に冒頭〜第8章のについてはSQLのテーブル操作の基礎となる部分であり、今後定期的に理解を深める為復習したいと思います。)

第9章〜第11章まで

第12章

  • テーブル設計

難しかったこと

 第Ⅳ部第12章の解説である「テーブルの設計」は、Webアプリケーションで必須であるデータベースの基本的な考え方となりますが、クライアントからの要望、現状の課題点を整理した上で、ER図を用いた要件定義(概念設計・論理設計と正規化・物理設計)が求められます。
 実務に於いても非常に重要で実践的な解説となっていますが、私自身、ER図というものを初めて耳にした形で、いざ実際に書いてみようとすると、手が動かない状況でした。

 これに関しては、第8章までに解説されているSQL構文同様、実際に構文を叩いて覚えるのと同様、提示された要件から図を何度か書く練習をする必要があると思いました。

 しかし、作者さんもおっしゃられているように、一度に全てを覚え切ろうとせず、実際に手を動かしてSQL文を書いてみる事と、実行結果を見て分からない事が出てきた時に、この本を読み返して理解を深めたいと思います。
(実際巻末には総合問題としての問題集が付属しており、本書を通じて学んだことを体系的に復習することが出来ます。)

9月の学習を振り返って

8月と大して変わらず暑かった9月ですが、学習を振り返りです。8月はRuby教材でのインプットが主体でしたが、9月は1ヶ月通してRuby課題に対するアウトプットに打ち込む月間となりました。

9月上旬

  • ターミナル上に計算結果を表示させるプログラムの実装。表示されるレイアウトも考慮して実装しなければならないが、ここで9月アップした別記事にもあるようにoptparseライブラリ・コマンドライン引数の学習、if, unless, rjustメソッド、raiseによる意図的な例外発生の実践的な活用法を学びました。
value = 1
unless value == 0
# value ≠ 0
  'hello' 
else
# value = 0
  'goodbye'
end
#=> "hello"


str = 'hoge'
str.rjust(5)
#=> " hoge"
str.rjust(10)
#=> "      hoge"

続いて、別ファイルからの標準出力を受け取り、受け取った文字列を解析し、Rubyプログラム側で用意した文字列に変換して出力するプログラムを作成しました。 この課題ではARGFの取り扱いと、transposeメソッドについて学習しました。

test_str = ARGF.gets.chomp
testtext
#=> "testtext"

arr1 = [1, 3, 5, 7]
arr2 = [2, 4, 6 ,8]
arr_cal = [arr1, arr2]
p arr_cal
#=> [[1, 3, 5, 7], [2, 4, 6, 8]]
p arr_cal.transpose
#=> [[1, 2], [3, 4], [5, 6], [7, 8]]

9月中旬~下旬

  • Rubyのクラスとインスタンスを使用して作成する課題に取り組んだが、当初、私自身の課題の解釈が間違っており、正解を導き出すのに時間が掛かってしまった。(根気よくコードレビューをして下さった方々、ありがとうございます。)
  • 課題に取り組む中、公式リファレンスでメソッドを探したり、チェリー本で文法の確認をしていたが、結果としてこの課題で、インスタンス同士の計算・比較方法、三項演算子・attr_readerの使い方、キーワード引数の指定方法、delete_at メソッド、ハッシュに対してのassoc,rassocメソッドを学びました。
test_score = 50
test_score.zero? ? '零点です' : "#{test_score}点です"
#=> "50点です"

hash_str = {water: 'blue', fire: 'red', leaf: 'green'}
hash_str.assoc(:water)
#=> [:water, "blue"]
hash_str.rassoc('green')
#=> [:leaf, "green"]
  • 9月末〜10月の頭現在では、SQLに関する基礎からテーブル設計までを網羅的に学習中。8月〜9月に学習したRubyと合わせてWebアプリケーション作成の礎として行きたいです。

optparseライブラリについて

Ruby学習の一環で、optparseライブラリを使用する機会があった為、アウトプットも兼ねて記事にしてみました。初めに公式リファレンスの解説では以下のように記載されています。

optparse を使う場合.

  1. OptionParser オブジェクト を生成する。
  2. オプションを取り扱うブロックを 変数 に登録する。
  3. <変数名>.parse(ARGV) でコマンドラインを実際に parse する。
上記の1、2の手順を先に行います。
1.ライブラリoptparseを呼び出し

optparse_test.rb

require 'optparse'
cmd = OptionParser.new
2.コマンドライン上のオプションとして指定したい値(今回の例の場合'-h'や'-m')を取り扱うブロックを、onメソッドを使用し変数に登録。

個人的にブロックを登録するというイメージが一番掴み辛かった。

optparse_test.rb

# コマンドライン上のオプション -h をブロックに格納
cmd.on('-h') { |val| }
# コマンドライン上のオプション -m をブロックに格納
cmd.on('-m') { |val| }
3. コマンドライン上のオプションに対応する値を、組み込み定数ARGVを使用して実際にパース(解析=プログラム内部で実行できる形式に変換)する。
出力は要素が文字列の配列形式 (ARGVに添え字を指定することで中の要素を取り出すことが出来ます)
結果、"ruby <ファイル名>.rb -h <値> -m <値>"で、使用できるオプションとその値を指定することが出来る。

optparse_test.rb

cmd.parse!(ARGV)
p ARGV
p ARGV[0]
p ARGV.class
p ARGV[0].class
p "今は#{ARGV[0]}#{ARGV[1]}分です"
❯ ruby optparse_test.rb -h 15 -m 30
["15", "30"]
"15"
Array
String
"今は15時30分です"

なお、parse!ではなくparseと記述すると、登録したオプション名まで一緒にパースされる

optiparse.rb

cmd.parse(ARGV)
p ARGV
p ARGV[0]
❯ ruby optparse_test.rb -h 15 -m 30
["-h", "15", "-m", "30"]
"-h"
余談ですがoptparseにはデフォルトで--helpオプションと--versionオプションが設定されており、それぞれ"<ファイル名>.rb --help"、 "<ファイル名>.rb --version"で呼び出すことができます。

"<ファイル名>.rb --help"では参照したファイルで使用できる(今回設定した)オプションの一覧が表示されます。

❯ ruby test_paper.rb --help
Usage: test_paper [options]
    -h
    -m

バージョン定数が定義されていると、"ruby <ファイル名>.rb --version"でバージョンが出力される。
(実際には与えられたARGVがパースされる前に定義、今回は変数cmdにOptionParserモジュールを設定した後に記述) optparse_test.rb

require 'optparse'
cmd = OptionParser.new
Version = "1.0.1"
❯ ruby optparse_test.rb --version
optparse_test 1.0.1