行動すれば次の現実

ほどよくモダンなシステム開発を目指しています。メインテーマは生産性、Ruby、Javascriptです。

ChatGPTに負けない技術ブログの書き方

ChatGPTのような言語モデルが登場したことで、情報の収集や問題解決が容易になりました。しかし、それによって技術ブログの存在意義が低下したわけではありません。むしろ、技術ブログが果たすべき役割がさらに重要性を増したと私は考えます。

ググり力がなくても問題が解決できる時代に

ChatGPT登場前は、自分で問題を解決するためには、疑問点を分解して検索エンジンで検索するための「ググり力(ググラビリティ)」が必要でした。しかし、ChatGPTが登場したことで、検索エンジンでの検索に頼る必要が少なくなり、疑問点をそのまま入力すれば答えが得られるようになりました。

これによって、ググり力がなくてもある程度の問題であれば解決できるようになったと言えます。

ChatGPTは個別事象の大量製造機

技術ブログは、個別の技術的な問題や事象について、深堀りした情報を提供しているケースが多くあります。そのため、読者は自分自身の問題について類似の技術ブログを検索し、問題解決のための情報を得ることができます。

全く同じ事象というのはなかなかありませんので、ブログの内容の本質を理解して応用する力が必要とされていました。

しかし、ChatGPTが登場したことで、個別の事象について最適な回答を瞬時に提供することができるようになりました。今や、読者が抱えている問題についての技術ブログが存在しなくても、ChatGPTが最適な回答を提供する世界になりました。そのため、ChatGPTは個別事象の大量製造機と言えるかと思います。

これからの技術ブログの立ち位置

ChatGPTの登場により、情報収集や問題解決に必要な知識がより簡単に得られるようになりました。しかし、技術ブログはまだまだその存在意義があります。今後の技術ブログの立ち位置について、以下に私の考えを示します。

技術の深堀りや現場で活かされる実践的な内容

自分自身が体験して技術的な事象や問題について、深堀りした内容や付随情報を提供することで、ChatGPTとは異なる価値を提供できると考えます。現場レベルの実践的なノウハウや、いろいろな事象をつなぎ合わせた複合的な内容について発信することで、読者にとって有益な情報を提供することができます。

例えば、自分でWebサイトを作成するときに、JavaScriptを利用してスムーズな動きを実現する方法について知りたいとしましょう。このような問題に直面した場合、技術ブログは大きな助けになります。

JavaScriptについて十分な知識がなくても、技術ブログを通じて、実践的な手順や具体的な例を知ることができます。さらに、技術ブログは、読者にとって重要な実践的なアドバイスを提供することもあります。これらの情報は、プログラマーが日々の作業において直面する問題を解決するための貴重な情報源となります。

1つのテーマについてのシリーズ記事

技術ブログは、1つのテーマについて、複数回にわたってシリーズ記事を書くことで、より深く掘り下げた内容を提供することができます。例えば、入門書のようにターゲットを絞ったシリーズ物にすることで、読者にとってより興味深く、わかりやすい形で情報を提供することができます。

セルフブランディングとして活用

技術ブログをセルフブランディングのために活用することができます。自分自身のポートフォリオとして、自分が行ったプロジェクトや、取り組んだ技術についてブログにまとめることで、自分自身のスキルアップや就職活動の際に有益な情報を提供することができます。

また、自分自身の作業ログとして技術ブログを活用することで、自分自身が行ったことを記録することができます。

システム開発に関する思想的な内容

自分自身が考えるシステム開発に関する思想的な内容を発信するために、技術ブログが有効な手段と考えられます。思想には正解はありませんので、自分自身の考え方を発信することができます。

システム開発には、開発者の思想や哲学が大きな影響を与えるため、技術ブログを通じて、開発者の思想的な観点や、開発におけるベストプラクティスなどについて情報提供することができます。

例えば、システム開発におけるアジャイル開発やDevOpsなどの手法、コードの品質や保守性、可読性についての考え方など、より思想的な内容についても技術ブログを通じて発信していくことが有効です。

さいごに

ChatGPTの登場により、個別の事象に関する記事ばかりを書いていると、この先はなかなか読まれなくなるのではないかと考えます。

しかし、技術ブログは、単に個別の事象を解決するための情報提供だけでなく、自分自身が学んだ知識や経験を整理し、スキルアップやキャリアアップにつなげることができる貴重な手段です。また、他の人に役立つ情報を提供することで、業界の貢献につながると考えます。

技術ブログは自己成長や社会貢献に繋がる重要な存在であるため、私は今後も積極的に記事を書いていきたいと思います。

ファイルを指定の件数ごとに分割するLinuxコマンド

10,000行あるrow.csvを1,000行ごとに分割してファイルを生成する例を説明します。

コマンド例

split -l 1000 -d rows.txt rows_
  • -lオプションには分割する行数を指定します。
  • -dオプションを指定すると、ファイル名の末尾につく数字の連番が付与されます。
  • rows_の部分にはファイル名の接頭辞を指定します。この接頭辞に数字の連番が付与されます。

実行後すると以下のファイルが生成されます。

rows_00
rows_01
rows_02
rows_03
rows_04
rows_05
rows_06
rows_07
rows_08
rows_09

このままでは拡張子が付いていないので、下記のスクリプトを実行してcsvの拡張子を付与します。

rename.sh

#!/bin/bash

for f in "$1"*
do
    mv -- "$f" "${f}.csv"
done
sh rename.sh rows_

実行後すると以下のファイルに変更されます。

rows_00.csv
rows_01.csv
rows_02.csv
rows_03.csv
rows_04.csv
rows_05.csv
rows_06.csv
rows_07.csv
rows_08.csv
rows_09.csv

Heroku Data for Redisをアップグレードする方法(v4 to v6)

Herokuからredisのバージョンをv6にアップブレードするようにと催促メールが届いたので対応しました。 公式のアップグレード手順に従って対応しましたが、それだけだとエラーが発生してしまいましたので記事にすることにしました。同じ轍を踏まないためにも参考なれば幸いです。

Herokuからのメール(抜粋)

Running up-to-date software versions is essential for maintaining a highly-available and secure fleet of Heroku Data for Redis instances. Your Redis database redis-xxx on your-app is running a deprecated version (4.0.14) and will not be supported after 30 Jun, 2023.

Redis6ではTLS接続が必須になるため設定ファイルに注意!

Redis6からはPremiumプラン以上の場合はTLS接続が必須となったようなので、Sidekiq等でRedisの接続定義を変更する必要があります

Sidekiq.configure_server do |config|
  config.redis = {
    url: ENV["REDIS_URL"],
    # ↓この部分を追加
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
  }
end

Sidekiq.configure_client do |config|
  config.redis = {
    url: ENV["REDIS_URL"],
    # ↓この部分を追加
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
  }
end

この定義を追加しなかった場合、OpenSSL::SSL::SSLError (hostname "xxxxxx" does not match the server certificate):というエラーが発生してアプリからRedisに接続ができなくなってしまいます。

なぜVERIFY_NONEなのかというとHeroku内部ではSSLを使用していないためです。HerokuのルーターレベルでSSLを終了させて、内部接続にはHTTPSを使用しているため、VERIFY_NONEで問題ないとのことでした。

https://stackoverflow.com/questions/65834575/how-to-enable-tls-for-redis-6-on-sidekiq

アップグレード手順

上記の考慮を踏まえてアップグレードを実行します。 基本的には公式のアップグレード手順と同じことをしています。

1. メンテナンスモードをON

heroku maintenance:on

2. アップグレード実行

heroku redis:upgrade --version 6.2

3. アップグレード進捗状況の確認

heroku redis:info

=== redis-angular-51206 (REDIS_URL)
Plan:                   Premium 0
Status:                 preparing (version upgrade in progress)
Created:                2021-09-08 20:41
Version:                5.0.12
Timeout:                300
Maxmemory:              noeviction
Maintenance:            not required
Maintenance window:     Tuesdays 21:00 to Wednesdays 01:00 UTC
Persistence:            AOF
HA Status:              Available
Requires TLS:           No
Keyspace Notifications: Disabled

私の環境の場合、preparingからavailableに変わるまで20分程度の時間が掛かりました。

4. メンテナンスモードをOFF

heroku maintenance:off

終わりに

以上でアップグレード作業は完了です。 途中OpenSSL::SSL::SSLErrorが発生してかなり焦りましたがすぐに対応できて良かったです。

テスト環境でもリハーサルでアップグレードをしたのですが、その時はエラーが発生しませんでした。なぜ発生しなかったかというとテスト環境ではRedisをPremiumプランにしていなかったためです。Premium未満の場合、TLS接続は必須ではないためOpenSSL::SSL::SSLErrorのエラーが発生しないため防ぐことが出来ませんでした。

テスト環境でも同スペックの構成をしておく必要があるのだと改めて痛感しました。。

参考

https://ogirginc.github.io/en/heroku-redis-ssl-error https://devcenter.heroku.com/ja/articles/connecting-heroku-redis#connecting-in-ruby

【超簡単】HerokuのpostgresDBのbackupデータをrestoreする方法

以下のコマンドで簡単にバックアップしたファイルを使って、簡単にリストアすることが出来ます。

heroku pg:backups:restore b042 DATABASE_URL --app your-appname
  • b042の部分はバックアップデータの名称を指定します
  • DATABASE_URLの部分は、本番環境を指定する場合はこのままで良いです

参考

Heroku PGBackups | Heroku Dev Center

外部キー(null許可)を複数持っているテーブルで検索する時のSQLクエリのサンプル

レガシーシステムの改修案件で以下のような正規化されていない条件で検索することがありましたので、記事にまとめました。

テーブル設計

  • orders (注文)

    • id
    • supplier_id
    • customer_id
  • suppliers (取引先)

    • id
    • is_active (boolean)
  • customers (顧客)

    • id
    • is_active (boolean)

例えば注文テーブルがあり、「取引先の注文」と「顧客の注文」のいずれかを一つのテーブルで管理しているとします。どちらも設定されることはシステムとしてありえないと仮定します。

この注文テーブルから、取引先がアクティブ(is_active=TRUE)である、または顧客がアクティブ(is_active=TRUE)であるテータを抽出したい場合のクエリを紹介します。

SQLのサンプル

SELECT
    orders.*
FROM
    orders
    LEFT OUTER JOIN
        suppliers
    ON  suppliers.id = orders.supplier_id
    LEFT OUTER JOIN
        customers
    ON  customers.id = orders.customer_id
WHERE
    (suppliers.is_active = TRUE OR suppliers.id IS NULL)
    AND
    (customers.is_active = TRUE OR customers.id IS NULL)

Activerecordで実装する場合

Order.left_outer_joins(:supplier, :customer)
  .merge(where(suppliers: { is_active: true })
    .or(where(suppliers: { id: nil })))
  .merge(where(customers: { is_active: true })
    .or(where(customers: { id: nil })))

【Carrierwave+fog-aws】特定バケットへのアクセス権限を持ってS3にアップロードさせる方法

RailsアプリでS3にファイルをアップロードする場合、Carrierwaveとfog-awsを使用することが多いと思います。複数アプリをS3バケットを切り替えて使用する際に、ユーザーごとにバケットのアクセス権限を与えることで、思わぬ事故を防いだり、セキュリティを向上させることができます。

今回は、特定バケットのみアクセスできる権限を持ったCarrierwaveとfog-aws周り環境設定を解説いたします。

インストールとアプリ側の設定

Gem

  • carrierwaveとfog-awsをインストールします
  • 環境変数管理用のdotenvもインストールします
gem 'carrierwave'
gem 'fog-aws'
gem 'dotenv'

Carrierwave設定ファイル

  • Carrierwaveの設定ファイルを作成します

config/initializers/carrierwave.rb

require 'carrierwave/storage/abstract'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage :fog
  config.fog_provider = 'fog/aws'
  config.fog_directory = ENV['S3_BUCKET_NAME']
  config.fog_public = true
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: ENV['S3_ACCESS_KEY'],
    aws_secret_access_key: ENV['S3_SECRET_ACCESS_KEY'],
    region: 'ap-northeast-1',
    path_style: true
  }
end

Modelへのマウント

  • 例として、Paymentモデルのreceipt_fileにReceiptUploaderをマウントします

app/models/payment.rb

class Payment < ApplicationRecord
  mount_uploader :receipt_file, ReceiptUploader
end

app/uploaders/receipt_uploader.rb

class ReceiptUploader < CarrierWave::Uploader::Base

  def extension_white_list
    %w[pdf]
  end
end

AWSの設定

AWSではS3とIAMのサービスを使用します。

S3の設定

S3バケットの作成を作成します。

S3バケットの作成

  • 任意の名前でバケットを作成します。

  • パブリックアクセスはデフォルトのオフのままにしておきます。それ以外の項目は要件に応じて任意で変更してください。私の場合はデフォルトのままであることが多いです。

IAMの設定

huzzah-bucketのみにアクセスできる権限(ポリシー)を作成して、ユーザーに付与します。

ポリシーの作成

  • ポリシーを使用すると、ユーザーに対して権限を割り当てることができます。JSONエディターで、特定バケットに対してアクセスを許可する操作を設定します。

JSONエディターの内容

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::huzzah-bucket"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::huzzah-bucket/*"
        }
    ]
}
  • 任意のポリシー名を入力してポリシーを作成します

ユーザーの作成

  • 任意のユーザー名を設定します。コンソールへのアクセスは無効のままにしておきます。

  • 「ポリシーを直接アタッチする」を選択して、先程作成したポリシーにチェックしてユーザーを作成します。

ユーザーに対してアクセスキーの設定

  • ユーザーの作成が完了したら、再度ユーザーの詳細画面を開きます。「セキュリティ認証情報」タブに移動して「アクセスキーを作成」をクリックします。

  • 「コマンドラインインターフェース」にチェックを入れてアクセスキーを作成します。

  • アクセスキーとシークレットアクセスキーが作成されますので、忘れないように控えておきます。

環境変数の設定

.envに先程控えたアクセスキーとシークレットアクセスキーとバケット名を登録します。

S3_BUCKET_NAME=huzzah-bucket
S3_ACCESS_KEY=xxxxxxx
S3_SECRET_ACCESS_KEY=zzzzzz

お疲れ様でした

作業は以上となります。お疲れ様でした!

HerokuのPostgreSQLをバージョン11から14にアップグレードしてみた

Herokuから以下の通知が来ました。

  • PostgreSQL 11 reaches End of Life on 2023-Nov-09. Due to security and operational concerns, Heroku cannot run unsupported software as a service. Therefore, the following database will need to be updated before 2023-Nov-09:

  • PostgreSQL 11は2023-11-09に終了を迎えます。Herokuでは、セキュリティや運用の観点から、サポート対象外のソフトウェアをサービスとして運用することができません。

PostgreSQL 11の終了の期限が迫ってきたので、重い腰を上げてバージョンを上げることにしました。実際やってみると思っていたより簡単に終わったので思いとどまっている方の参考になれば幸いです。

アップグレード方法の選定

基本的には公式のアップグレードガイドに沿った説明になっていますが、実際作業してみての所感などを追記していますので、合わせて確認するとより理解ができるかと思います。

PostgreSQLをアップグレードする方法は2つの選択肢があります。

  1. pg:upgradeを使用する方法
  2. pg:copyを使用する方法

私はpg:copyを使用する方法を選択しました。 理由は以下のとおりです。

  • pg:copyの方が作業がシンプルであるため
  • DBは10GBを超えているがダウンタイムを許容できるため
  • Database Bloat(使用されなくなったレコードによって占有される余分な領域)を解消したいため

アップグレード手順

1. 新しいデータベースを作成する

アップグレード後のデータベースを構築します。--versionを指定しない場合、2023/01/21時点ではversion 14が適用されます。

heroku addons:create heroku-postgresql:premium-2 -a your-appname

2. アプリをメンテナンスモードをオンにする

データベースへの書き込みを停止させるためにメンテナンスモードにします。

heroku maintenance:on -a your-appname

3. 新しいデータベースにコピーする

既存のデータベースの内容を新しいデータベースにコピーします。 HEROKU_POSTGRESQL_CYAN_URLの部分は新しいデータベースの名称です。PostgreSQLの管理画面やheroku pg:infoコマンドなどで確認できます。

heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_CYAN_URL -a your-appname

ちなみに私の環境の場合は20GB程度のコピーに15分ほど掛かりました。また、肥大化の部分がカットされて容量が8GB程度に下がりました。

4. 新しいデータベースに切り替える

新しいデータベースを使用するように切り替えます。

heroku pg:promote HEROKU_POSTGRESQL_CYAN_URL -a your-appname

5. アプリをメンテナンスモードをオフにする

メンテナンスモードをオフにします。以後アプリは新しいデータベースを使用するようになります。

heroku maintenance:off -a your-appname

6. 古いデータベースを削除する

アプリが安定稼働していることを確認したら、下記のコマンドまたは管理画面から古いデータベースを削除します。

heroku addons:destroy HEROKU_POSTGRESQL_LAVENDER -a your-appname

終わりに

以上で作業は終了です。思っていたよりも簡単にアップグレードできたので、一安心しました。 細かいことを意識しなくても手順に沿えばアップグレードできてしまうあたりは、さすがのHerokuだと改めて感心しました。