改めて「REST」について学ぶ

RESTについて学ぶと、「何いってんだこいつ、そんなの当たり前のことだろ?」となります
REST自体は2000年頃に提唱された概念で、当時は斬新だったらしい
いま当たり前だと思えるのは、それだけ優れていて、普及しきっているということです

RESTとは?

RESTはREpresentational State Transferのことで、
分散型システムにおける設計原則群という意味になります
分散型というのは、ネットとかWEBのことです(今どきのブロックチェーンやweb3のはなしではないことに注意)
つまりRESTとは、WEBシステムを設計する基本的なルールです

RESTfulとは?

RESTに則って設計されたシステムのことです

REST APIとは?

RESTfulなAPIのこと
つまりRESTのルールに則って設計されているAPIのことです

RESTの6原則

RESTの原則は4原則だったり、6原則だったりするけど、ここでは6原則とします
6原則は以下です

  • クライアント・サーバー
  • ステートレス
  • キャッシュ制御
  • 統一インターフェース
  • 階層化システム
  • コードオンデマンド

一つずつ説明します

クライアント・サーバー

クライアントサイドとサーバーサイドを明確に分離する
UIはクライアント側で、制御して
データはサーバーサイドで制御する
クライアントサイドがトリガーで、サーバーサイドは受け身

ステートレス

サーバーサイドはクライアントの状態を保持せず、必要な情報を明記して送信する
つまり、「前に言ってたアレだよ、アレ」というものを認めない

キャッシュ制御

クライアント側で、HTTPレスポンスをキャッシュできる
ここで言うキャッシュはHTTPレスポンスのことであり
cssとかjsとか画像などをキャッシュで溜め込めることとはまた違う

統一インターフェイス

統一インターフェイスはさらに4つに分けられる

リソースの識別
名前がつけられて、サーバーサイドに保持できるデータのことをリソースという
URIを使って、リソースを識別できること

表現を用いたリソース操作
リソースの断面とは、クライアントが必要としているリソースの一部のことで、 断面を使って、リソースをCRUD操作できること
動画を特定の秒から再生できるとか、
一度書き込んだ文章を修正できることを指す

自己記述メッセージ
メッセージ内容が何であるかをヘッダーに記述すること

HATEOAS
レスポンスに、前のページや次のページのハイパーンクを含めること
現在あんまり使われてない

階層化システム

WEBとAPとDBを明確に分ける
コンポーネントを作って使い回す

コードオンデマンド

1回サービスをリリースした後、
サーバーサイドを更新することで、
クライアントサイドのコードを更新できること

REST APIの設計レベル

REST APIには設計レベルがあって

レベル0 HTTPを使っている

レベル1 リソースの概念を導入している

レベル2 HTTPの動詞が導入されている

レベル3 HATEOASが導入されている

HATEOASは普及しなかったので、実際ではレベル2を目指すべきであり、 RailsやLaravelなどのモダンフレームワークでアプリを作ると、自然とレベル2を満たしたことになる

CRUD操作におけるURIとHTTPメソッドの具体的な定義例

以下movieというリソースで、実際にテーブルを作ってみる

URI HTTPメソッド コントローラとアクション 意味
/movies get movies#index 動画の一覧を読み取る
/movies/new get movies#new 新規投稿フォームを開く
/movies post movies#create 新規投稿を保存させる
/movies/:id/ get movies#show 動画の詳細ページを開く
/movies/:id/edit get movies#edit 動画を編集する
/movies/:id put/patch movies#update 動画の編集を保存する
/movies/:id delete movies#destroy 動画を削除する

まとめ

RESTは2000年頃に提唱され、現在では十分普及している概念なので、
勉強するとあたり前のことばかりでした。
Railsでアプリを開発していると、自然とRESTに沿った開発になるけど、
一度意識して学ぶことで、解像度度が高くなり、理解がより進んだと感じた。

RailsやLaravelなどのアプリで開発するときはCRUDの定義をちゃんと覚えましょう。 一度覚えてしまえば、ずっと使えます。

『達人に学ぶDB設計徹底指南書』から学んだこと

学んだこと

実際この本からは、理屈や知識よりは、自力で正規化したり、ER図を書くことを学んだ
これができるようになったことがとても大きい進歩

一般的な話

RAIDのことが書かれているけど、いまはもうSSDが主流だと思う
AWSなどにはスナップショットが取れる機能があり、それを使えばいい

差分バックアップ増分バックアップがややこしい
差分バックアップは、フルの後の差分を積み上げたものをいう
増分バックアップは、フルの後の1回ずつの個別にバックアップしたものをいう(積み上げてない)

冗長というのは、同じデータを複数の場所で保管すること
理論設計では、エンティティの抽出、エンティティの定義、正規化、ER図を書くという順番でやる
外部キーが参照できなくなる時があるので、先に参照元を削除してから、参照先を削除する
テーブル名やカラム名は、日本語ではなく英語で書く
テーブル名は小文字から始まって、複数形

正規化とER図

第1正規化は、一つのセルに一つの値
第2正規化は、主キーに対する部分的関数従属を取り除く
第3正規化は、間接的な、関数従属を取り除く
1対1の関係であれば、同じテーブルに書くのであんまりない
多対多の関係は2つの1対多に分けて、中間テーブルを作る
ER図には色々規格があるけど、書き方にそんなに差はない
0以上か1以上かは意識して、分ける必要がある
あえて、正規化を崩して、SQLを簡素にして、パフォーマンスを上げる事ができる(けど、自分はまだ控えておきたい)
インデックスや統計情報で、パフォーマンスをアップすることができる

やってはいけないアンチパターン

一つのセルに複数の値をいれる(第1正規化に反する)
一つのカラムに2つ以上意味を持たせて、何処かで切り替わる
主キーと他のカラムの構造が同じだから、違うテーブルを一つのテーブルにまとめる
テーブルを縦か横に分割すること(テーブル設計の構造の方を優先することが大事)
主キーや外部キーの方を揃えない
マスタテーブルが複数あって、統一されない

グレーゾーンの設計

主キーの役割を果たすものがないので、代理キーとしてカラムを作る(idはこれに当てはまるので、自分はこれはいいと思う)
繰り返しの列を持つテーブル(これは正規化して、複数のレコードで表せばいい)
その場しのぎで思いついたようなカラムを追加すること(あとでややこしくなる、ちゃんとしたテーブルかビューを作る)
多段ビュー(負荷が重くなったり、人間が見てややこしくなる)

良かったところ

アンチパターンやグレーパタンが載っていて、やらないようにしようと思った
実際練習して正規化やER図の作成ができるようになった

難しかったところ

パフォーマンスの話があるけど、自分がまだそこ到達してないので頭に入らなかった
なぜ木をDBに収納しようとするのかよくわからなかった

まとめ

一つ前に『スッキリわかるSQL入門』を使ってSQLの構文を詳しく学んだが、 その後この本で設計について学ぶと、 ER図を書いたり、正規化したりすることができるようになり、 実際のサービスのDBを設計できるようになる

また、アンチパターンやグレーゾーンの設計が載っており、
それを知ることで、より正しいDB設計ができるようになる

自力でDBを設計できるようになったのは大きな進歩
ビジネスをDBに落とし込むのにまだ練習が必要だと思う

『スッキリわかるSQL入門』で学んだこと

良かったところ

とにかく説明がわかりやすい
なぜ、これはこうなっているのかや、内部ではこう処理している
などちゃんと解説してくれる所が良かった
この本1冊やれば、体系的にSQLが学べる

付録に練習用ドリルが付いていて、WEBで練習できる

わかったこと

全体像

DBの操作の言語は、DDLDML、DCLがある
DDLはデータベースの構造の定義
DMLが具体的なCRUD処理
DCLが権限の付与や解除など
基本的に学ぶのはDBのCRUDの操作なので、DMLがメイン

NULLはそもそもtrueかfalseを帰す以前に存在しないのでIS NULL, IS NOT NULLを使って判別する

NOT,AND,ORが、カッコなしである場合、
NOT, AND, ORの順に処理される、必要に応じてカッコをつけると、カッコの中が先に処理される

主キーは複数のカラムによって、構成される、複合主キーが存在する

DISTINCTがSELECTにないときは、実はALLが省略されている

引数をとらない関数は、関数名の後ろに()をつけない

COALESCE関数を使うと、SELECTするときにnullがある場合、別の値を代わりにいれることができる

集計関数は、一つのグループに対して、値を一つ帰す、自分でグループ化しなければ、一つのグループとして、一つの値を帰す
集計関数を使う場合は、GROUP BYに使ったものと、集計関数をSELECTに書き、集計に関係ないものは書かない

JOIN

FRON, JOIN ON, WHERE, GROUP BY, 集計関数, HAVING, ORDER BY, LIMITという順で処理される
副問合せは、返り値にパターンが有り、単一の値か、1カラムのベクターか、カラムが複数か、一つのテーブルとして2次元のデータかを帰す
テーブルとして返ってくる副問合せは、FROMの中で使うことができる
1列のデータが返ってくるタイプは、INなどでWHEREの中で使う
JOINと書いた場合はINNER JOINで、両方のテーブルにあるデータだけ出される
LEFT JOINは左側のテーブルのすべてのデータが出て、右は一致したものだけが出る、RIGHT JOINはその逆
LEFT JOINとRIGHT JOINは書き換えができるけど、全部LEFTで書いたほうがわかりやすい
FULL JOINは、左右のテーブルのすべてのデータが出てくる

トランザクション

トランザクションは、一連の処理がすべて終わらないと、ロールバックと言って、なかったことになる
すべての処理を完了することをコミットという

トランザクションには、複数の分離レベルがあり、分離レベルが高いと、安全だが速度が遅くなる
デッドロックは、お互いがロックしようとするときに起きるけど、DBMSが自動に解決してくれるシステムがある

その他

外部キー制約をつけると、他のテーブルの主キーを参照する。削除や変更するときは順番に気をつける必要がある

特定のカラムをインデックスとして設定できる、インデックスを設定したものを参照するときはすこい早くなる
結合済みのテーブルをビューとして定義すると、次からシンプルなSQLでSELECTできる

DBにはACID特性といって、原子性、一貫性、分離性、永続性のことで
原子性とは、中途半端なデータをいれないこと
一貫性とは、データベースに狂った値が入らないこと
分離性とは、複数の処理を同時実行しても問題ないこと
永続性とは、データを消滅せず保存できること

バックアップは、バックアップしたデータと、それ以降のログファイルを使う、ロールフォワードという

DB設計

設計には、概念設計と論理設計と物理設計がある
概念設計でER図を作る
論理設計でキーを設定したり、正規化をする
正規化は第6まであるけど第3までやればいい
第1正規化は、一つのセルに一つの値をいれるようにする
第2正規化は、主キーに対する部分関数従属をなくす
第3正規化は、間接的な関数従属をなくす
物理設計では、特定のDBMSにいれるための設計をする

難しかったところ

実際にSQLの文を自分で組み立てるのが難しかった
要件をER図に落とし込むことや第三正規化やることも練習が必要と感じた

まとめ

SQLについてこの本は本当によくまとまっていて、すごいわかりやすい
逆に今まで、自分が体系的に学んでこなかったので、知識が頭の中で散らばっていたと感じた 自分が第3版を買ったときに第4版がでたので、できれば新しい方を買ってください

optparseを使って、ターミナルで動くカレンダーを作る

optparseってなに?

optparseというのはRubyのライブラリで、 ターミナル側へ入力したオプションを処理してくれるものです。 これに使うことでcalで呼び出せるカレンダーを作ることができます

全体のコードは以下のようになります

# frozen_string_literal: true

require 'date'
require 'optparse'

option = {}
opt = OptionParser.new
opt.on('-m MONTH', Integer) do |month|
  option[:month] = month
end
opt.parse!(ARGV)

if option[:month] && (option[:month] < 1 || option[:month] > 12)
  puts "#{option[:month]} is neither a month number (1..12) nor a name"
  exit
end

year = Date.today.year
month = option[:month] || Date.today.month
first_day = Date.new(year, month, 1)
last_day = Date.new(year, month, -1)

puts "#{year}#{month}".center(20)
puts '月 火 水 木 金 土 日'

print '   ' * ((first_day.wday + 6) % 7)

(first_day..last_day).each do |day|
  day = if day.sunday?
          "#{day.day.to_s.rjust(2)}\n"
        else
          "#{day.day.to_s.rjust(2)} "
        end
  print day
end

詳しく解説します

ライブラリの呼び出し

require 'date'
require 'optparse'

これは、デフォルトではdateとoptparseのライブラリを使えないので、呼び出しています。 dateは日付関係のライブラリです。 optparseは、この記事のメインのテーマのライブラリで、引数でオプションを受け取って、処理するためのものです。

オプションを受けれるようにする

option = {}
opt = OptionParser.new
opt.on('-m MONTH', Integer) do |month|
  option[:month] = month
end
opt.parse!(ARGV)

optionというハッシュを初期化します。

OptionParserのインスタンスを作り、optに入れます。
onメソッドはルールを定義するものであり、parse!をすることによって実行されます。

optのonメソッドを使って-mとその引数を、整数でMONTHとして受取り、
更にそれをmonthとして、ブロックに渡します。
ブロックの中で、monthをさっき作ったoptionというハッシュに、キーは:monthとして入れます。 そうすると、optionの中が{ month: 9 }のようになります
opt.parse!(ARGV)により、
ターミナルで引き受けた["-m", "9"]のような配列を、onで定義した通りに実行します。 これで-mと月を書くことで、月を指定できるようになりました。

1~12月以外が入らないようにする

if option[:month] && (option[:month] < 1 || option[:month] > 12)
  puts "#{option[:month]} is neither a month number (1..12) nor a name"
  exit
end

optionの:monthの値が存在し、かつ1から12以外の場合に、エラーのメッセージを出力し、終了させます

日付を定義する

year = Date.today.year
month = option[:month] || Date.today.month
first_day = Date.new(year, month, 1)
last_day = Date.new(year, month, -1)

1から12の月が入力されたことを想定して、
まず今日の日付から、年を出します。
次に、もし引数として、月を受けた場合はそれを使い、なければ今月をmonthに代入します。
月の初めの日をfirst_dayに入れます。
月の最後の日をlast_dayに入れます。

年と月と曜日の文字を出力する

puts "#{year}#{month}".center(20)
puts '月 火 水 木 金 土 日'

ここから出力する部分を作っていきます。 最初に、中央揃えで、先ほど定義した年と月を出力します。

最初の空白を揃える

print '   ' * ((first_day.wday + 6) % 7)

これは、最初の日の曜日を揃えるために空白を出しています。
今回は、月曜日から始まるので、このように書きます。
wdayは日曜日なら0、月曜日なら1を返します。
(wday + 6)を7でわって余った分だけ、半角スペース3つ与えるときれいに並びます。
最初の日が月曜日の場合、(1 + 6) % 7 = 0なので、きれいに左に並びます。

実際に日付を出力する

(first_day..last_day).each do |day|
  day = if day.sunday?
          "#{day.day.to_s.rjust(2)}\n"
        else
          "#{day.day.to_s.rjust(2)} "
        end
  print day
end

(first_day..last_day)と書くことによって、この範囲を、末尾を含むレンジオブジェクトとします。
eachにブロックを渡し、先程のレンジオブジェクトの中身をdayとして、if文を書きます。

day.day.to_s.rjust(2)というのは、レンジメソッドのアイテムをdayとして、その中の日の値を取って、文字列に変換し、2文字になるようにスペースで埋めます。

カレンダーは月曜日から日曜日まで並ぶので、日曜日のdayの後ろに改行文字をつけて、それ以外の日の後ろに半角スペースを付けます。 dayを再定義します。

そしてprintを使ってdayを一つずつ出力します

まとめ

複数の基礎的な操作を組み合わせることによって、カレンダーを作ることができました。 わからないことあったら、基礎に戻って復習しましょう。 今回のポイントは、OptionParserを初期化して、onメソッドで定義して、parse!メソッドでそれを実行することでした。

『プロを目指す人のためのRuby入門』を使って、Rubyを学んだ感想文

学んだこと

  • シンボルについて基礎的な知識を得た。
  • ほぼすべてのオブジェクトが何らかのクラスに所属し、そのクラスのメソッドを使える。
  • レンジクラスを学んだ。
  • クラスから他クラスのセッターを呼び出して、値を渡すことができた。
  • 継承やモジュールを使いこなせるようになった。
  • クラスもまた、クラスクラスのインスタンスである。
  • カーネルがいろんなものに組み込まれていて、putsやgetはオブジェクトの部分を省略して、色んなところで呼び出している。
  • テストを書いてみた、まだ身についてない。
  • 正規表現について、以前より理解がまして、アレルギーが減った。ブログ記事がとてもわかりやすい。

自分はオブジェクト指向の部分を重点的に意識して学んできたことを、この記事書きながら、自覚しました。 やっぱりオブジェクト指向が一番たいへんだと思っているからです。

良かったところ

大事なことについて網羅的に書かれているので、
読むことでRubyの理論について効率よく学ぶことができた。
この本を1週読み切ることで、同じような分厚い本でも、学んでいけるという自身がついた。

悪かったところ

本自体はいいのですが、
難しいし、分厚いので、読んでいるとメンタルが削れました。
1日中ずっと読んでいるのはきつかったです。

対策

本の中身を、セクションなどで細かく分割したり、
1日に消化するページ数を減らして、実際にプログラミングする時間も確保すること。

難しかったところ

この本はそもそも分厚いし、全体的に難しい。
アマゾンのレビューを見ると、他言語の経験者がRubyを勉強するのに向いているとあったが、
初学者がいきなり、この本を読むと難しさを感じる 。

対策

もっと簡単な教材を使ってルビーの理解を深めてからトライすること
実際にプログラミングして、経験をためてから読むこと

具体的に難しかったこと

  • 正規表現オブジェクト指向、例外処理は、この本を読む前に学んでいたので比較的スムーズだったけど、難しいと思う
  • Proc(ブロックのオブジェクト化)やパターンマッチ、テストを書くことはあんまりやってこなかったので難しさを感じた。

まとめ

Rubyに関しては、この本を深く読むことで、かなり理解が進みます。
1週通読して、一部手を動かして、学んできました。
まだ理解できない部分もたくさんありますが、かなり濃く学ぶことができ、Rubyにたいする理解が進みました。
時間と精神的なゆとりができて、
もっと実際手を動かしてRubyの経験を積んでから、また読み直したいと思います。
本当に素晴らしい本です。

RailsのプロジェクトをDcoker化してみる

このブログ記事は私が、 HCのDockerの課題のリポジトリからコピーして、 Docker上でRailsのプロジェクトを動かす練習の記録です。 以下はそのやり方について解説します。

自分のリポジトリにコピーをする

Use This Template

Use This Templateと書かれた緑のボタンを押して、そこから自分のリポジトリとして新しく作ります。 新しく作った自分のリポジトリからローカルにクローンします。 ローカルでdockerというブランチを切ります。 以降、dockerブランチで作業します。

ruby用のDockerfileを作る

FROM ruby:3.2.2

RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
nodejs \
postgresql-client \
yarn

WORKDIR /docker-ruby
COPY Gemfile Gemfile.lock /docker-ruby/
RUN bundle install
COPY . /docker-ruby

FROMでRubyの3.2.2のイメージを取ってきます。

RUNで apt-get updateでapt-getのリストを更新して、
apt-get installでRailspostgresqlに必要なファイルをインストールしています。

WORKDIRで作業フォルダを指定します

COPYでGemfileとGemfile.lockを作業フォルダに移してしてから、 RUN bundle installを使ってRailsをインストールします。 そのあとホストのカレントディレクトリのものをすべて、コンテナの作業フォルダにコピーします。 この順番でやることによって、Dockerのレイヤーをうまく使って、パフォーマンスがいいです。

docker-compose.ymlを編集する

version: '3'

volumes:
  docker-ruby-db:

services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    volumes:
      - ".:/docker-ruby"
    tty: true
    stdin_open: true
    environment:
      - "DATABASE_PASSWORD=postgres"
    depends_on:
      - db

  db:
    image: postgres:12
    volumes:
      - "docker-ruby-db:/var/lib/postgresql/data"
    environment:
      - "POSTGRES_PASSWORD=postgres"
version:3

versionに3を指定します。

volumes:
  docker-ruby-db:

これで、docker-ruby-dbというボリュームを確保します。

services:の中にwebとdbを作ります。 web側にrubyrailsを入れて、 db側にpostgresqlを入れます。

web:の中に書いてあるもの

build .

でカレントディレクトリでビルドをします

command: bundle exec rails s -p 3000 -b '0.0.0.0'

これは、コンテナが起動したら、実行するコマンドで bundleからrails sでサーバーを起動して ポートを3000番に指定して、 b- に'0.0.0.0'を指定することで、すべてからアクセス可能にします。 これを指定しないとホストからアクセスできません。

ports:
 - "3000:3000"

これを指定することで、ホストの3000番に来るアクセスをコンテナの3000番に渡します。

volumes:
  - ".:/docker-ruby"

これで手元のフォルダとコンテナ内の作業フォルダを同期させます。

tty: true
stdin_open: true

これで、デフォルトで、ターミナルからインタラクティブにコマンド打てるようにします。 いわゆる-itオプション。

depends_on:
  - db

Railsで使うDBを指定しています。 servicesのwebの下で定義したものを指定しています。

environment:
  - "DATABASE_PASSWORD=postgres"

これは環境変数を定義していますが、本番環境では別のやり方でやったほうがいいです。 この環境変数はコンテナの中に渡されます。

db:の中に書いてあるもの

  image: postgres:12

自分でDockerfileでビルドせずに、イメージを取ってきています。 postgresの12を取ってきています。

  volumes:
    - "docker-ruby-db:/var/lib/postgresql/data"

上の方で確保したボリュームに、コンテナ内のDBの保管場所を合わせることで、 DBの中身を永続化できます。

  environment:
  - "POSTGRES_PASSWORD=postgres"

DBの方のコンテナに渡す環境変数です。 これはrootのパスワードですが、本番環境では別の渡し方をしたほうがいいです。

railsのconfig/database.ymlを編集する

config/database.ymlを編集する

  host: db
  user: postgres
  port: 5432
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>

デフォルトにスクリーンショットのように4行を追記します。 接続するDBとユーザー名とポート番号とパスワードを入れています パスワードはdocker-compose.ymlで入れたものをとってきます。

docker-compose up -d

これでコンテナがたり上がります -dを入れると、デタッチモードになり、ターミナルを操作できます。

コンテナが起動した後の作業

Railsがすでに立ち上がりました。
ブラウザからlocalhost:3000にアクセスするとエラーが出ますが この時点でRailsはすでに起動しています。

ホストコンピューターからwebコンテナに入ります

docker-compose exec web bash

webコンテナのbashに入ってから以下のようにします

rails db:create

少し待ってから

rails db:migrate

これでDBが作成されて、RailsからDBの設定がされます。

docker-compose down
docker-compose up -d

再起動したら、アプリが起動しました!

Github Pagesで、無料でサイトを公開しよう

Github pagesを使うことで、無料でhtml,css,jsで構成されたファイルをホームページとして公開することができます。
ここでは、リポジトリを作って、index.htmlをとその他ファイルをリポジトリに入れたあとの、公開する設定について説明します。

リポジトリはパブリックにしてください。

settingを選びます

settingを選びます

Pagesを選びます

Pagesを選びます

deploy form a branch(Branchからデプロイをする)を選んで
ブランチ名と/(root)を選択します
自分で追加したサブディレクトリを基準にして、サイト公開したかったのですが、
自作ディレクトリを選択できませんでした。
だからrootで公開すればいいと思います。

mainから別のbranchを切って、そこからデプロイしたい場合はそのbranchを選びます。

ブランチを選んで、rootのままで、saveします

しばらく待ちます

更新するとurlがでてくるので urlを貼ったり、共有するかvisit siteをクリックしてサイトに飛べるようになります 。

デプロイできました

まとめ

githubを使うことで、無料でサイトを公開することができました。