Err the Blog, revisited

Before there was GitHub, there was Err the Blog. Chris Wanstrath and PJ Hyett wrote one of the essential Rails blogs of early Rails era. Therein, many of the idioms and ideas we use to build Rails apps today were documented or born.

I’d figured this site was offline, as are most things from the mid-2000s. ‘Lo and behold, it’s still online in its pink-and-black glory. Lots of nostalgia on my part here.

There was a Big Moment here, in my career and Ruby/Rails, where an abnormal density of smart people were together in a moment (if not a community) and the basis of my career took shape. It was good times, even if we didn’t yet have smartphones or doom-scrolling.

Allow me to reflect on what I found as I went through the archives.

How we built things back then

Rails circa 2.x was a quite unfamiliar game to the modern developer. REST conventions for CRUD controllers had just taken hold, and were not yet the canonical way to structure Rails code. There was a lot of experimentation and many of the solutions we take for granted today (namely, dependencies) were extremely unsolved back then.

DRY Your Controllers — err.the_blog – ideas about CRUD controllers before CRUD controllers were the thing in Rails (2.0 I think?). That said, if you were to write this now… I’d have issues with that. 😆

My Rails Toolbox — err.the_blog – this probably represented the state of the art for building Rails in its time… 17 years ago. 👴

Vendor Everything — err.the_blog – I followed this approach on my first Rails app. It was a pretty good way to keep things going for one, enthusiastic developer at the time. But RubyGems, Bundler, etc. are far better than vendor’ing these days. And, one of the crucial leverage points for working in the Rails space.

How we built things back now

Some things stay the same. For example, the need to fill in the gaps between Rails’ conventions for organizing your app, enhancing Ruby via ActiveSupport, and the lack of a suitable approach to view templates that satisfies writing code, testing code, and building front-ends.

Organize Your Models — err.the_blog – early memories of attempting to organize files in a Rails 1.2 app despite numerous headwinds presented by Rails itself. (IMO, organizing a Rails app by folder+namespace has really only started to work after Rails 6.0).

Rails Rubyisms Advent — err.the_blog – a love letter to ActiveSupport’s extensions to the Ruby language. Many of these are in the Ruby language now, thankfully! ActiveSupport (still) rubs some folks the wrong way, but it remains one of my favorite things about Rails.

View Testing 2.0 — err.the_blog – amazingly, there’s still no good story here. It’s all shell games; write e2e tests instead of unit tests, use object-like intermediaries instead of ERB templates, etc.

How we stopped building things that way

Rails has always had flawed ideas that need re-shaping or removing over time. Mostly in making ActiveRecord as good of an ecosystem participant as it is a query-generation API.

with_scope with scope — err.the_blog – ActiveRecord scopes are way better now! I think with_scope remains, at least in spirit, in the Rails router API.

ActiveRecord Variance — err.the_blog – wherein our heroes discover inconsistencies in AR’s find* APIs and patch their way to more predictable operation thereof.

How I was even more excited about Ruby

Err the Blog was not first on the Rails hype wave of the mid-2000’s. But, it was consistently one of the best. Every time a new post was published, I knew it was worthwhile to make time to read the latest post. I learned a lot about my favorite things about Ruby from Err: writing little languages and Enumerable.

Pennin’ a DSL — err.the_blog – I could not read enough posts on building DSLs in my early Ruby days. It was the feature I was excited about in Ruby. Thankfully, it’s a lot easier to do ‘macro magic’ in Ruby these days. And, hooking into the idiomatic ways to write Rails-style declarative bits is much better now.

Select a Reject — err.the_blog, Allow Me to Inject — err.the_blog – love letters to Enumerable, my favorite thing about Ruby. And Full of Ambition — err.the_blog – fan fiction about Enumerable and ActiveRecord finally uniting in a loving relationship.

We have to go back

If you liked this, you may also enjoy revisiting:

  • has_many :through – Josh Susser’s blog was one of the first to explain how Rails works and how to leverage it
  • Red Handed – _why the lucky stiff’s blog
  • Envy Labs – a Rails blog from the Rails Envy folks, Gregg Pollack and Jason Seifer
  • Caboose – part community, part collective, an early nexus of Rails talent

And so, I come to the end of my nostalgia. Now, I must go forward.

Make code better by writing about it

Writing improves thoughts and ideas. Doubly so for thoughts and ideas about code.

Writing, about software or otherwise, is a process wherein:

  1. thoughts and ideas are clarified
  2. ideas are transferred to colleagues
  3. culture (of a sort) is created by highlighting what’s essential and omitting what’s transient

Documenting code, as a form of writing, is a process wherein:

  1. the concepts and mechanics in the code are clarified
  2. what’s in our head today is made available to our teams (and ourselves) in the future
  3. culture happens by highlighting what’s intended and what’s “off the beaten path” when working with this codebase

I suspect that open source is (often) of higher quality than bespoke, proprietary software because it has to go through the crucible of documentation. Essentially, there’s a whole other design activity you have to go through when publishing a library or framework that internal/bespoke software does not.

I can’t objectively verify this. Subjectively, when I have made the time to write words about a bit of code I wrote, it has resulted in improving the design of the code along the way. Or, I better understand how I might design the code in the future.

Writing is a great tool for designing code. Use it more often!

Offloading fast operations in Ruby by data structure

Noteflakes: A Compositional Approach to Optimizing the Performance of Ruby Apps — the idea is to offload “inner-loop”-type operations from Ruby to C-extensions. The clever twist is this happens via data-structure-as-language. Ruby being Ruby, you can wrap a DSL around the data structure generation to reduce the context switch from Ruby to offloaded operations.

There’s precedent to the approach: if you squint, it’s not unlike offloading the math for computer graphics or machine learning to a GPU. That said, the speed-up is unlikely to be as dramatic.

I hope to hear more of this approach in the future!

Adjacent: “it’s wild how much of the 2021 programming ecosystem is declarative data structures evaluated by recursive functions.”

Code minutiae, October 23, 2017

For some reason, identifier schemes that are global unique, coordination-free, somewhat humanely-representable, and efficiently indexed by databases are a thing I really like. Universally Unique Lexicographically Sortable Identifier (ulid, for humans) is one of those things. Implementations available for dozens of languages! They look like this: 01ARZ3NDEKTSV4RRFFQ69G5FAV.

Paul Ford’s website is twenty years old. For maybe half that time I’ve been extremely jealous of how well he writes about technology without being dry and technical. When I grow up, I’ll write like that!

How Awesome Engineers Ask For Help. So much good stuff there, I can’t quote it. There’s something in there for new and experienced engineers alike. In particular: don’t give up, actively participate in the process of getting unstuck, take and share notes, give thanks afterwards.

The best time to work on your dotfiles is on weekends between high-intensity project pushes at work. No better time to do some lateral thinking and improving of your workflow. Feels good, man.

You must be this tall to ride the services

If I were trying to convince myself to extract a (micro)service, today, I’d do it like this. First I’d have a conversation with myself:

  • you are making tactical changes slightly easier at the expense of making strategic changes quite hard; is that really the trade-off you’re after?
  • you must have the operational acumen to provision and deploy new services in less than a week
  • you must have the operational acumen to instrument, monitor, and debug how your applications interact with each other over unreliable datacenter networks
  • you must have the design and refactoring acumen to patiently encapsulate the service you want to build inside your current application until you get the boundaries just right and only then does it make sense to start thinking about pulling a service out

I would reflect upon how most of the required acumen is operational and wonder if I’m trying to solve a design problem with operational complexity. If I still thought that operational complexity was worthwhile, I’d then reflect upon how close the code in question was to the necessary design. If it wasn’t, I would again kick the can down the road; if I can’t refactor the code when it’s objects and methods, there’s little hope I can refactor it once its spread across two codebases and interacting via network calls as API endpoints, clients, data formats, etc.

If, upon all that reflection, I was sure in my heart that I was ready to extract a service, it’d go something like this:

  • try to encapsulate the service in question inside the current app
  • spike out an internal API just for that service; this API will become the client contract
  • wrap an HTTP API around the encapsulation
  • make sure I have an ops buddy who can help me at every provisioning and deployment step, especially if this sort of thing is new and a monolith is the status quo
  • test the monolith calling itself with the new API
  • trial deploy the service and make some cross-cutting changes (client and server) to make sure I know the change process
  • start transferring traffic from the monolith to the service

In short, I still don’t think service extraction is as awesome as it sounds on paper. But, if you can get to the point of making a Modular Monolith, and if you can level up your operations to deal with the demands of multiple services, you might successfully pull off (micro)services.

How methodical and quality might keep up with fast and loose

I’ve previously thought that a developer moving fast and coding loose will always outpace a developer moving methodically and intentionally. Cynically stated, someone making a mess will always make more mess than someone else can clean up or produce offsetting code of The Quality.

I’ve recently had luck changing my mindset to “make The Quality by making the quantity”. That is, I’m trying to make more stuff that express some aspect of The Quality I’m going for. Notably, I’m not worrying too much if I have An Eternal Quality or A Complete Expression of the Quality. I’m a lot less perfectionist and doing more experiments with my own style to match the code around me.

I now suspect that given the first two developers, its possible to make noticeably more Quality by putting little bits of thoughtfulness throughout the code. Unless the person moving fast and loose is actively undermining the quality of the system, they will notice the Quality practices or idioms and adopt them. Code review is the first line of defense to pump the brakes and inform someone moving a little too fast/loose that there’s a Quality way to do what they’re after without slowing down too much.

Sometimes, I’m an optimist.

One step closer to a good pipeline operator for Ruby

I’ve previously yearned for something like Elm and Elixir’s |> operator in Ruby. Turns out, this clever bit of concision is in Ruby 2.5:

object.yield_self {|x| block } → an_object
# Yields self to the block and returns the result of the block.

class Object
  def yield_self
    yield(self)
  end
end

I would prefer then or even | to the verbosely literal yield_self, but I’ll take anything. Surprisingly, both of my options are legal method names!

class Object

  def then
    yield self
  end

  def |
    yield self
  end

end

require "pathname"

__FILE__.
 then { |s| Pathname.new(s) }.
 yield_self { |p| p.read }.
 | { |source| source.each_line }.
 select { |line| line.match /^\W*def ([\S]*)/ }.
 map { |defn| p defn }

However, | already has 20+ implementations, either of the mathematical logical-OR variety or of the shell piping variety. Given the latter, maybe there’s a chance!

Next, all we need is:

  • a syntax to curry a method by name (which is in the works!)
  • a syntax to partially apply said curry

If those two things make their way into Ruby, I can move on to my next pet feature request: a module/non-global namespace scheme ala Python, ES6, Elixir, etc. A guy can dream!

Strange Loop 2017

I was lucky enough to attend Strange Loop this year. I described the conference to friends as a gathering of minds interested in programming esoterica. The talks I attended were appropriately varied: from very academic slides to illustrated hero’s journeys, from using decomposed mushrooms to create materials to programming GPUs, from JavaScript to Ruby. Gotcha, that last one was not particularly varied.

In short, most of the language-centric conferences I’ve been to in the past were about “hey look at what I did with this library or weird corner of the language”, though the most recent Ruby/Rails conference are more varied than this. By comparison, Strange Loop was more about “I did this thing that I’m excited about and its a little brainy but not intimidating and also I’m really excited about it.”

Elm Conf 2017

I started the weekend off checking out the Elm community. I already think pretty highly of the language. I would certainly use it for a green-field project.

Size, excitement, and employment-wise, Elm is about where Ruby was when I joined the community in 2005. Lots of excited folks, a smattering of employed folks, and a good technical/social setup for growth.

A nice thing about the community is that there is no “other” that Elm is set against. Elm code often needs to interface with JavaScript to get at functionality like location or databases, so they don’t turn their nose up at it. It’s a symbiotic relationship. Further, most Elm developers are probably coming from JavaScript, so its a pretty friendly relationship. This is nice shift from the tribalism of yore.

It’s also exciting that Elm is already more diverse than Ruby was at the same point in its growth/inflection curve. Fewer dudes, more beginners, and none of the “pure Ruby” sort of condescension towards Rails and web development.

Favorite talks:

  • “Teaching Elm to Beginners” (no talk video), Richard Feldman. Using Elm at work requires teaching Elm to beginners. Teaching is a totally different skill set, disjoint from programming. When answering a question, introduce as few new concepts as possible. Find the most direct path to helping someone understand. It’s unimportant to be precise, include lots of details, or being entertaining when teaching. You can avoid types and still help students build a substantial Elm program.
  • If Coco Chanel Reviewed Elm, Tereza Sokol: Elm as seen through the lens of high and low fashion. Elm is a carefully curated, slow releasing collection of parts ala Coco Chanel. It is not the hectic variety of an H&M store.
  • Accessibility with Elm, Tessa Kelly: Make accessible applications by enforcing view/DOM helpers with functional encapsulation and types. Your program won’t compile if you forget an accessibility annotation. A pretty good idea!
  • Mogee, or how we fit Elm in a 64×64 grid”, Andrew Kuzmin: A postmortem on building games with Elm. Key insight: work on the game, not on the code or engine. Don’t frivolously polish code. Use entity-component-system modeling. Build sprite/bitmap graphics in WebGL by making one pixel out of two triangles.

The majority of the talks referenced Elm creator Evan Czaplicki’s approach to designing APIs. He is humble enough that I don’t think this will backlash like it did with DHH’s opinions did with Rails.

By far the biggest corporate footprint in the community and talks was NoRedInk. Nearly half of the talks were by someone at the company.

Most practical talks from StrangeLoop

Types for Ruby: it seems like they’ve implemented a full-blown type system for Ruby. It’s got all the gizmos and gadgets you might expect: unions, generics, gradual typing. It applies all its checks at runtime though, and they didn’t say if it does exhaustive checking, so I’m not sure how handy it would be in the way that e.g. Elm or Flow are. On my list of things to check out later.

Level up your concurrency skills with Rust. Learning Rust’s concepts for memory and concurrency safety, i.e. resources, ownerships, and lifetimes, can help you program in any language. Putting concurrency into a system is refactoring for out-of-orderness and most likely a retrofit of the underlying structure. Rust models memory like a resource, ala file handles or network sockets are modeled by the operating system. Rust resource borrowing in summary: if you can read it, no one else can write it; if you can write it, no one else can read or write it; borrows are checked at compile time so there is no runtime overhead/cost.

GPGPU programming with Metal. Your processor core has a medium sized arithmetic logic unit and a giant control unit (plus as much memory/cache as they can spare). A GPU is thousands of arithmetic logic units. Besides drawing amazing pictures, you can use all those arithmetic logic units to train/implement a neural network, do machine vision or image processing, run machine learning algorithms, and any kind of linear algebra or vector calculus. Work is sent to the GPU by loading data/state into buffers, converting math instructions to GPU code and load that into GPU buffers, and then let the GPU go wild executing it.

Seeking a better culture and organization of open source maintainership (no talk video). Projects are getting smaller, more fragmented, and attracting no community (ed. the unintended consequence of extreme modularity?) Bitcoin and Ethereum have very little backing despite the astronomical amounts of money in the ecosystem. We need a new perspective on funding open source work. Consumption of open source has won, but production of open source is still in a pretty bad place.

How to be a compiler. Knitting is programming; you can even compile between knitting description pseudo-languages. Implemented Design by Numbers, a Processing predecessor, as transpiler to SVG.

Random cool things people are really doing

Measuring and optimizing tail latency. Activating instrumentation and “slow-path” techniques on live web requests that run so long they will fall into the 99th percentile. Switch processor voltage to “power up” a processor that’s running a slow request so it will finish faster, e.g. switch a core from low power/500MHz mode to high power/2GHz mode.

Really using functional ideas of composition and state in production, consumer-facing applications (e.g. the NY Times) and using ML-style type checkers with JavaScript (e.g. Flow and Elm).

My two favorite talks by far: Making digital art with JavaScript, WebGL, vdom and immutability. Scraping/querying/aggregating image data from various space missions (e.g. Jupiter and Pluto flybys).

Facebook stopped using datacenter routers and started building their own servers that program the networking chips a router would use from CentOS, basically giving them programmable routers that deploy like you would update infrastructure like Nginx or memcached. I wonder when/if treating network devices as software will scale down to your typical large company?

Strange Loop takeaways

  • a conference of diverse backgrounds and experiences is a better one
  • my favorite talks told a hero’s journey story through illustrations
  • folks in this sphere of technology are taking privacy and security very seriously, but the politics of code, e.g. user safety and information war, were not particularly up there in the talks I went to (probably by self-selection)
  • way more people are doing machine learning applications than I’d realized; someone said off-hand that we’d “emerged from the AI winter in 2012” and that struck me as pretty accurate
  • everyone gets the impostor syndrome, even conference speakers and wildly successful special effects and TV personalities like Adam Savage

If you get the chance, you should go to Strange Loop!

exa in 30 seconds

What is it? exa is ls reimagined for modern times, in Rust. And more colorfully. It is nifty, but not life-changing. I mostly still use ls, because muscle memory is strong and its basically the only mildly friendly thing about Unix.

How do I do boring old ls things?

Spoiler alert: basically the same.

  • ls -a: exa -a
  • ls -l: exa -l
  • ls -lR: exa -lR

How do I do things I rarely had the gumption to do with ls?

  • exa -rs created: simple listing, sort files reverse by created time. Other options: name, extension, size, type, modified, accessed, created, inode
  • exa -hl: show a long listing with headers for each column
  • exa -T: recurse into directories ala tree
  • exa -l --git: show git metadata alongside file info

Generalization and specialization: more of column A, a little less of column B

  1. Now, I attempt to write in the style of a tweetstorm. But about code. For my website. Not for tweets.
  2. For a long time, we have been embracing specialization. It’s taken for granted even more than capitalism. But maybe not as much as the sun rising in the morning
  3. From specialization comes modularization, inheritance, microservices, pizza teams, Conway’s Law, and lots of other things we sometimes consider as righteous as apple pie.
  4. Specialization comes at a cost though. Because a specialized entity is specific, it is useless out of context. It cannot exist except for the support of other specialized things.
  5. Interconnectedness is the unintended consequence of specialization. Little things depend on other things.
  6. Those dependencies may prove surprising, fragile, unstable, chaotic, or create a bottleneck.
  7. Specialization also requires some level of infrastructure to even get started. You can’t share code in a library until you have the infrastructure to import it at runtime (dynamic linking) or resolve the library’s dependencies (package managers).
  8. The expensive open secret of microservices and disposable infrastructure is that you need a high level of operational acumen to even consider starting down the road.
  9. You’re either going to buy this as a service, buy it as software you host, or build it yourself. Either way, you’re going to pay for this decision right in the budget.
  10. On the flip side is generalization. The grand vision of interchangeable cogs that can work any project.
  11. A year ago I would have thought this was as foolish as microservices. But the ecosystems and tooling are getting really good. And, JavaScript is getting good enough and continues to have the most amazing reach across platforms and devices.
  12. A year ago I would have told you generalization is the foolish dream of the capitalist who wants to drive down his costs by treating every person as a commodity. I suspect this exists in parts of our trade, but developers are generally rare enough that finding a good one is difficult enough, let alone a good one that knows your ecosystem and domain already.
  13. Generalization gives you a cushion when you need help a short handed team get something out the door. You can shift a generalist over to take care of the dozen detail things so the existing team can stay focused on the core, important things. Shifting a generalist over for a day doesn’t get you 8 developer hours, but it might get you 4 when you really need it.
  14. Generalization means more people can help each other. Anyone can grab anyone else and ask to pair, for a code review, for a sanity check, etc.
  15. When we speak of increasing our team’s bus number, we are talking about generalizing along some axis. Ecosystem generalists, domain knowledge generalists, operational generalists, etc.
  16. On balance, I still want to make myself a T-shaped person. But, I think the top of the T is fatter than people think. Or, it’s wider than it is tall, by a factor of one or two.
  17. Organizationally, I think we should choose what the tools and processes we use carefully so that we don’t end up where only one or two people do something. That’s creating fragility and overhead where it doesn’t yield any benefit.