8tako8tako8’s blog

ソフトウェアエンジニア

【感想】「スッキリわかるSQL入門」を読んで

概要

SQLはバックエンドエンジニアに必須スキルであり、今回は知識の再確認のため、ミック本の次のステップとして有名な「スッキリわかるSQL入門」を読んだ感想です。

良かったところ

  • 基礎知識が整理できた
  • 一部知らないことを知れたこと

学んだこと

サブクエリをINSERT文で利用する

あまり使う機会はなさそうですが、サブクエリを用いてデータ追加する方法です。

# 平均所有ポイントより高いユーザーを高ポイントテーブルに追加
insert into high_point_users (id, name, point)
select id, name, point
from users
where point > (select avg(point) from users);

他のテーブルに登場する行のみ抽出したい

これは頻繁に使うパターンです。

# 高ポイントテーブルに登場するユーザーのみ抽出
select name
from users u
where exists
(
  select *
  from high_points_users hpu
  where u.id = hpu.id
);

truncatedeleteより高速

定番の知識ではありますが、テーブルの全件を削除したい時には、truncatedeleteより高速です。 今回はその理由をちゃんと理解することができました。

  • truncate:記録を残さずに全行削除するため高速(しかし、ロールバックできない)
  • delete:行ごとにログ記録が行われるため、大量のデータを削除する際にはパフォーマンスが低下する

まとめ

SQLの基礎知識を改めて整理するために、「スッキリわかるSQL入門」を読んだ感想を簡単にまとめました。新しく知られた知識はほとんどなかったですが、知識の再確認ができたことにより、確実に身についているとわかり自信が持てました。今後も、新しい知識だけでなく、既に知っていることの再確認は定期的にやっていこうと思います!

RailsアプリをDocker化してみた

はじめに

この記事では、Dockerfiledocker-compose.ymlを作成することで、既存のRailsアプリをDocker化する方法を紹介します。

前提条件

  • Docker Desktopがインストールされていること
  • 対象となる既存のRailsアプリが存在すること
  • DBはPostgreSQLを使用すること

Dockerfileの作成

RailsアプリのルートディレクトリにDockerfileを作成し、下記の内容を記述します。

FROM node:16 as build-stage

FROM ruby:3.0.2

# Install Node.js and Yarn
RUN mkdir -p /opt
COPY --from=build-stage /opt/yarn-* /opt/yarn
COPY --from=build-stage /usr/local/bin/node /usr/local/bin/
COPY --from=build-stage /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx

# Setup Rails App
RUN apt-get update -qq && apt-get install -y \
  build-essential \
  libpq-dev
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

イメージ軽量化のためマルチステージビルドしていますが、ここでは紹介しないので下記を参考にしてください。

docker-compose.ymlの作成

Railsアプリのルートディレクトリにdocker-compose.ymlファイルを作成し、以下の内容を記述します。

version: "3"
services:
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - db_data:/var/lib/postgresql/data

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
    environment:
      DB_HOST: db
      DB_NAME: myapp
      DB_USER: postgres
      DB_PASSWARD: postgres

volumes:
  db_data:

config/database.ymlの編集

Railsアプリのconfig/database.ymlファイルを編集して、PostgreSQLを使用するように設定します。

default: &default
  adapter: postgresql
  host: <%= ENV['DB_HOST'] %>
  database: <%= ENV['DB_NAME'] %>
  username: <%= ENV['DB_USER'] %>
  password: <%= ENV['DB_PASSWARD'] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_dev

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_prd

動作確認

下記のコマンドで、Dockerコンテナを起動します。

docker-compose build
docker-compose up

次に、データベースの作成です。

docker-compose run web rake db:create

コンテナ内でマイグレーションする。

docker-compose exec web bash
> rails db:migrate

http://localhost:3000/にアクセスして、アプリケーションが正常に動作していることを確認できれば完了です!

まとめ

この記事では、RailsアプリをDockerコンテナで実行するための基本的な設定を行いました。非DockerなものをDocker化するのは骨が折れると思いますが、Docker環境での開発のメリットは大きいので移行しておくいいかと思います!

P.S. 本番環境をEC2→ECSに移行するのは結構大変そう...

Rubyのoptparseを使ったコマンドライン引数の解析

はじめに

Rubyの標準ライブラリであるoptparseは、コマンドライン引数の解析を簡単かつ効率的に行うためのライブラリです。optparseの基本的な機能について説明し、使い方を紹介します。

基本的な使い方

使用するために、optparseを読み込みます。

require 'optparse'

onメソッドでオプションを定義します。また、どのオプションが指定されたかを保持するためにハッシュを使用します。

opt = OptionParser.new
option = {}
opt.on('-f', '--file FILENAME', 'input file') { |v| option[:f] = v }
opt.on('-m', '--month MONTH', 'input the month(1-12)') { |v| option[:m] = v }
opt.parse(ARGV)

puts "-f:#{option[:f]}, -m:#{option[:m]}"

上記のコードを実行するとコマンドライン引数を受け取れていることがわかります。

$ ruby optparse.rb -f input_file -m 1
-f:input_file, -m:1

定義されているオプションも簡単に出力できます

opt.on('-h', '--help', 'Show help message') { puts opt }

カレンダーを作る

Rubyでカレンダーを作成するのにoptparseを使ってオプション-mを実装しました。

# オプションなし
$ ruby calendar.rb
      4月 2023
月 火 水 木 金 土 日
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

# オプションで1月を指定
$ ruby calendar.rb -m 1
      1月 2023
月 火 水 木 金 土 日
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

なお、コードは下記になります。

require 'date'
require 'optparse'

def print_calendar(month = nil)
  year = Time.now.year # 現在の年
  month ||= Time.now.month # nilなら現在の月
  first_day = Date.new(year, month, 1) # 始まり
  last_day = Date.new(year, month, -1) # 終わり

  print_header(month, year)
  print_first_spaces(first_day.wday)

  (first_day..last_day).each do |date|
    print date.strftime('%e')
    print(date.sunday? || date == last_day ? "\n" : ' ')
  end
end

def print_header(month, year)
  puts "      #{month}#{year}"
  puts '月 火 水 木 金 土 日'
end

def print_first_spaces(wday)
  if wday.zero? # 日
    print '                  '
  elsif wday == 1 # 月
    print ''
  else # 火〜土
    print '   ' * (wday - 1)
  end
end

def valid_month(month)
  month && (month >= 1 && month <= 12)
end

# コマンドライン引数を取得
opt = OptionParser.new
option = {}
opt.on('-m MONTH', 'the month(1-12)') { |v| option[:m] = v }
opt.parse(ARGV)
target_month = option[:m]&.to_i

# オプションのチェック
if target_month && !valid_month(target_month)
  puts "#{target_month} is neither a month number (1..12) nor a name"
  return
end

# 出力
if target_month
  print_calendar(target_month)
else
  print_calendar
end

まとめ

optparseは、オプションの定義やヘルプメッセージの生成が容易に行えるため、コマンドラインツールやスクリプトを開発する際に非常に便利です。ぜひ使ってみてください。

【感想】「プロを目指す人のためのRuby入門」を読んで

概要

Rubyのキャッチアップをすることになり、Prodateで学習した後の入門書で有名な「プロを目指す人のためのRuby入門」を読んだ感想です。

良かったところ

さすが有名な著書ということもあり情報量が素晴らしく良かった。よく使われるテクニックが載っているので、たくさんあるRubyの文法から重要なもの掻い摘んで勉強できて良かった。

悪かったところ

特に悪いと思ったわけではないが、、、 入門書の割にボリュームが凄いので、Ruby初学者は全てマスターしようとせずに、こんな書き方があるんだーくらいで読み進めていくのが良さそうでした。

学んだこと

&.ぼっち演算子

メソッドを呼び出されたオブジェクトがnilでない場合はその結果をnilだった場合はnilを返す。

str&.upcase # strがnilならばnil、nilでないならupcaseの結果となる

||=nilガード

変数がnilまたはfalseであれば値を代入する。

sum ||= 10 # sumがnilまたはfalseならば10を代入する

これは、下記のように評価されるから

sum || sum = 10

!!を使った真偽値の型変換

!!を使うと、?で定義したメソッドを短く書ける。

def user_exists?
  !!find_user
end

難しかったこと

文法が多すぎるので、どの書き方がよく使用されるか見極めるのが難しかった。現場ではマニアックな文法に出くわす機会が多そうな言語なので、その都度調べて習得していく。

まとめ

Rubyの文法は多すぎて習得するのは難しいが、その中でも重要なものについては特筆されていたので学習しやすかった。頻繁に使われそうなものはこの機会に習得して今後のコーディングに役立てていきたい。

覚えておきたいvimとtmux操作

概要

VSCode等を使用しているとvimtmuxについては使用する機会は少ないが、vimはサーバー内での設定ファイルの変更で、tmuxはサーバーのログ監視で活躍しそうなイメージがあるので、基本操作について整理しておく。

vim

たくさんあるvimキーバインドやコマンドで絶対に覚えておきたいものをまとめてみました。 :set number:set listは結構使っています。 visual blockモードは覚えてもすぐ使い方を忘れるので今回はリストから外しました。

キーバインドorコマンド 説明
esc Normalモード
i Insertモード
:wq 保存して終了
:q! 保存せず終了
dd 1行削除
{数値}dd {数値}行削除
yy 1行コピー
{数値}yy {数値}行コピー
P ddやyyで保持した行をペースト
:set number 行番号を表示
:set list 制御文字を表示
gg ファイルの先頭に移動
G ファイルの最後に移動
{数値}gg {数値}行目に移動
gg ファイルの先頭に移動
/{検索したい文字列} 文字列を検索
n 次の検索結果に移動
N 前の検索結果に移動

tmux

tmuxは使い慣れていないので、これぐらいなら覚えられるだろうとまとめてみました。

コマンド 説明
tmux tmuxを起動
tmux ls セッション一覧を表示
tmux a -t {セッション名} 指定のセッションにアタッチ
Control + b d デタッチ
tmux kill-server tmuxのシャットダウン
Control + b % 左右に分割
Control + b " 上下に分割
exit ペイン破棄
Control + b ↑↓←→ ペインを移動
Control + b { ペインの順序を前方向に入替
Control + b } ペインの順序を前方向に入替

tmuxの使用例として2つのログ監視で使用するデモを行いました。ターミナル複数並べるより見やすいです!

下記がログ出力用のシェルスクリプトです。

#!/bin/bash

logfile="test.log"

while true; do
  random_number=$((RANDOM % 3 + 1))

  case $random_number in
    1)
      message="testlog A"
      ;;
    2)
      message="testlog B"
      ;;
    3)
      message="testlog C"
      ;;
  esac

  echo "$(date) - $message" >> $logfile

  sleep 2
done

まとめ

これぐらいは覚えておいた方がいいと思ったものをまとめてみました! とは言っても使ってないと忘れるので、たまにはvimでコーディングしてみるのもアリかなって思ってます(笑)

参考

現役シリコンバレーエンジニアが教える NeoVim(VIM) + Tmux + Zsh 入門