Let's not refer to Ruby classes by string
I am basically OK with the tradeoffs involved in using autoloading in Rails. I do, however, rankle a little bit at this bit of advice in the Rails guide to developing engines.
[caption id=“attachment_4216” align=“alignnone” width=“661”] Screencapture from Rails Guide to Engines[/caption]
In short, when configuring an engine from an initializer, you’re supposed to protect references to autoloaded application classes (e.g. models) by encoding them as strings. Your engine later constantize
s the string to a class and everything is back to normal.
A thing I am not OK with is “programming with strings”. As an ideal, strings are inputs from other machines or humans and internal references to code are something else. In Ruby, symbols fill in nicely for the latter. Could I refer to classes as Symbols instead of Strings and live with the tradeoffs?
Well it turns out, oddly enough, that Rails is pretty sparing with Symbol extensions. It has only 120 methods after Rails loads, compared to 257 for String. There are no specific extensions to symbol, particularly for class-ifying them. Even worse (for my purposes), there isn’t a particularly great way to use symbols to refer to namespaced classes (e.g. Foo::Bar
).
But, the Rails router has a shorthand for referring to namespaced classes and methods, e.g. foo/bar#baz
. It doesn’t bother me at all.
In code I have to work with, if at all possible, I’d rather refer to classes like so:
- Refer to classes by their real ClassName whenever possible given the tradeoffs of autoloading
- When autoloading gets in the way, refer to things by symbols if at all possible
- If symbols aren’t expressive enough, use a shorthand encoded in a string, e.g.
foo/bar#baz
- … (alternatives I haven't thought of yet)
- Refer to classes by their full string-y name
But, as ever, tradeoffs.
They're okay political opinions
The downside to the Republicans proposing a healthcare bill is that it’s a major legislative disappointment, given they’ve spent seven years symbolically opposing healthcare. The upside is that, at least, we have something substantive to discuss about healthcare. The silver lining is possibly voters will come to see the Republican party for its cynicism.
What is there to talk about? We could start with David Brooks on how we got to the point wherein the GOP has received their moment in the sun. He argues that neglecting three ideas led us to the propaganda of the Trump era:
First, the crisis of opportunity. People with fewer skills were seeing their wages stagnate, the labor markets evaporate. Second, the crisis of solidarity. The social fabric, especially for those without a college degree, was disintegrating — marriage rates plummeting, opiate abuse rates rising. Third, the crisis of authority. Distrust in major institutions crossed some sort of threshold. People had so lost trust in government, the media, the leadership class in general, that they were willing to abandon truth and decorum and embrace authoritarian thuggery to blow it all up.
Brooks argued Obama should have addressed these crises, which the ACA arguably did for the second. IMO, Republicans stoked all three of these fires while pointing their fingers elsewhere. Supply side economics built the first crisis, privatization the second, and propaganda media the third.
Meanwhile in Congress, Paul Ryan is rolling up his sleeves and saying taking healthcare away from Americans is about giving them freedom. Paul Ryan’s Misguided Sense of Freedom:
...But Mr. Ryan is sure they will come up with something because they know, as he said in a recent tweet, “Freedom is the ability to buy what you want to fit what you need.”He went on to argue that Obamacare abridges this freedom by telling you what to buy. But his first thought offers a meaningful and powerful definition of freedom. Conservatives are typically proponents of negative liberty: the freedom from constraints and impediments. Mr. Ryan formulated a positive liberty: freedom derived from having what it takes to fulfill one’s needs and therefore to direct one’s own life.
(Positive and negative freedom, as terminology, always confuse me; this bit is well written!) This op-ed makes a nice point: healthcare as envisioned by Obamacare, and other more progressive schemes, imagine an America where we are free from worrying about health care. Preventative care happens because we needn’t worry whether we should spend the money elsewhere or take the day off. Major health care events like pregancy or major illness are only intimidating because they are life events, not life-changing unfunded expenditures.
I cannot understand why, outside of deep cynicism of the American dream, Republicans in Congress would not want this kind of free world.
A little PeopleMover 💌
I love the Tomorrowland Transit Authority PeopleMover. It’s what a transportation system should be.
[caption id=“attachment_4190” align=“alignnone” width=“500”] People Mover entrance, overlooking Main Street and the Cinderalla Castle, overlooking Tomorrowland[/caption]
Outside but covered. Elevated so pedestrians can pass below it. Passing in and out of nearby structures. Couch-like.
[caption id=“attachment_4191” align=“alignnone” width=“500”] The People Mover over Test Track and Space Mountain[/caption]
Futuristic but achievable. Doesn’t isolate people from each other. You’re one of my favorites, People Mover.
Your product manager could save your day
I thought the feature I’m working on was sunk. An API we integrate with is, let us say kindly, Very Much Not Great. Other vendors provide an API where we can request All The Things and retrieve it page by page. This API was not nearly so great, barely documented, and the example query to do what I needed didn’t even work.
Sunk.
Luckily, only an hour in, I rolled over to the product manager and asked if it was okay if we were a little clever about the feature. We couldn’t request All The Things, but we could request Each of The Things that we knew about. It wasn’t great, but it was better than sunk.
The product manager proceeded to tell me that was okay and in fact that’s kind of how the feature works for other APIs too. I hadn’t noticed this because I was up to my neck in code details. She described how this feature is used in out onboarding process. It wouldn’t matter, at that level, whether we made a dozen requests or a hundred.
I wrote basically no code that day. Someone who “crushes code” or “moves fast and breaks things” would say I didn’t pull my weight. Screw ‘em.
I didn’t go down a rabbit hole valiantly trying to figure out how to make a sub-par API work better. I didn’t invent some other way for this feature to work. My wheels were spinning, but only for a moment.
Instead, I worked with the team, learned about the product, brainstormed, and figured out a good way forward. I call it a very productive day.
Three Nice Qualities
One of my friends has been working on a sort of community software for several years now. Uniquely, this software, Uncommon, is designed to avoid invading and obstructing your life. From speaking with my Brian, it sounds like people often mistake this community for a forum or a social media group. That’s natural; we often understand new things by comparing or reducing them to old things we already understand.
The real Quality Uncommon is trying to embody is that of a small dinner party. How do people interact in these small social settings? How can software provide constructive social norms like you’d naturally observe in that setting?
I’m currently reading How Buildings Learn (also a video series). It’s about architecture, building design, fancy buildings, un-fancy buildings, pretty buildings, ugly buildings, etc. Mostly it’s about how buildings are suited for their occupants or not and whether those buildings can change over time to accommodate the current or future occupants. The main through-lines of the book are 1) function dictates form and 2) function is learned over time, not specified.
A building that embodies the Quality described by How Buildings Learn uses learning and change over time to become better. A building with the Quality answers 1) How does one design a building such that it can allow change over time while meeting the needs and wants of the customer paying for its current construction? and 2) How can the building learn about the functions its occupants need over time so that it changes at a lower cost than tearing it down and starting a new building?
Bret Victor has bigger ideas for computing. He seeks to design systems that help us explore and reason on big problems. Rather than using computers as blunt tools for doing the busy work of our day-to-day jobs as we currently do, we should build systems that help all of us think creatively at a higher level than we currently do.
Software that embodies that Quality is less like a screen and input device and more like a working library. Information you need, in the form of books and videos, line the walls. Where there are no books, there are whiteboards for brainstorming, sharing ideas, and keeping track of things. In the center of the room are wide, spacious desks; you can sit down to focus on working something through or stand and shuffle papers around to try and organize a problem such that an insight reveals itself. You don’t work at the computer, you work amongst the information.
They’re all good qualities. Let’s build ‘em all.
I have become an accomplished typist
Over the years, many hours in front of a computer have afforded me the gift of keyboarding skills. I’ve put in the Gladwellian ten thousand hours of work and it’s really paid off. I type fairly quickly, somewhat precisely, and often loudly.
Pursuant to this great talent, I’ve optimized my computer to have everything at-hand when I’m typing. I don’t religiously avoid the mouse. I do seek more ways to use the keyboard to get stuff done quickly and with ease. Thanks to tools like Alfred and Hammerspoon, I’ve acheived that.
With the greatest apologies to Bruce Springsteen:
Well I got this keyboard and I learned how to make it talk
Like every good documentary on accomplished performers, there’s a dark side to this keyboard computering talent I posess. There are downsides to my keyboard-centric lifestyle:
- I sometimes find it difficult to step back and think. Rather than take my hands off the keyboard, I could more easily switch to some other app. I feel like this means I'm still making progress, in the moment, but really I'm distracting myself.
- Even when I don't need to step back and think, it's easy for me to switch over to another app and distract myself with social media, team chat, etc.
- Being really, really good at keyboarding is almost contrary to Bret Victor's notion of using computers as tools for thinking rather than self-contained all-doing virtual workspaces.
- Thus I often find I need to push the keyboard away from me, roll my chair back, and think, read, or write to do the deep thinking.
All that said, when I am in the zone, my fingers dance over this keyboard, I think with my fingers, and it’s great.
The occurrence and challenge of ActiveRecord lookup tables
I’ve noticed lots of Rails apps end up with database-backed lookup tables. Particularly in systems with some kind of customer or subscription management, it’s almost guaranteed that User
or Customer
models belong_to
SubscriptionLevel
or Plan
models. Thus, you frequently need to query both models.
If you’re looking for avoidable database work, as I sometimes have, this seems like low-hanging fruit. Plan level models very rarely change. You could replace those Plan
or SubscriptionLevel
models with a hardcoded data object and move on.
In my experience, you now have a white whale on your hands. This low-hanging fruit may haunt you for a while. It could cause you to invent increasingly implausible mechanisms for ridding yourself of this “technical debt” (scare quotes, it’s a trade-off and not actual technical debt). Teammates will appear drowsy when you mention this problem and its technical details, then back away slowly.
Why is it so tricky to convert AR database lookups to non-AR in-memory lookups?
I’ve attempted this twice. Both times, I tried to grab as little surface area as possible and ended up with nearly all of the models. A current teammate is trying now and suffering a somewhat similar fate. They’re more detail-oriented and motivated than I am, so I hope they’ll succeed. (Ed. they succeeded!)
Is this phenomenon something we can easily write off to coupling or is it something else? My pessimistic, gossip-y sense leads me to think people who have become ORM Skeptic went down this path thinking it’s inevitable if you accept an ORM into your life. They came away a dark shade of who they were with the conclusion that ORMs ruin everything. However, the phases of coping that involve a three thousand word essay and then writing a new database layer thing don’t actually solve this problem.
In the ActiveRecord flavor of ORMs, it is easy to describe model graphs and interactions amongst those graphs. Once you’ve got the whole model graph, its often difficult to isolate a subsection of it. AR, in particular, can make it easy to violate Demeter and reach through that graph in hard-to-refactor ways.
Our lack of great and general tools for working with Ruby code that uses these graphs and rewriting said code is another big challenge. Solving these problems requires visualizing the direct and transitive connections between models. Then you need some kind of refactoring tool to rewrite code to use an indirection object instead of directly coupling. We lack both of those in the Ruby world.
Optimistically, I’d think this is a case of refactoring smarter. Given a solid test suite you could:
- connect your lookup models to an in-memory SQLite database populated at app start, no need to remove ActiveRecord
- use one of the several libraries that implement enough of the ActiveRecord interface to replace models with classes backed by static data
- lots of things I haven't thought or heard of!
The thing you wouldn’t want to do, and where I faltered at least once, was to let it become a long-running task. When you’re making changes all over the code base, any amount of churn behind your back is potentially crippling. If you can freeze the code base, I highly recommend it. (Coincidentally, this is exactly what my smarter-than-me teammate did!)
The other thing to keep in mind is that, inevitably, you will come across weird uses of ActiveRecord and Rails that you didn’t know about, are pretty sure you don’t like, and have to work with anyway. Set aside time for these known unknowns.
When dealing with potentially large, radical changes to your application code, how radical are you willing to go to make many smaller changes than one big one? There’s no crisp answer here. All code grows awkward in different ways. As always: divide, conquer, and celebrate your victories!
The annoying browser boundaries
Since I started writing web applications in around 1999, there’s been an ever-present boundary around what you can do in a browser. As browsers have improved, we have a new line in the sand. They’re more enabling now, but equally annoying.
Applications running on servers in a datacenter (Ruby, Python, PHP) can’t:
- interact with a user’s data (for largely good reason)
- make interesting graphics
- hop over to a user’s computer(s) without tremendous effort (i.e. people running and securing their own servers)
Browser applications can’t:
- store data on the user’s computer in useful quantities (this recently became less true, but isn’t widely used yet)
- compute very hard; you can’t run the latest games or intense math within a browser
- hang around on a user’s computer; browsers are a sandbox of their own, built around ephemeral information retrieval and not long-term functionality
- present themselves for discovery in various vendor app stores (iTunes, Play, Steam, etc.)
It may seem like native applications are the way to go. They can do all the things browsers cannot. But!
- native apps are more susceptible to the changing needs of their operating system host, may go stale (look outdated) or outright not work anymore after several years
- often struggle to find a sustainable mechanism for exchanging a user’s money for a developer’s time; part of that is the royalty model paid to platforms and stores, part of that is the difficulty of business inherent to building any application
- cannot exceed the resources of one user’s computer, except for a few very high-end professional media production applications
In practice, this means there’s a step before building an application where I figure out where some functionality lives. “This needs to think real hard, it goes on a very specific kind of server. This needs to store some data so it has to go on that other server. That needs to present the data to the user, so I have to bridge the server and browser. But we’d really like to put this in app stores soooo, how are we going to get something resembling a native app without putting a lot of extra effort into it?”
There’s entirely good reasons that this dichotomy has emerged, but it’s kinda dumb too. In other words, paraphrasing Churchill:
Browsers are the worst form of cross-platform development, except for all the others.
What is the future of loving cars?
To me, a great car is equal part shape, technology, sound, and history. It seems like the future of cars is all technology at the expertise of all other factors. What will it mean to love cars over the next ten years?
A well shaped car is defined by function. A long hood accommodates an engine running the length of the car and not between the wheels. Aerodynamic surfaces, not too many please, keep the car pressed to the road. The shape of the car is further of a function of air inlets to cool all the moving parts. Once all that is done, you can think of the form, getting just the right balance of smooth curves and straight lines.
Future cars are likely to move toward aerolumps. Drag is always the enemy of cars, doubly so for anything seeking efficiency. But the form needed to accommodate moving parts (read: combutions engines and their support infrastructure) will go away. You’re left with just a bubble holding the passengers. Not inspiring.
The sound of future cars is the sound of air running over the car and tires meeting the road. You may hear the occassional whine of an electric motor, perhaps an artifical soundtrack inspired by old combustion engines. No more growls, burps, and high-rev screams.
When all this sorts out, some companies will have a more interesting product due to their use of technology. A lot of companies will have a more boring but practical product. We will surely say, “they don’t make them like they used to” because literally, of course, they won’t.
But what will we find to love about how cars are built and function? Will that fade as a historical note while we revel in the agency a personal car brings without some of the external costs of highways, parking lots, and petrofuels?
Levels of musical genius
I often think about what kind of unique musical talent some performer I enjoy possesses. A few examples:
- J-Dilla was at the center of many groups doing amazing things creating an exciting moment in time, but at the same time was a master composer himself
- Prince or Quincy Jones were often running multiple performers and groups, serving as sort of the well from which their respective musical ideas came from
- Tom Petty isn't particularly gifted technically and doesn't write ground-breaking songs but is very, very good at working within a specific form and genre, one of the best in that space
- Jimmy Page is not musically the best or most innovative, but very adept at the style he created for himself, is technically a good guitarist
- Pete Townsend holds a group together, is the glue that leads a group of virtuosos, somehow the master creator and craftsperson who runs the group with a solid hand without making it all about him
- Brian Wilson plays a whole ensemble, a studio as an instrument, micromanaging every detail to produce a sublime musical whole; Bruce Springsteen is close to this
- Bob Dylan or Leonard Cohen are excellent wordsmiths who get great results when the music around them is also pretty good
- Annie Clark is a guitar-shred-meister who runs with the avant-alt mantle set forth by The Talking Heads
- Merrill Garbus builds amazing lo-fi layered music of incredible stylistic range that sounds right at home on the festival circuit
The connection amongst these individuals is more than playing their instruments or writing their songs. They’re working a level above that, whether it’s Tom Petty and Jimmy Page making fine-tuned rock or J-Dilla, Prince, and Merrill Garbus micromanaging a subgenre into existence. I’m a little envious of that level of musical acumen.
Four parks, one day
In January, Courtney and I went to Disney World for her birthday. We bought an annual pass last year, so we’ve literally been a few times over the past year. This time ‘round, Courney wanted to visit all four parks in one day. Our Official Rules were we had to ride two rides (or see a show and do a ride), drink a boozy drink, and eat a dessert in each park. We made it!
We had a few other days to enjoy the park at a more leisurely pace. We did a Safari tour at the Animal Kingdom resort, which afforded opportunities for giraffe selfies. I got to take lots of pictures and enjoy Epcot and Tomorrowland, my favorites. Along the way, we ate a bunch of ice cream and sang along with “Let It Go” nearly every day.
As ever, a magical time.
[gallery ids=“4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061” type=“rectangular”]
The right way and the practical way
Brent Simmons, Reason Number 33,483 to Hate Programming:
Or I could have the superclass expose the appIsTerminating property in its header file, so that the subclass could see it. This also sucks, because a controller class has no business exposing its own copy of global application state.
In the end, though, that’s what I did. (Along with a comment that the property was there for subclasses.)
It reminds me that there are two competing values:
Do everything the right way every time.
Make responsible and professional decisions about time and expenses and benefits and drawbacks.
My nature is to take path #1. It is so hard for me to take path #2. I have the utmost respect who can work on sprawling, modern software and stay on path #2. But path #1, always pulling me in and sending me down rabbit holes.
Sometimes I wonder which of these paths got me to where I am in my career. Others, I wonder if I think I’m a everything-the-right-way person but really I’m a responsible-and-professional-tradeoffs person.
A brain’s a weird place to live.
Framework and Library people
By unscientific survey, I think many developers would prefer to work in a “framework world” where many decisions of principle and organization are passed down by a vendor or architecture team. Think Rails/Django/Laravel for backends, Ember/Elm for frontends, Unity for games. These are the Framework people.
Fewer developers would prefer to create their own world, building up tools and libraries to suit. They select a few first principles and build their own world. They’re the bebop jazz musician, eschewing big band gigs and music people can dance to to create their own intellectual world. These are the Library people.
I’m a Framework person. The allure of Library people sometimes tempts me after I look at a beautifully-restored car or a well-structured song. But constructing a library world is thankless and not particularly high leverage, unless you succeed in creating something for framework people. Weird, eh?
Empathy Required
Nearly fourteen years ago, I graduated college and found my first full-time, non-apprentice-y job writing code. When I wrote code, these were the sorts of things I worried about:
- Where is the code I should change?
- Is this the right change?
- What are the database tables I need to manipulate?
- Who should I talk to before I put this code in production?
Today, I know a lot more things. I did some things right and a lot of things wrong. Now when I write code, these are the sorts of things I worry about:
- Am I backing myself into a corner by writing this?
- Why was the code I'm looking at written this way and what strategy should I use to change it?
- Will this code I just wrote be easy to understand and modify the next time I see it? When a teammate sees it?
- Should I try to improve this code's design or performance more, or ship it?
Half of those concerns are about empathy. They’re only a sampling of all the things I’ve learned I should care about as I write code, but I think the ratio holds up. As I get better and better at programming, as my career proceeds, I need more empathy towards my future self and my teammates.
Further, that empathy needs to extend towards those who are less experienced or haven’t learned the precise things I’ve learned. What works for me, the solutions that are obvious to me, the problems to steer clear of, none of that is in someone else’s head. I can’t give them a book, wait three weeks, and expect them to share my strengths and wisdoms.
That means, when I advise those who listen or steer a team that allows me to steer it, I have to make two camps happy. On one hand, I have to make a decision that is true to what I think is important and prudent. On the other hand, I have to lay out guidelines that lead the listener or teammate towards what I think is important or prudent without micromanagement, strict rules, and other forms of negative reinforcement.
It’s so easy, for me, to just hope that everyone is like me and work under that assumption. But it’s much better, and highly worthwhile, to figure out how to help friends and teammates to level up on their own. It requires a whole lot of empathy, and the discipline to use it instead of impatience. Worth it.
Copypasta, you're the worst pasta
Copypasta. It’s the worst. “I need something like this code here, I’ll just drop it over there where I need it. Maybe change a few things.” Only you can prevent headdesks!
It’s not really possible, in my experience, to make it easier to use code through methods and functions than to just copy what you need and start changing it. No amount of encapsulation or patterns is easier than a pasteboard.
Perhaps, copypasta’s natural predator is a well-informed code review. There are tools, like flay, that can detect some kinds of code duplication.
But for the most part, it’s a battle of dilligence.
(Ed. I found this in my draft folder from four years ago. Copypasta; copypasta never changes.)
Through mocks and back
A problem with double/stub/mock libraries is that they don’t often fail in a total manner. They don’t snap like a pencil when they’re used improperly. Instead, when you use them unwisely, they lay in waiting. At an inopportune time, they leap out.
Change an internal API method name or argument list and your poorly conceived doubles will moan. Rearrange the relationship between classes, and your overly-specific stubs won’t work anymore.
At some point, I felt pretty handy with mocks. Then I wrote a bunch of brittle mocks and decided I needed to go back to square one. I’m through the “just avoid mocks” phase, and now I use them sparingly.
Favor a better API in the code under test, then hand-coded fakes, then stubbed out methods, before finally falling back to a mock. Someone, possibly yourself, will thank you later.