-
一意のIDを持たないデータベースでActiveRecordを扱う——重複ID問題への対処と教訓
時には、特殊な状況や制御できない事情によって、型破りな要件に直面することがあります。最近、私はデータベースのIDに一切頼らずにActiveRecordを使わなければならないという経験をしました。同じことを検討している方がいれば、別の方法を見つけることを強くお勧めします!それでは、話の続きに進みましょう。 決定はすでに下されていました。構造は同一ですがデータが異なる複数の小規模データベースを統合する必要があったのです。私がプロジェクトに参加したのは、チームがあるデータベースから別のデータベースへレコードをコピー&ペーストするスクリプトの仕上げを行っている、まさにそのタイミングでした。このスクリ
-
RubyのコードローダーZeitwerk徹底解説:クラスとモジュールを自動管理する
RubyのコードローダーZeitwerk徹底解説:クラスとモジュールを自動管理する Zeitwerkを使えば、クラスやモジュールがどこからでも利用可能になるため、プログラミングをよりシンプルかつ快適に進められます。 コードローダーとは? コードローダーとは、開発者が複数のファイルやフォルダにまたがってclassやmoduleを定義しても、明示的なrequireなしにコードベース全体でそれらを利用できるようにする仕組みです。Railsはコードローダーを活用している代表例です。Railsでは、モデルをコントローラー内で使う前にいちいちrequireを書く必要がありません。実際、Rails 6
-
Rubyでのログ出力をマスターする:LoggerとLogrageの使い方徹底解説
Rubyでのログ出力入門:LoggerとLogrageの使い方 ロギングは、アプリケーション開発において最も重要なタスクの一つです。ログは以下のような場面で活用されます。 アプリ内部で何が起きているかを把握したいとき アプリケーションを監視したいとき 特定のデータに関するメトリクスを収集したいとき 新しいプログラミング言語を学ぶ際、最初に選ばれるのはその言語がネイティブに備えているロギング機構でしょう。標準機能は通常、扱いやすく、ドキュメントも充実しており、コミュニティでも広く使われています。 ただし、ログデータの内容や扱い方は、企業の方針、ビジネスの性質、アプリケーションの種類に
-
Rubyで学ぶSOLID設計原則:変更に強いコードを書くための5つの原則
すべてのソフトウェアは時間とともに変化します。そして、その変更は予期しない連鎖的な問題を引き起こすことがあります。しかし、変化しないソフトウェアを作ることはできないため、変更そのものは避けられません。ソフトウェアが成長するにつれて要件も変わり続けるからです。私たちにできるのは、変更に強い(レジリエントな)設計をすることです。適切な設計には最初に時間と労力がかかりますが、長期的には多大な時間と手間を節約してくれます。密結合なソフトウェアは壊れやすく、変更によって何が起きるかを予測できません。 設計の悪いソフトウェアには、次のような悪影響があります。 コードが移動・再利用できない(不動性)。
-
最速のRubyテンプレートエンジンはどれ?ERB vs HAML vs Slim 徹底パフォーマンス比較
本記事では、Rubyで最も人気のある3つのテンプレートエンジン——標準搭載のERB、HAML、そしてSLIM——のパフォーマンスを実際に計測し、徹底的に分析します。 ベンチマークとは、自社のプロセスやパフォーマンス指標を業界最高水準や他社のベストプラクティスと比較する手法のことです。一方、ロードテスト(負荷テスト)は、システムに意図的に負荷をかけ、その応答を測定するプロセスを指します。 今回のゴールは、Rubyコードの実行時間を計測・レポートするためのメソッドを提供する「Benchmark」モジュールの使い方を学ぶことです。インラインテンプレートを作成してテストを実行し、3つのエンジンそれ
-
複雑な正規表現はもう卒業!単純なパーサーに置き換える方法(Ruby実装例)
正直に告白します。私は正規表現を扱うのがあまり好きではありません。日常的によく使うものの、/^foo.*$/ より少しでも複雑になると、立ち止まって考えてしまうのです。\A(?=\w{6,10}\z)(?=[^a-z]*[a-z])(?=(?:[^A-Z]*[A-Z]){3}) のような式を一瞥で読み解ける人も確かにいるでしょうが、私の場合は何分も検索して調べる羽目になり、決して気分の良いものではありません。Ruby のコードを読むときとの大きな違いです。 ちなみに、上記の例は正規表現の先読み(lookahead)について解説した記事から引用したものです。 状況:検索クエリのトークン化
-
Sidekiqをスマートにスケーリングする方法 ― AWS Auto Scalingでワーカーを優雅に終了させる
今年の初め、私たちは専用サーバーのホスティング環境からAWSへ移行しましたが、この決断は大正解でした。自動化の仕組みを数多く整えたことで、サーバーの細かい設定やメンテナンスにかける時間を大幅に削減できています。:) この記事では、処理するエラー通知の量が変動した際に、私たちのインフラストラクチャ内部で何が起こるのかを詳しく解説します。 スケーリングの仕組み 私たちの処理パイプラインはSidekiqに大きく依存しており、これまで非常に安定して稼働しています。パイプライン内の作業の大部分は、Auto Scalingグループに属するインスタンスによって処理されます。Sidekiqのバックログ(未
-
例外クラスへのコンテキスト追加が簡単に――honeybadger Ruby Gem 3.2の新機能
私たちは先日、honeybadger Ruby Gemのバージョン3.2をリリースしました。このリリースには、エラーレポートへのコンテキスト追加をこれまで以上に簡単に行える新機能が含まれています。 概要(tl;dr) honeybadger gemでは、任意の例外クラスに #to_honeybadger_context メソッドを定義できるようになりました。その例外のインスタンスが発生してHoneybadgerに報告されると、コンテキストが自動的にエラーレポートに含まれます。 class MyError < StandardError attr_reader :custom_a
-
Rubyのnilは危険:RustのOption型に学ぶ安全な値の処理方法
ここ半年ほど、私はRustでNESエミュレータの開発に取り組んできました。予想どおり、Rustについては多くを学びましたし、NESの内部構造に関してはさらに多くを学びました。しかし、この経験は私がRubyを見る目まで変えてしまったのです。 具体的に言えば、nilを返すメソッドに対して、かなりの疑心暗鬼に陥るようになりました。 何かを信じない者は、何にでも騙される Rubyにおいてnilとは一体何を意味するのでしょうか? 答えは「ほぼ何でもあり」です。メソッドがnilを返すとき、それは次のような意味があり得ます。 メソッドに戻り値が存在しない 通常は戻り値があるが、今回はたまたまない データベ
-
不安定なテストスイートの実例から学ぶ、決定論的なテスト設計の重要性
最近、信頼性の低さゆえに非常にストレスを感じるテストスイートを扱う機会がありました。本記事では、その実体験をもとに、テストスイートが不安定になる原因と、決定論的で信頼できるテストを設計するための考え方を解説します。問題のテストスイートの概要このテストスイートが対象としていたのは、Railsで構築されたAPI専用アプリケーションでした。テストコードはJavaScriptで書かれており、Chakramという「JSON RESTエンドポイントに対するE2E(エンド・トゥ・エンド)テストの実行を目的としたAPIテストフレームワーク」が使用されていました。最大の問題は、このテストスイートが決定論的ではな
-
Honeybadger Ruby Gem 4.0がついにリリース!新機能「before_notify」でエラー報告を自由自在にカスタマイズ
先週、Ruby用のhoneybadger Gemのバージョン4.0.0をリリースしました。このリリースには、長年待ち望まれていた機能が含まれており、Honeybadgerにエラー報告を送信する前に、その内容をこれまで以上に簡単にカスタマイズできるようになりました。また、必要とされていたリファクタリングを行い、いくつかの機能の削除や非推奨化も実施しています。ご安心ください。APIの大部分は変更されていないため、ほとんどのユーザーにとってアップグレードは比較的スムーズなプロセスとなるはずです。 注目の新機能:before_notify コールバック 以前のバージョンのhoneybadger G
-
AWS LambdaでRubyを使ってみた:Serverlessフレームワークによるデプロイ実践ガイド
AWS LambdaによるRubyサポートが発表されたとき、私はすぐにでも試したいほどワクワクしました。Honeybadgerでは以前からLambdaを活用しており、関数をRubyで書けるようになる日をずっと待ち望んでいたからです。新しいRubyサポートを数時間ほど触ってみた結果、Node.jsやGo、Pythonに割いていた時間を減らせるだろうと確信するに至りました。 簡単なサンプル AWSの公式ブログを読めばRuby on Lambdaをすぐに始められますが、本記事ではServerlessフレームワークを使ってRubyのLambda関数をデプロイする方法をご紹介します。このフレームワー
-
Rubyで肥大化するUserクラスを防ぐ――ジャンクドロークラス問題の回避策
Rubyはオブジェクト指向言語なので、世界をオブジェクトの集合としてモデル化しがちです。たとえば、2つの整数(xとy)をPoint(点)と呼び、Line(線)はその2つを持つ、という具合です。 このアプローチは多くの場面で有効ですが、大きな問題を1つ抱えています。それは、データに対する特定の解釈を他のすべてより優先してしまうことです。xとyは常にPointであり、Cell(セル)やVector(ベクトル)として振る舞うことはない、と決めつけてしまうのです。 では、Cellが必要になったらどうなるでしょうか。データの所有権はPointにあるため、PointにCell用のメソッドを追加することにな
-
UUIDとULIDを徹底解説!一意識別子の仕組みと使い分けを深く掘り下げる
先日、チームで雑談していたときのことです。DevOpsの達人であるBenが「あのシステムはUUIDじゃなくてULIDにしておけばよかった」とつぶやきました。 ベテランエンジニアらしく、私は特に決定的なことを言わず適当に相槌を打ち、その場を離れるやいなやこっそりGoogleで「そもそもULIDとは何なのか」を検索し始めたのでした。 2時間後。虚ろな目つきで調査を終えて戻ってきた私は、一意識別子の世界が想像以上に広大で奥深いものであることを痛感したのです。 ULIDの話に入る前に、まずは基本に立ち返って「UUIDとは何か」をおさらいしましょう。 「普通の」連番IDにはどんな問題があるのか? データ
-
アカウントセキュリティを強化:二要素認証(2FA)の導入とTOTPの仕組みを徹底解説
高額なインターネット料金にうんざりして、「隣人のセキュリティがザルなWi-Fiを勝手に使ってしまいたい」と思ったことはありませんか?それをためらわせていたのが、Honeybadgerの一要素認証フローだったという方に、朗報です。 ついに登場:二要素認証(2FA) 冗談はさておき、私たちはセキュリティを非常に真剣に考えています。ユーザーの皆様とそのデータをより安全に守るための重要なツールをご提供できることを、大変嬉しく思います。 単純に2FAの有効化手順だけを説明してもいいのですが、それでは面白くありません。そこで今回は、暗号技術の世界を軽やかに覗きながら、2FAがどのように動作するのかを
-
Honeybadgerのブレッドクラム機能とは?エラー調査を効率化する使い方と拡張術
本番環境でエラーが発生し、どんなに試しても開発環境やステージング環境でその問題を再現できない——そんな経験はありませんか?多くの場合、次のステップとして本番環境にデバッグログを仕込んでデータを集めることになります。しかし、ログとリクエストを紐付ける適切な手段がないと、特にインシデント対応中は非常に苦労します。 そこで私たちは、この課題を解決する機能「ブレッドクラム(Breadcrumbs)」を追加しました。 ブレッドクラムはログイベントによく似ていますが、エラーとともに保存・レポートされる点が特徴です。ログと同様にメッセージを含むだけでなく、ハッシュマップ形式のメタデータを持たせることもでき
-
Rubyで管理するPostgreSQLパーティションテーブル ― 古いデータの効率的な削除を実現するpg_partition_manager
なぜパーティションテーブルが必要なのか 私たちの主力PostgreSQLデータベースでは、古いデータを効率的に期限切れにするために、パーティションテーブルを活用しています。巨大なテーブルからまとめて大量のデータをDELETEすると、データベースのパフォーマンスが大きく低下してしまうためです。 実はPostgreSQL 10より前のバージョンには、パーティションテーブルのネイティブサポートが存在しませんでした。そのため当時は、pg_partman拡張機能を使ってパーティショニングを実装していました。この拡張機能は、PostgreSQLのテーブル継承を利用してパーティション対象テーブルの子テーブル
-
Ruby開発者のための文字エンコーディング、Unicode、UTF-8徹底入門
RubyでUndefinedConversionErrorやIncompatibleCharacterEncodingsといった例外を目にしたことはありませんか?目にすることはあっても、その意味を正しく理解できた人は少ないのではないでしょうか。この記事を読めば、文字エンコーディングの仕組みと、それがRubyでどう実装されているのかが分かるようになります。読み終える頃には、これらのエラーをより簡単に理解し、修正できるようになっているはずです。 そもそも「文字エンコーディング」とは何なのでしょうか? どんなプログラミング言語でも、私たちは文字列を扱います。入力として処理したり、出力として表示し
-
Rubyで学ぶビッグオー(Big-O)記法:アルゴリズムの効率を直感的に理解する
かつて「それのビッグオー記法は何ですか?」という質問を聞くことほど怖いものはありませんでした。学校で習った記憶はあるものの、数学(決して得意科目ではありませんでした)に関わる話題だったため、記憶から完全に消し去っていたのです。 しかし、キャリアが進むにつれて、私は次のような場面に直面するようになりました。 パフォーマンスチャートを眺める 遅いクエリのデバッグに苦戦する 「負荷が増えたときにコードは耐えられるのか検討しましたか?」と問われる そろそろ原点回帰して(分かりますかね?)ビッグオーを学び直そうと決めたとき、その驚くほどシンプルな本質に気づきました。この記事では学んだことを共有
-
Rubyにおけるデカップリング手法:委譲と依存性注入
オブジェクト指向プログラミングでは、あるオブジェクトが機能するために、別のオブジェクトに依存することはよくあります。 例えば、財務レポートを生成するためのシンプルなクラスを作ってみましょう。 class FinanceReport def net_income FinanceApi.gross_income - FinanceApi.total_costs end end この場合、FinanceReportはFinanceApiに依存していると言えます。外部の決済プロセッサから情報を取得するために、FinanceApiを利用しているわけです。 しかし、将来別のAPI