Greg Navis Profile picture
🖥 Fractional CTO 🛠 Creator of active_record_doctor 📢 Follow me for tweets about Ruby, Rails, Hotwire, and PostgreSQL
Oct 2 7 tweets 3 min read
🆕 There were a few interesting releases in the last few days, so I wanted to bring them to your attention in case you missed them.

1. PostgreSQL 17.
2. Solid Queue 1.0.
3. Kamal 2.0.
4. Hotwire Native.
5. @dhh's keynote.

Let's have a quick look at each. PostgreSQL 17

1. Vacuum, I/O performance, and query performance gains.
2. JSON_TABLE for converting JSON documents into tables.
3. More features added to MERGE.
4. Simpler upgrades when using logical replication + failover!

postgresql.org/about/news/pos…
Apr 28, 2023 11 tweets 4 min read
💡 Rails tip: Rails 7 shipped with error handling infrastructure

It's a small module, but I find it extremely useful, especially when integrating with third-party APIs, as you usually want to gracefully inform the user the API is down, but still report that internally.

Ready? At a high level:

- there are multiple subscribers registered with the error reporter
- each error is passed to each subscriber
- the reporter offers methods for detecting, reporting, and swallowing exceptions thrown by the app

Let's take a close look at those methods. Image
Apr 5, 2023 7 tweets 3 min read
💡 Ruby meta-programming tip: it's trivial to add support for object literals to Ruby

Object literals are frequently found in JavaScript: these are objects defined on the spot, both state and methods, without a prior class definition.

Let's try to add them to Ruby! ⬇️ Let's start with a JavaScript example: an app object comprised of a database connection and a router; there's a method to start the whole thing up.

The app object was instantiated without a class definition.

How would a Ruby counterpart look like? Image
Mar 25, 2023 9 tweets 3 min read
💡 Ruby meta-programming: lazy accessors are simple to implement and more robust than lazy computations via ||=

Meta-programming can be fun, productive, and helpful. Let's have a look at another example, including a bigger engineering lesson.

⬇️ Let's go! What's a lazy accessor?

It's an accessor with a block of code to determine a value. That block of code is called only on first use; subsequent calls reuse the value the block returned.

In short: lazy accessor = laziness + caching
Mar 24, 2023 12 tweets 4 min read
💡 Ruby meta-programming idea: final classes can be easily implemented in Ruby

I've actually published a gem whose first feature is exactly that. More on that later though. Let's understand the concept of final classes first.

Ready? Set? Go! What's a final class?

A final class is a class that cannot be inherited from. Any attempt to subclass it would result in an error (compile-time or runtime, depending on the language).

It's a foreign concept in Ruby land, so let's have a look at other languages.
Mar 8, 2023 9 tweets 3 min read
💡 Rails tip: as_json can be used to convert models into ... no, not JSON ... into hashes

It can be useful when building and working with APIs, so it's always a good idea to understand how it works. It's implemented by Active Model and is quite generic.

Let's dive in! 🤿 😅 Called without arguments it returns a hash including all columns in the model.

Is this a good idea? NO!

⚠️ Do that in a public API and it's guaranteed you'll leak sensitive data sooner or later. Therefore, you should use this rarely, if ever.

What's the alternative? Image
Feb 27, 2023 7 tweets 2 min read
💡 Ruby tip: hierarchical logger can be built in under 20 lines

Motivated by helping active_doctor_users identify specific parts of their code base that break the tool.

Logs benefit from structure, and it's trivial to add _some_ structure even if they're text-based.

Here's how Text logs shown as a sequence of lines fail to capture the call stack structure.

If line A is followed by line B then it's difficult to tell whether B is from the same function, a caller function, a callee function, or another place entirely.

Fortunately, it's easy to fix.
Feb 21, 2023 7 tweets 3 min read
💡 Ruby tip: when defining methods, it's easy to teach Ruby to tell the difference between

- no argument passed
- argument equal to the default value passed

⬇️ Code speaks louder than words, so let's jump right in! First, an example motivating the whole thread ... Let's start with an example of the problem.

Have a look at two method calls below: in the naive approach the "nothing passed" and "nil passed" approaches are indistinguishable.

Our goal: make them distinguishable!

What's great is it's actually quite simple ... Image
Feb 15, 2023 6 tweets 2 min read
💡 Ruby tip: object allocation and initialization are two separate steps

Usually we just call .new to instantiate a class. Did you know it's possible to allocate an object WITHOUT initializing it?

⚠️ Useless but interesting content ahead!

⬇️ Read on if you're intrigued! There's a method called .allocate. It returns an instance of a call that IS NOT INITIALIZED 😱

The $1M question is: can such object be initialized?

Attempting to call initialize will result in an error: the constructor is PRIVATE!

Fortunately, this is easy to fix! Image
Feb 15, 2023 6 tweets 2 min read
💡 Ruby tip: multiple arrays can be easily combined without duplicates

There's no need to convert to and from Set or any other tricks like that. It's all built into Array.

⬇️ Let's have a look at `|` and `union`: two relatively unknown `Array` methods. Example: we need to send reminders for two types of invoices: unpaid and overdue.

Problem: if an invoice is BOTH unpaid and overdue we may end up sending the reminder twice if we aren't careful

It's more likely when working with two separate set of model IDs.

What can we do?
Feb 8, 2023 10 tweets 3 min read
💡 Rails tip: Active Support offers an instrumentation API

I'm using it in a client project right now and need to say it's quite simple, yet powerful. Unfortunately, it's relatively obscure, too.

Let's put it in the spotlight today 🔦 There are two sides to instrumentation:

• Emitting events, including time measurements
• Subscribing to events

Active Support offers a simple API that handles both. We'll start with emitting events (which is simpler) and then proceed to subscribing and handling.
Feb 6, 2023 9 tweets 3 min read
💡 Ruby tip: use memoization to avoid running expensive operations twice or resolve dependencies automatically

I guess you may be intrigued A quick way to implement memoization is via ||=

Let's have a look at an example ChurnRiskDetector class. It uses single- and multi-line memoization. More statements can be memoized by wrapping them in begin/end.

There's a problem with this approach, though ... Image
Feb 3, 2023 6 tweets 2 min read
💡 Ruby tip: assertions usually accept an error message to show when they fail.

Let's have a look at three SIMPLE techniques that can make your test suite much more informative and easier to work with.

Let's start with a relatively unknown parameter to assert ... The last argument to assert is the error message. It's optional, so if you don't pass it the assertion will work, producing a potentially unclear message.

A bit of discipline (and a linter?) can greatly help make the test output more understandable.

That's not everything ... Image
Feb 1, 2023 6 tweets 2 min read
💡 Rails tip: Active Record supports the hstore column type in PostgreSQL

hstore = a map from strings to strings (or a null!)

No nesting, no arrays, no other types. And sometimes it's EXACTLY what you need!

Let's have a look at how to use it. First, you must enabled the relevant PostgreSQL extension. After the extension is enabled, you can use `hstore` as the column type.

The example below adds `feature_flags` to `organizations`. Image
Jan 28, 2023 8 tweets 3 min read
💡 Ruby tip: don't rely on libraries calling refinement-provided methods

I guess that may sound indecipherable, so let's unpack this step by step. This thread is based on my work on Feature Envy: a bunch of features from other languages implemented in Ruby.

Let's dive in! Refinements are a Ruby feature for safe monkey patching.

A refinement is a change to an already existing class. Refinements can be grouped in a module which then can be activated (via `using`) in a given scope.

The effect is classes are monkey patched WITHIN THAT SCOPE ONLY. Image
Jan 18, 2023 4 tweets 2 min read
💡 Ruby tip: hash keys and values can be easily transformed via

• transform_keys
• transform_values

Such small conveniences can make code much more readable.

Let's have a look ... transform_keys/transform_values are map-like methods that map each key or value respectively, and are helpful when only one part of a hash must be changed.

Example: converting keys to strings.

Code speaks louder than words, so have a look at the snippet below. Image
Jan 12, 2023 7 tweets 2 min read
💡 Ruby gem: YARD is a great tool for documenting Ruby code

I'm writing documentation for my soon-to-be-released gem, which is a great reason to talk about documenting Ruby.

Documentation, often neglected, is a huge factor in good developer experience.

Let's look at YARD, now. Code speaks louder than words, so we'll start with a piece of code.

Here's a snippet from the gem I'm working on. It makes use of several YARD tags, but it's the tip of the iceberg!

The resulting HTML document should look familiar to most who look up documentation online ... Image
Jan 9, 2023 13 tweets 4 min read
💡 Ruby deep-dive: Benchmark makes it easy to measure and compare performance of one or more pieces of code

Useful for:

1. Profiling
2. Picking the highest performer
3. Automating measurements as part of the test suite

Let's have a closer look at what it's got to offer. First, we need to require "benchmark". We'll have access to Benchmark and several methods implemented on it.

We'll explore each of these methods in turn, from simple to complex.
Jan 5, 2023 18 tweets 5 min read
🆕 Ruby 3.2 is out, so let's start 2023 by exploring what's new.

Many of the changes warrant separate deep-dives, but we can describe them briefly to raise awareness.

Let's roll! 1/16 New hook method! 🎉

Whenever a new constant is added to a module, .const_added is called with that constant's name as a symbol.

Example use case: automatic registration of classes inside a module with some third-party API
Dec 22, 2022 7 tweets 3 min read
💡 Ruby tip: be careful when storing test data in constants

Constants may look innocent, but can easily lead to flaky tests and implicit test ordering dependencies.

Let's understand what can go wrong! First, we need to clarify what "constant" means. In Ruby, it's an identifier that cannot be reassigned. The object it points though, can be modified.

⚠️ This is NOT what most people think of when they hear "constant" Image
Dec 21, 2022 5 tweets 2 min read
💡 Rails tip: Active Support adds convenience methods for working with time intervals and data sizes

• Make code more expressive and intention revealing
• Monkey-patching 🙈

⬇️ Let's have a look at what's available.
⚠️ Inconsistencies ahead! First, you can write 2.kilobytes instead of 2 * 1024 or 2048. The same is true for units up to exabytes.

Processing zettabytes, yottabytes, or hellabytes? Active Support won't help, but you must be coming from a distant future either way. 😉 Image