Uncategorized
Context is data to burst your bubbles
Context is a slippery topic that evades attempts to define it too tightly. Some definitions cover just the immediate surroundings of an interaction. But in the interwoven space-time of the web, context is no longer just about the here and now. Instead, context refers to the physical, digital, and social structures that surround the point of use.
Great design is built around people, not devices or software. Applying responsive design or native app UX is a tool, not a solution. Instead, we should design software that solves a problem for a real person (not a power-user or one of our colleagues) given the devices available to them and the context of use they’re in.
A high information density display is no good to a parent trying to get their kids out the door. Documentation based on video tutorials is no good for someone riding a bus. A developer troubleshooting a service bottleneck needs to know more than the average response time.
As both designers of user experiences and developers of software, we need to get away from the desk and out amongst those we’re building for. It’s too easy to build for ourselves and our friends. We need to consider how others approach and use what we make. Armed with that context, we can design a solution for everyone, and not just those we share a bubble with.
Hyperthreading illustrated
I'm fond of saying hyperthreading is a lie. It's true though; a dual hyperthreaded core is nowhere near as awesome as a four real cores. That's more provocative than useful, so let me draw you some pictures.
If you zoom way out, a single core, dual cores, and a single hyperthreaded core look like this:

Note how the hyperthreaded core is really a single core with an extra set of registers and instruction/stack pointers. The reason hyperthreading is a lie is you can't actually run four processes, or even four threads, at the same time. At best, you can run two threads with two others ready in the wings.
I'm a dilletante of processor architecture at best, but I think I can explain why chip designers would do this.

My best guess as to why you would design and release a hyperthreaded core is to increase the number of instructions you can retire (i.e. mark as completely executed) per clock cycle. Instructions retired per cycle is one of the primary metrics processor architects use for judging a design.
The enemy of instructions retired per clock cycle is memory accesses and branch mispredictions. When a processor has to go access a cache line or worse, something out in main memory, it has nothing to do but wait. When a branch (i.e. a conditional or loop) is incorrectly speculatively executed (how awesome is it that processors start executing code paths before they even know if its the right thing to do?) they end up in the same predicament. Cache misses and branch mispredictions are at best a recipe for some overhead, and at worst a recipe for waiting around on main memory.
Hyperthreading attempts to solve this problem by keeping extra programs (threads or processes) waiting in the wings, ready to start executing as soon as another pauses due to needing something from main memory. This means our execution units, the things that actually do math and execute the logic of a program, are (almost) always utilized and retiring instructions. And that gets us to our happy place of a higher instructions retired per clock cycle.
Why not just throw more execution units in and have real cores ready to work? I'm not sure, there must be something about how modern processor pipelines work that I don't know which makes it too expensive to implement. That said, hyper threading (as I understand it) is a pretty clever hack for improving the efficiency of a processor.
TextMate's beautiful and flawed extension mechanism
This is about how TextMate’s bundle mechanism was brilliant, but subtly flawed. However, to make that point, I need to drag you through a dichotomy of developer tools.
Composition vs. context in developer tools
What's the difference between a tool that developers work with and a tool developers often end up working against? Is there a useful distinction between tools that seem great at first, but end up loathed as time goes on? Neal Ford has ideas. Why Everyone (Eventually) Hates (or Leaves) Maven:
I defined two types of extensibility/programability abstractions prevalent in the development world: composable and contextual. Plug-in based architectures are excellent examples of the contextual abstraction. The plug-in API provides a plethora of data structures and other useful context developers inherit from or summon via already existing methods. But to use the API, a developer must understand what that context provides, and that understanding is sometimes expensive.
Composable systems tend to consist of finer grained parts that are expected to be wired together in specific ways. Powerful exemplars of this abstraction show up in *-nix shells with the ability to chain disparate behaviors together to create new things.
Ford identifies Maven and IDEs like Eclipse as tools that rely on contextual extension to get developer started with specific tasks very quickly. On the other hand, a composable tool exchange task-oriented focus for greater adaptability.
Contextual systems provide more scaffolding, better “out of the box” behavior, and contextual intelligence via that scaffolding. Thus, contextual systems tend to ease the friction of initial use by doing more for you. Huge global data structures sometimes hide behind inheritance in these systems, creating a huge footprint that shows up in derived extensions via their parents. Composable systems have less implicit behavior and initial ease of use but tend to provide more granular building blocks that lead to more eventual power.
And thus, the crux of the biscuit:
Contextual tools like Ant and Maven allow extension via a plug-in API, making extensions the original authors envisioned easy. However, trying to extend it in ways not designed into the API range in difficultly from hard to impossible...
Contextual tools are great right up to the point you hit the wall of the original developer’s imagination. To proceed past that point requires a leap of one or two orders of magnitude in effort or complexity to achieve your goal which the original developer never intended.
Bundles are beautiful
Ford wrote this as a follow-on to a piece Martin Fowler wrote about how one extends their text edior. It turns out that the extension models of popular text editors, such as VIM and Emacs, are more like composable systems than extension-based systems.
All of this is a extremely elaborate setup for me to sing the praise of TextMate. Amongst the many things it got very right, TextMate brilliantly walked the line between a nerdy programmer’s editor and an opinionated everyday tool for a wide range of developers. It did this by exposing its extension mechanism through two tools that every developer knows: scripts and regular expressions.
To add functionality to TextMate, you make a bundle. A bundle is a convention for laying out a directory such that TextMate knows the difference between a template and a syntax definition through a convention. This works because developers know how to put things in the right folder. There were only ever five or so folders you needed to know about, so this was a simple mechanism that didn’t become a burden.
To tell TextMate how to parse a language and do nifty things like folding text, you wrote a bunch of regular expressions. If I recall, there were really only a few placeholders to wedge in these regular expressions. This worked great, as most languages, though the “serious” tools use lexers and parsers, are amenable to low-fidelity comprehension with a series of naive pattern matches. The downside was that languages that didn’t look like C were sometimes odd to work with.
In my opinion, the real beauty of TextMate’s bundles was that all of the behavioral enhancement was handled with shell scripts. Plain-old Unix. You could write them in Ruby, Python, bash, JavaScript, whatever fit your fancy. As long as you could read environment variables and output text (or even HTML), you could make TextMate do new things. This led to an absolute explosion of functionality provided by the community. It was a great thing.
Downfall
Interestingly enough, TextMate is essentially a runtime for bundles. This is how VIM and Emacs are structured as well. TextMate just put a nicer interface around that bundle runtime. However, the way it did so was its downfall, at least for me.
Recall, a few hundred words ago, the difference between composable and contextual extensions. A contextual extension is easy to get going, but comes up short when you imagine something the creator of the extension point didn’t imagine. The phenomenal thing about TextMate was how well it chose the extension points and how much further those extension points took the program than what came before it. I’d estimate that about 90% of what TextMate ever needed to do, you could do with bundles. But the cost to find that last 10%, it was brutal.
Eventually, I bumped up against this limitation with TextMate. I wanted split windows, I wanted full-screen modes, I wanted better ctags integration. No one could add those (when TextMate wasn’t open source, circa 2010) because they required writing Objective-C rather than using TextMate’s extension mechanism. And so, I ended up on a different editor (after several months of wandering in a philosophical desert).
The moral of the story
If possible, you should choose a composable extension mechanism (a full-blown language, probably) and use that extension mechanism to implement your system, ala Vimscript/VIM and elisp/Emacs. If you can’t do that, you can get most of the benefit by doing a plugin API, but you have to choose the extension points really, really well.
SoundCloud, micro-services, and software largeness
From a monolithic Ruby on Rails app to the JVM, how Soundcloud has transitioned to a hybrid approach with Ruby apps intermingling with Scala and Clojure apps. I think some of their idea of what is idiomatic Rails and how to operate Ruby are not exactly on center. But, their approach to the problem of a large Rails app is right on: break it up into “micro-services” that, if you don’t like the code, you can rewrite quickly if necessary.
Lest you fear this is yet another “Rails doesn’t scale!” deck, they do make a key observation. “Rails, PHP, etc. are a very good choice to start something”. Once you get past “starting” and “growing” to “successful and challenging”, you’ll face the same level of challenge no matter what you choose: Ruby or Java, MySQL or Riak. All the technologies we have today are challenged when they grow large.
So don’t let applications and services get large. Easy to say; hard, but worthwhile, to practice.
Twitter's optimizations
Data point: a few of the infrastructure pieces out of Twitter have been implemented in low-level, heavy metal C and they’re optimizing on individual machines instead of architecture. Today, twitter/fatcache, a memcached-on-SSDs:
To understand why network connected SSD makes sense, it is important to understand the role distributed memory plays in large-scale web architecture. In recent years, terabyte-scale, distributed, in-memory caches have become a fundamental building block of any web architecture. In-memory indexes, hash tables, key-value stores and caches are increasingly incorporated for scaling throughput and reducing latency of persistent storage systems. However, power consumption, operational complexity and single node DRAM cost make horizontally scaling this architecture challenging. The current cost of DRAM per server increases dramatically beyond approximately 150 GB, and power cost scales similarly as DRAM density increases.
It’s fascinating to observe Twitter’s architectural growth from the outside. They quickly exceeded the capacity of typical MySQL setups, then of Ruby and Rails, then memcached alone. They’ve got distributed filesystems, streaming distributed processing pipelines, and distributed databases. Now they’re optimizing down to the utilization of their hardware, taking advantage of the memory-like latencies of SSDs. When you start caring about power and the size of your index entries, you’ve reached a whole new level of Maslow’s hierarchy of scaling.
If trends continue and Twitter is a leader in how large-scale distributed systems are implemented, watch out. Twitter led many of us to Scala, ZooKeeper, and their own inventions like Storm and Finagle. Gird your programming and scaling fashion loins, because you’re about to learn a lot more about malloc
, ERRNO
, and processor architecture than you ever wanted to know!
Stella by Starlight
My latest weekend project, called "Stella by Starlight" after a Charles Mingus recording, was to build an analytics-style dashboard for looking at random metrics and events generated by a faked-out backend. I started with these rules for myself:
- Write every 30-60 minutes. If I don't keep myself honest in journaling this, I'll never get around to writing about it.
- Use Scala for the backend service. More on this in a moment.
- Learn D3.js. This is a primary goal of this exercise.
- Maybe use Coffeescript. More on this too, below.
And now, my notes from periodic progress reports. I've annotated it with GitHub commits at each step; you can also peek at the whole repo.
Get started with Scalatra
Per my motivation to use Scala, I figured I'd start with Scalatra. It integrates with Akka, which seems like a great thing, sticks pretty close to the Sinatra-style of web app construction, and seems like its probably approachable by a Scala beginner.
Strike 1 is that you need to use this giter8 tool. Luckily, it's available via Homebrew, so it's not a blocker.
Strike 2 is all the work needed to setup a Coffeescript gizmo to work with Scalatra. I've been blocked on SBT-related stuff before, and the instructions don't match the style of SBT project that was generated by giter8.
So I have a decision to make: should I plow forward with Scala and drop CoffeeScript or make a strategic retreat to the comfortable land of Ruby where there's probably a thing that will automatically compile CoffeeScript every time I hit a page?
For this weekend, I'm going to tradeoff getting better with Scala instead of CoffeeScript. The latter's domain is browsers, a domain I have chosen not to optimize myself for.
First commit: I have no idea what I'm doing.
Boilerplates
With one decision down, I need to figure out what my first real milestone is. It seems like a spike/prototype project like this requires two setup steps before real work can begin:
- Put all the project boilerplate in place. Get the backend service running and responding to requests. Decide on any front-end boilerplate I'm going to use (Twitter bootstrap, et. al.) and put it where your server will hand it off to a browser.
- Get your feedback loop working. Make a trivial change to the backend app, make sure it appears in the front-end. Make a front-end change and make sure everything changes properly.
Once I've got these two nailed down, I'm ready to actually iterate on the idea in your head.
I've got the Scalatra part of this working, and just fetched Bootstrap. Now I just need to get its boilerplate working and I can start actually working on an analytics dashboard.
Templates and cargo cults
So Scala can manipulate XML as a language-level thing. This is both terrifying and, in the case of emitting HTML inline within a Scalatra action, useful. But the limit of this is that not-quite-valid XML, but perfectly reasonable HTML, will cause your Scala program to flat-out not compile. Ergo, I decided it was time to bite the bullet and move my HTML bits into an actual template (commit).
That turned out to be pretty easy. Read the Scalate (Scalatra view templates) docs, skim the actual Scalate docs and you're mostly good to go. The only catch is that I had pre-generated HAML-style templates laying around which were causing a weird error about title
not being defined. Once I figured out I had cruft laying around and killed it dead, all was pretty good.
I cargo culted all the CSS from a Twitter Bootstrap example and ended up with something decent looking. Note to past-self: HTML and CSS are terrible, but things like Bootstrap will make it reasonably possible to put up a decent-looking app quickly without needing a designer or browser-bug expert.
The change loop for Scalatra is nice and quick when doing front-end work. The SBT feature that watches the filesystem for changes and automatically runs tasks on change is pretty handy and, IMO, a better place for that functionality than in something like Guard.
Let there be charts
Now I want to get Cubism in place. At first glance, I thought I was goinging against the grain here. Cubism has a slight tendency towards using Graphite or Cube as the metric source. However, the demo page for Cubism shows some charts using random data.
Peeking at the source showed me the way to creating a data source that isn't pulling from Graphite or Cube (commit). This saved me the effort of trying to reverse engineer the Graphite/Cube query APIs before I could make any progress at all.
This points to an important lesson of prototyping: when in doubt, steal from the example that looks like what I want to do. It's totally OK to cargo-cult things into your system at this point. Later on, I can do it with software engineering and craftsmanship. In the present, I want to make progress on exploring my idea.
Random numbers as a service
Now I want to emit some random numbers via JSON from the service. This ended up being a not-so-tough journey into actual Scala. Turns out the JSON support in Scalatra is pretty straight-forward. I had to take a side-trip through JodaTime, a library I'd heard about before but never worked with directly. Of course, that resulted in some temporary Maven confusion, but all was well in the end (commit).
I was pleased by how one can go about quickly emitting JSON from a Scalatra action. What you do is write a case class (somewhat analogous to a Ruby struct, but with more tricks up it s sleeve) for the structure you're going to convert to JSON. Then you return one or more instances of that class from your action and the library handles the rest. All of this mostly made sense when I read the examples and converted it to my own thing, so I guess the basics of Scala are starting to stick. Happy!
Better random numbers, an attempt
I wanted to generate more realistic data from the service. I figured I would port the random metric generator from the Cubism example's JavaScript to Scala. This would make it easier for me to grok the timeline windowing scheme that Cubism uses.
It ended up that porting this algorithm was a bit trickier than I thought. Oddly enough, you can paste the crux of the algorithm from JavaScript to Scala and it looks like valid Scala. However, doing so gave me compiler errors that took me a little while to work out. Basically, the algorithm expects to work with doubles, but the compiler infers integers if you specify any default value such as start = 0
. Adding type annotations to declarations resolves all of this. With that worked out, making the Scala compiler happy was a little more obvious.
It turned out that the Cubism example, as I cargo culted it, passes timestamp strings to the service. It was getting late and the first few things I tried to parse timestamps in Scala didn't work out, so I decided to call it there (embarrassingly broken commit).
How'd I do?
On the bright side, I didn't get hung up on Maven dependencies, I roughed my way through the Scala type system, and I had a pleasant experience with Scalatra and Cubism. On the downside, I didn't get to streaming events to the browser from the server and I couldn't quite get random metrics flowing from the server into the browser.
These weekend hacks are like that. I learn about things I expected to learn about and I learn about entirely different things too. I didn't expect to find myself pressing ahead with Scala, but doing so was an entirely different kind of educational fun than if I hadn't.
The nice things about these weekend hacks is that they're just that; a hack over the weekend. It's not a big project that I am responsible for afterwards. But it's still enough progress that I can write about it here and share it on GitHub. That feels productive. Learning plus productivity feels really good!
Adam’s Law of Redis
No matter how many times you tell everyone to not use KEYS
, there remains a non-empty set of people who think they can use KEYS
.
You can’t use KEYS
because it has to look at every key in the database. Even if you use a prefix pattern to narrow the scope.
Don’t use KEYS. If that means you need to redesign your schema, you have no choice but to redesign your schema.
Thoughts on (Programming) Scala
On a whim, I flew through Programming Scala this weekend. I’ve had the book for a while, and actively tried to read it before. But this time, it stuck.
All the ideas in Scala are fascinating for a language nerd. It’s the best instance I know of, so far, where ideas from object-oriented and functional programming are combined intentionally and at-scale to produce a language that developers are using on a day-to-day basis. For a language nerd like me, it’s fun to see how all those ideas play out together.
That said, there is a lot of language lawyering. Having to write a chapter on scoping and public/protected/private rules in OO seems like a demoralizing thing for the authors to tackle. And all those hybrid OO/FP ideas come at a conceptual cost; it seems like there’s a lot to know. I’ve noted before that I’m very interested to see how Scala does in the marketplace of minds. It’s a very large language, but I think it’s large in a way that is already familiar to developers. So it could end up that Scala isn’t a great beginner language, but is fine for someone who already knows one FP and one OO language.
I should note that this isn’t my first Scala rodeo. I’ve tried, at various times, to tinker and hack on little projects or simply to grok other people’s code. The blocker on these previous attempts is that I, personally, am sbt-challenged. Whenever I’ve tried to compile projects or add dependencies to my own, I end up in an sbt-shaped trough of disallusionment. Part of this is my ongoing war of attrition with Maven. Part of this is, well, I’m not sure yet. I should note that I can mostly make leiningen, also Maven-based, work. So it’s not entirely Maven’s fault.
Most interesting to me is that Scala could have the versatility of Ruby, wherein one can grow a program from a script, to a message-based program, to a hybrid OO/functional system, to a multi-machine distributed program. You can’t say this about other JVM languages like Java or Clojure. The JVM is a gift and a curse. It makes Scala and Java impractical for scripts, due to startup time. But once your program is somewhat grown-up, Hotspot and the JVM’s excellent concurrency features come in quite handy.
More specific to the book, it cleared up some ideas I’d previous found confusing:
- What’s a method call/operator overloading? It’s an object, a dot or space, and then a method/operator name.
- Implicit methods/views; if you declare methods with the
implicit
keyword and they have the right type signature, the compiler will use them to coerce objects to your own types, giving you many of the benefits of something like Ruby’s open classes - How functions, maps, and ad-hoc data structures that are typical in Ruby map to actual types in Scala; lots of things get converted to
Function
andTuple
objects by the compiler, which makes sense when you think about it in an ML-ish everything-is-strongly-typed way. - Internal DSLs feel weird, but parser combinators for external DSLs seems like it would be great.
- for-comprehensions; I guess I’ve read enough about them in Clojure now that they make sense in Scala. It’s worth noting that Scala’s for-comprehensions feel simpler than Clojure’s.
- Self-type annotations; I’ve seen this all over in Scala code and didn’t quite understand what was going on. It sure does have an odd name.
And some things are still confusing to me:
- Type bounds, variance; when will I need these?
- Linearization of object hierarchies; rules, I don’t like learning them!
- Tail-calls/trampolines; the JVM makes this a headhurt.
- Path-dependent types; not sure when I’d really need this, but it’s good to know about.
- Anything that’s a band-aid over type-erasure; again, the JVM is sometimes a headhurt.
I don’t have any projects that imminently need the things that Scala provides. Further, I think imposing Scala on a team that’s already succeeding at Ruby or Python is a stretch. You have to be in a place where you really need low, predictable latencies to accept the tradeoff of working with a much larger language.
That said, it’s totally a reasonable choice as a way to get yourself onto the JVM; if Clojure isn’t your thing, Scala probably is. Even if neither are your thing, don’t be a wuss; read some code in either language and expand your mind to reduce your headhurt.
Reflecting on Ruby releases
Ruby 1.8 brought us a couple changes that made many kinds of metaprogramming easier, plus a whole bunch of library additions that made Ruby feel more "grown up". Without seeking external libraries, one could write Ruby to solve many problems developers face in commonplace jobs. I wasn't around for Ruby 1.6, but I've been thinking of Ruby 1.8 as a transition from "better Perl or Java" to "better Smalltalk".
Ruby 1.9 brought us features that make some functional programming idioms easier. Lambdas, i.e. anonymous functions, require less syntax and are better defined. Enumerators make it possible to use features of Enumerable, itself a very functional-esque feature, in more places. Symbol-to-proc makes it easier to pass methods around as blocks, another FP-esque practice. I might say that Ruby 1.9 is the "better MatzLisp" version of Ruby.
Ruby 2.0 is bringing us features that, on the surface, make it easier for Rails to extend the Ruby language via ActiveSupport. I think that's too shallow of a reading. The new tools in Ruby 2.0 (excepting the highly-controversial refinements) make it easier to cleanly add functionality to Ruby's core objects and library. Reducing the cost of extending the core make it possible for more libraries and applications to judiciously make high-leverage additions to the lower levels of Ruby. That seems like a pretty good thing.
I can't find a source for this, but I could have sworn I once read that all programming is language design. It was probably related to Lisp, where you're arguably directly manipulating the AST much of the time. If the changes in Ruby 2.0 can take us closer to this level of program design, where we think more about building language up to the problem domain instead of objects and mechanism, sign me up.
Design for test vs. design for API
How many design considerations are there in an almost trivial method? Let's look at two of them. Consider this code:
def publish!
self.update_attributes(created_at: Time.now)
end
If you've been studying OO design and the SOLID principles, using TDD as a practice to guide you towards those ideas, there's a missing piece here. The reference to Time
is a dependency that should be injected. In Ruby, it's really easy for us to fix that:
def publish!(time=Time.now)
self.update_attributes(created_at: time)
end
I suspect a lot of TDDers would instinctively write the above first, skipping the first version by force of habit. But, let's stop and think about what the drives us to want the second version.
The strength of the second version is that it is designed for test. If we need to test how this model behaves when it is published at night, or on a leap day, or the day before Arbor Day, injecting the time object makes that easier.
There are some other test-focused design direction this method could go. We could create our own object whose role is to hand out timestamps, which would allow us to reasonably stub out the time reference, instead of injecting it. I'll bet there are other approaches lurking out there as well.
I want to look at another set of design considerations. I could design this code for testability, which often leads me to code that follows the SOLID principles which often leads me to decoupled code that is easier to change later. To many people, that's a good thing.
However, there's another lens I can look through: API design. How does this method hold up as a piece of behavior that developers will leverage?
Strictly speaking, the TDD'd version is a more complicated API. Even adding one optional parameter to a method carries "mass". Consider documenting the parameter-less version:
Publishes the current post. The
created_at
timestamp is set to the current time. Returns thecreated_at
timestamp.
For numbers sake, it's 40 words. More importantly, it reads linearly. Now let's look at the dependency-injected version:
Publishes the current post. By default,
created_at
is set to the current time. Optionally, callers may pass in aTime
object, or any object that returns aTime
object when sent thenow
message. Thecreated_at
column is set according to thatTime
value. Returns the value of thecreated_at
timestamp.
This one is 54 words. That's not too many more, numerically, but notice that the explanation is no longer linear. There's a default, easy case where I don't care about the timestamp. Then there's a clever case where I do care about the timestamp. In real API documentation, I'd need to specify when and why I'd want to use that clever case and what it looks like.
There's some further potential trouble lurking in this API. What if a caller passes in the wrong kind of Time
object? What if sending the now
message raises an exception? Those are important parts of the API too, both from a behavior specification perspective and when considering the user experience of using this API in code and possibly troubleshooting it when things go wrong.
My point is, that optional argument is starting to look rather weighty. Adding the code is pretty trivial. The possible interactions with the optional argument and its support cost is where it gets expensive. Like many things, it's a trade-off.
I won't claim to know which of these is better. Honestly, I think it comes down to a subjective view on what's important: test design, or API design. This is where I can't make a bold-sounding prognosis. I believe that design, even of code, is about deciding what to leave out. Everyone has to decide what to leave out for themselves.
Declaring coupling
A lot of discussions on software design end up focusing on dependencies and coupling. In short, hell is dependencies and the couplings it produces. It's a tricky problem because its hard to look at some program text and see all of its dependencies; some of them require intelligence to recognize.
In Ruby, we don't have very good ways to declare a class's dependencies and no ways ways to declare its couplings. We can describe a project's dependencies with a Gemfile or a file's dependencies with requires. The trick is that these specifications often explode in complexity. Requiring Ruby's thread library brings in some thread-safe data structures like queues and condition variables. Requiring ActiveRecord brings in a world of dependencies and causes a number of behavioral changes to Ruby that some consider impolite.
In some tinkerings with Clojure this weekend, I was struck how the ns
function is more effective at both declaring dependency and coupling and in restricting the possible distress those qualities may bring. Consider this snippet from my weekend project:
(ns hrq.routes
(:use compojure.core
hrq.core)
(:require [compojure.route :as route]
[compojure.handler :as handler]
[ring.middleware.params :as params]))
I have pedantic quibbles with ns
, but I like what's happening here. This file can only use the functions in compojure.core
and hrq.core
with no namespace qualifications. This file can only use the functions from compojure.route
, compojure.handler
and ring.middleware.params
when they are qualified with the proper prefix. So now I have a very good idea of what code this particular file depends on and where I should look to find behavior that this file is subject to.
To a lesser extent, I have a good guess about what state this file depends on. If there are dynamically scoped variables (pardon me if those are the wrong Clojure/Lisp words) in the dependencies declared for this file, I would need to care about them. If those files are pure behavior (i.e. referentially transparent pure functions), I have nothing to worry about.
Clojure isn't perfect in this regard; it does allow mutations and state changes outside of functions. It's not strictly referentially transparent like Haskell is. The tradeoff is worthwhile, in my opinion. Admit some possible coupling in exchange for ease of building typical programs.
I'm not sure that Clojure is inherently superior to Ruby in this regard. It's possibly a momentary cultural advantage, a reaction by those who were burned by expansive, implicit dependencies in Ruby and other languages. That said, it's a good example of Clojure’s considered separation of concerns solving problems that are quite thorny in other languages.
Intermediate variables, organizing OO, meeting Grinders half way
I work with Dave Copeland at LivingSocial, but not on the same team. Maybe someday I’ll fix that, but for now I learn a lot from his writings. Herein, a few things worth checking out yourself.
If you ever need to read my code, you’ll eventually come to suspect I have a particular dislike for intermediate variables. You’ll come to suspect this through finding lots of uses of inject
and tap
, two Ruby methods not everyone is on good terms with. You can imagine I’d side with Dave on the subject of Tap versus intermediate variables. You’d be right, but Dave says it so well, you should read his take on the joy of tap
. He also shows how to annoy people with tap
-like constructs in other languages. If you’re into combinators, Reg Braithwaite has written about tap
in terms of Kestrels.
I’ve been learning a lot about how to think about organizing a non-trivial object-oriented system this year. Gary Bernhardt is doing some fantastic work explaining a hybrid imperative/object/functional system. If you don’t have time to dive into Gary’s entire backlog (it’s worth it to find the time), Dave covers some similar ground describing the only four types of classes in your OO system. Think of these as a post-hoc observation on how many systems seem to evolve; Record objects take root, Service objects reveal themselves (often intertwined amongst other objects), Builders are sprinkled throughout, and there are a few classes hanging out that you wish you’d made immutable. These are handy guides for thinking about and refactoring an existing design. That said, I think it would be overkill to start a design with these archetypes. Caveat: some developers will really dislike organizing a system this way; tread carefully.
I’ve written about the virtues of The Grinder. I know a lot of non-Grinders wish that the Grinder knew more about how to take the code they’ve made to work and improve it so that it is more malleable in the future. Making it Right: Technical Debt vs. Slop sets out a good mindset on how this can happen. Think before you type, write a test, make it work, and then tidy it up with future malleability in mind. From there, non-Grinders need to meet Grinders in the middle is in shrinking the feedback cycle. When tests are too much effort to write or take too long to run, Grinders fall back to their old habits. When making it right involves too many intermediate steps with nothing to show for it, Grinders move on to the next thing. When a non-Grinder learn to be less precious with our work, or a Grinder learns to take a moment to round off the sharp corners on their work, you end up with a much stronger team. Fight for it.
Why I'm down on hypermedia containers
In response to my hypermedia opinions, Mike Kelly said:
These two seem to conflict: “In my opinion, abstract container formats aren’t useful.” and “Just use JSON”. People normally talk about “generic” media types, but they don’t have to a “container” at all, they can simply add conventions for linking. Having conventions for this stuff is useful because it allows us to build tooling around it, if everyone reinvents the wheel in their own way then we can’t build re-usable code. For a similar reason, “specifying your own custom MIME types” is not a good idea – there’s also the time cost associated with doing that. If you use something like hal+json you avoid that cost, and can concentrate on establishing your API’s workflows via link relations.
The logic behind the madness goes like this: abstract containers aren’t solving a problem I currently have. Unfortunately, this means they create problems for me. In the end, I’m building an API to provide functionality, not as advocacy.
As of summer 2012, there are ideas like HAL, JSON collections, etc. and specifications of those ideas. There are very few implementations. As a service provider, I wouldn’t actually get any benefit out of using those formats. The convention, within my own API, that fields ending in _url
are links is sufficient. I’d actually end up net negative, because I’d have to explain how e.g. HAL works and support client developers seeking to understand how to work with it. Anyone building to my API would likely end up having to write their own HAL code, so they don’t benefit much either.
I’ve decided to use JSON because providing an API that returns HTML and expects users to scrape it via selectors is extremely confusing to developers. Keep in mind, not everyone is savvy to the latest development trends. To them, an API means an HTTP service that returns XML or JSON. If I were to embrace HTML as a response type, I’m again stuck with explaining a new concept to client developers.
If it’s not obvious yet, one of my main principles in adopting hypermedia is to avoid educating developers on hypermedia as much as possible. I’m in the game of providing a useful API, not a system that shows off the possibilities of hypermedia and how deeply committed I am to its theories.
Finally, I’ve chosen to craft my own content types because I need some kind of contract with client developers that tells them what kind of data they can expect to see, plus some documentation that expresses that contract in a way that is easy for humans to understand. An RFC-style specification that states what a content type MUST/MAY/SHOULD include is exactly the right kind of abstraction. It allows me to update the specification with a version identifier and specify how each revision changes in terms of what data is available. Further, I found a content type the most tractable solution for specifying the input formats supported by PUT and POST endpoints. None of the abstract containers that existed as of August 2012 fit my needs for specifying links, structure, and how to submit data via POST
/PUT
/PATCH
.
Honestly, link traversal and machine-to-machine interaction are not the pain I’m feeling. What I want is the simplest possible API that allows potential client developers to understand what they can do via our API and how to do it. Further, I want it to be possible, even if it’s not magical or easy, to change the API in the future so I’m not constricted by its current design. I feel no need to apply all of the hypermedia principles to make something useful; I can cherrypick some of the hypermedia principles and still achieves the goal of an API that is stable but not set in stone.
Hypermedia opinions
Through the Gowalla API, and now the Sifter API, I’ve worked with a couple systems one could reasonably call a hypermedia API. Since smart people are talking about them today, I feel compelled to throw in my two cents.
A URL-based API alone won’t prevent breakage, as many point out. It won’t even prevent people from figuring out how to extract IDs and continue to bang URL strings together. I don’t know why creating URL strings is the security blanket of many API client developers, but it seems you can’t take it away from a few of them.
That said, a URL-based API does make life easier for good actors. Client developers, especially the ones that can’t upgrade their deployed applications quickly, can sleep better knowing that the upstream API could change and their code won’t break. Service developers can rest easy knowing it’s not easy, but it is possible to change their URL structure if they need to.
A hypermedia API means you can’t skip on documentation. In fact, it means you probably need better documentation. You’ll need to explain what each link in the API responses means (is photos_url
the URL for my photos, or my friends’ photos?) and what kind of data they can expect that URL to return (a photo object? a collection of photo objects? a user?) As I mentioned before, a lot of client developers don’t have their minds wired for hypermedia yet, so you’ll need a lot of examples for how they should build their clients.
In my opinion, abstract container formats aren’t useful. Squeezing your application’s data into someone else’s data model is not a great place to live. That said, I do think specifying your own custom MIME types is a promising idea. You specify each of the content types in your API, RFC-style, and then provide examples of that data. Should you need to change your response formats, you update your RFC-style specification, adding a new field as a “MAY provide” type feature.
The rub of this approach is that you can end up with an explosion of response-type handling code in your application. Again, it’s not that hypermedia principles make it easy, they just make it possible.
I’ve seen some hypermedia APIs expressed as hypertext, using HTML and cleverness. I don’t see the benefit of this. Just use JSON, and maybe specify your own response types.
The shortcoming in much of the hypermedia content out there is they focus on clients reading data and hand-wave over clients that need to create or update data. I can see why; I think that machine discoverable parameters are a tarpit. Trying to tell a client what fields the server will accept, what types are accepted, and then handle all the possible error flows is verbose and riddled with edge-cases. The way I’m solving this is to specify, in the documentation, which URLs clients can expect to POST
/PUT
/etc. data to and what content-type those URLs expect to receive. I’m pretty much doing the least hypermedia-ish thing possible, but I think that’s the correct choice right now.
The great thing about the principles of hypermedia APIs and its discourse if a focus on workflows. The biggest mistake I’ve made in building APIs is in exposing a database instead of a service. No one cares what your table structure or domain model looks like. They want to fetch some data, preferably indexed in a way that is immediately useful to them, and maybe write some data back. When you look through this lens, API design starts to look a lot like UI design. It’s fun!
You should read about hypermedia APIs, if only to challenge your thinking. It helped me a lot to do just that. Check out Steve Klabnik’s Designing Hypermedia APIs; it’s not perfect, but it makes a lot of these things easier to grasp.
In the end, I think designing, building, and supporting a hypermedia API is hard. You may be better off with an RPC-over-HTTP, or ID-based REST design. The good news is you can benefit from an incremental application of the principles of hypermedia APIs; you don’t have to go all in before you get something out of it.
Wherein I heart Code Climate
We’ve had Sifter’s repo hooked up to Code Climate for a couple months now and I’m really loving it. Garrett and I have both found it fun to kill duplication or refactor away complex code. A decent test suite enables this, but Code Climate is very much the compass that points you right to the trouble spots. The Code Climate blog is a great read too, consistently featuring thought-provoking ideas on how to think about making better code.
I love tools like flog and flay for quick smell detection. If you are like me and too lazy to configure CI and code metrics, Code Climate’s easy setup and awesome trending are well worth a look.
Needs better words
How much easier would Haskell be if its vocabulary wasn’t so deeply rooted in abstract mathematics? How many more people would immediately understand Cassandra if it just adopted the vernacular of row-oriented databases instead of overriding it with column-oriented semantics? Wouldn’t the programming world be better if every language didn’t call itself object-oriented?
So many programmer-facing things could be better if they had better names for concepts. The power of good naming:
Characters are cheap, confusion is costly. Let’s not make things harder for the programmers who come after us. Remember, this is just as likely to be ourselves in a few months. Let’s avoid using a name like prj when project is only four characters more typing. Anything that reduces reading friction in our code is a good thing.
The cynical view is, we are actively confusing and inhibiting ourselves when we use names that are too short, not clear, or outright wrong. The optimistic view is that there’s a progression we can take from not knowing what something should be named, to giving it an acceptable name, to using the naming process to discover better structures.
If you ever hear me say something “needs better words”, it means that I think the idea is right but the labels are wrong. A philosophical dialog may ensue, where I struggle to discover what the essence of the idea is. The end goal is a word that is concise, has the right connotation, and whose meaning is obvious and accessible to as many audiences as possible.
I love naming things.
A pithy take on development vs. operations
The essential, face-palming difference between too many development teams and too many operations teams is thus:
Development: “I know how it works, but I don’t know how to make it work”
Operations: “I know how to make it work, but I don’t know how it works”
Be the solution, friends.
Follow the smells
It’s handy to know a lot about programming langauges, patterns, “best” practices, and anecdotal experience in applying those ideas. But premature application of ideas can lead to its own bad experiences and new anecdotal evidence. How can you apply ideas without falling into the premature architecture/optimization trap?
Follow the smells.
You know what a bad method looks like. You know what slow code looks like and how to find it. You can tell when a class is doing too many things. Follow those smells.
Once you’ve smelled it, you’ve dealt it. Kidding!
Once you’ve found a culprit that is imminently making your life as a developer harder, you have to explain it to someone else. Tell them why it’s slow, badly coupled, or too much architecture. Once they’re convinced, then you can reach into that deep knowledge of languages, patterns, practices, and experience to fix the problem.
You commit the code, push it to production, and do a happy dance. You’re not done.
Now you need to share it. Write down what you did and share it with your team, lest the problem happen again. Show your co-workers how to find the problem elsewhere and quickly dispatch it.
If you do it this way, you’re helping yourself three times:
- You fixed the original problem
- You showed your colleagues how to fix the problem or how to avoid creating the problem
- You showed your colleagues how to make measurable, if minor, progress in making your application better without the need for drastic projects
Follow the smells. Fix the smell. Put the fix in everyone else’s brain. Repeat.
A kingdom of concerns
When doing object-oriented programming and following SOLID principles, there is sometimes a concern that classes will proliferate and you end up with a Kingdom of Nouns.
I find it more concerning when there is a proliferation of concepts. Too many layers, too many patterns, too many frameworks. The best designs I’ve seen provide just one or two concepts that manage to tie everything together without breaking orthogonality.
The great thing about Rails and Sinatra was that they boiled previously conceptually heavy domains down to a simpler, better set of ideas. In doing so, they move you up the hierarchy of needs, so to speak, and you still end up inventing your own concepts and nouns. More on that soon!
Designing for Concurrency
A lot is made about how difficult it is to write multi-threaded programs. No doubt, it is harder than writing a CRUD application or your own testing library. On the other hand, it’s not as difficult as writing a database or 3D graphics engine. The point is, it’s worth learning how to do. Skipping the hubris and knowing your program will have bugs that require discipline to track down is an enabling step to learning to write multithreaded programs.
I haven’t seen much written about the experience of writing a concurrent program and how one designs classes and programs with the rules of concurrency in mind. So let’s look at what I’ve learned about designing threaded programs so far.
The headline is this: only allow objects in consistent states and don’t rely on changing state unless you have to. Let’s first look at a class that does not embody those principles at all.
class Rectangle
attr_accessor :width, :height
def orientation
if width > height
WIDE
else
TALL
end
end
WIDE = "WIDE".freeze
TALL = "TALL".freeze
end
Just for fun, mentally review that code. What are the shortcomings, what could go wrong, what would you advise the writer to change?
For our purposes, the first flaw is that new Rectangle
objects are in an inconsistent state. If we create an object and immediately call orientation
, bad things will happen. If you’re typing along at home:
begin
r = Rectangle.new
puts r.orientation
rescue
puts "whoops, inconsistent"
end
The second flaw is that our object allows bad data. We should not be able to do this:
r.width = 100
r.height = -20
puts r.orientation
Alas, we can. The third flaw is that we could accidentally share this object across threads and end up messing up the state in one threads because of logic in another thread. This sort of bug is really difficult to figure out, so designing our objects so it can’t happen is highly desirable. We want to make this sort of code safe:
r.height = 150
puts r.orientation
When we modify width
or height
on a rectangle, we should get back an entirely new object.
Let’s go about fixing each of these flaws.
Encapsulate object state with Tell, Don’t Ask
The first flaw in our Rectangle
class is that it isn’t guaranteed to exist in a consistent state. We go through contortions to make sure our databases are consistent; we should do the same with our Ruby objects too. When an object is created, it should be ready to go. It should not be possible to create a new object that is inconsistent.
Further, we can solve the second flaw by enforcing constraints on our objects. We use the “Tell, Don’t Ask” principle to ensure that when users of Rectangle
change the object’s state, they don’t get direct access to the object’s state. Instead, they must pass through guards that protect our object’s state.
All of that sounds fancy, but it really couldn’t be simpler. You’re probably already writing your Ruby classes this way:
class Rectangle
attr_reader :width, :height
def initialize(width, height)
@width, @height = width, height
end
def width=(w)
raise "Negative dimensions are invalid" if w < 0
@width = w
end
def height=(h)
raise "Negative dimensions are invalid" if h < 0
@height = h
end
def orientation
if width > height
WIDE
else
TALL
end
end
end
A lot of little things have changed in this class:
- The constructor now requires the width and height arguments. If you don’t know the width and height, you can’t create a valid rectangle, so why let anyone get confused and create a rectangle that doesn’t work? Our constructor now encodes and enforces this requirement.
- The
width=
andheight=
setters now enforce validation on the new values. If the constraints aren’t met, a rather blunt exception is raised. If everything is fine, the setters work just like they did in the old class. - Because we’ve written our own setters, we use
attr_reader
instead ofattr_accessor
.
With just a bit of code, a little explicitness here and there, we’ve now got a Rectangle
whose failure potential is far smaller than the naive version. This is simply good design. Why wouldn’t you want a class that is designed not to silently blow up in your face?
The crux of the biscuit for this article is that now we have an object with a narrower interface and an explicit interface. If we need to introduce a concurrency mechanism like locking or serialization (i.e. serial execution), we have some straight-forward places to do so. An explicit interface, specific messages an object responds to, opens up a world of good design consequences!
Lean towards immutability and value objects whenever possible
The third flaw in the naive Rectangle
class is that it could accidentally be shared across threads, with possibly hard to detect consequences. We can get around that using a technique borrowed from Clojure and Erlang: immutable objects.
class Rectangle
attr_reader :width, :height
def initialize(width, height)
validate_width(width)
validate_height(height)
@width, @height = width, height
end
def validate_width(w)
raise "Negative dimensions are invalid" if w < 0
end
def validate_height(h)
raise "Negative dimensions are invalid" if h < 0
end
def set_width(w)
self.class.new(w, height)
end
def set_height(h)
self.class.new(width, h)
end
def orientation
if width > height
WIDE
else
TALL
end
end
end
This version of Rectangle
further extracts the validation logic into separate methods so we can call it from the constructor and from the setters. But, look more closely at the setters. They do something you don’t often see in Ruby code. Instead of changing self
, these setters create an entirely new Rectangle
instance with new dimensions.
The upside to this is, if you accidentally share an object across threads, any changes to the object will result in a new object owned by the thread that initiated the change. This means you don’t have to worry about locking around these Rectangle
s; in practice, sharing is, at worst, copying.
The downside to this side is you could end up with a proliferation of Rectangle
objects in memory. This puts pressure on the Ruby GC, which might cause operational headaches further down the line. Clojure gets around this by using persistent data structures that are able to safely share their internal structures, reducing memory requirements. Hamster is one attempt at bringing such “persistent” data structures to Ruby.
Let’s think about object design some more. If you’ve read up on domain-driven design, you probably recognize that Rectangle
is a value object. It doesn’t represent any particular rectangle. It binds a little bit of behavior to a domain concept our program uses.
That wasn’t so hard, now was it
I keep trying to tell people that, in some ways, writing multithreaded program is as simple as applying common object-oriented design principles. Build objects that are always in a sensible state, don’t allow twiddling that state without going through the object’s interface, use value objects when possible, and consider using immutable value objects if you’re starting from scratch.
Following these principles drastically reduces the number of states you have to think about and thus makes it easier to reason about how the program will run with multiple threads and how to protect data with whatever form of lock is appropriate.