You’re reading Signal v. Noise, a publication about the web by Basecamp since 1999. Happy !

Ignore details early on

Jason Fried
Jason Fried wrote this on 26 comments

There’s a lot of talk about how important details are. But what’s often left out of the discussion is timing. Details and timing are intimately related.

God, the devil, beauty, perfection, precision – these aren’t the only things you’ll find in the details. You’ll also find stagnation, disagreement, meetings, and delays. These things can kill morale and lower your chances of success.

How often have you found yourself stuck on a single design or code element for a whole day? How often have you realized that the progress you made today wasn’t real progress? This happens when you focus on details too early in the process. There’s plenty of time to be a perfectionist. Just do it later.

Don’t worry about the size of your headline font in week one. You don’t need to nail that perfect shade of green in week two. You don’t need to move that “submit” button three pixels to the right in week three. Just get the stuff on the page for now. Then use it. Make sure it works. Later on you can adjust and perfect it.

Details reveal themselves as you use what you’re building. You’ll see what needs more attention. You’ll feel what’s missing. You’ll know which potholes to pave over because you’ll keep hitting them. That’s when you need to pay attention, not sooner.
(Reprinted from Getting Real, The smarter, faster, easier way to build a successful web application.)

Winning is the worst thing that can happen in Vegas

David
David wrote this on 30 comments

There’s nothing more appealing than thinking you’re just that good. Our brains are optimized for fondly remembering our successes and quietly downplaying our failures.

The casinos in Vegas are primed for this by making it relatively likely you’ll win something early on. By the time you realize that the slight edge of the house means over the long run it’ll win everything back and more, well, you’ve probably spent more than your first ATM stop and then some.

Future coding is a lot like playing the roulette. If you can guess where the requirements of tomorrow will land today, you’ve just scored the ultimate programmer’s prize: looking like a wizard. You saw the future and you were right! High five, brain!

That’s the almost irresistible draw of “flexibility”—often just a euphemism for building half or whole features before you know how they’re supposed to work or whether you need them. Just like in Vegas, the worst thing that can happen is to be right about this once in a while.

Because like the casinos, the house of program complexity will take all your little bets on the future and add them up until you just don’t know how this damn program got so deep into technical debt!

Running up the debt on your code is not just about the quick hacks and dirty commits you know you really should clean up (but just don’t). No, the far more insidious kind of debt is that acquired in the name of “flexibility”.

Every little premature extraction or abstraction, every little structure meant for “when we have more of this kind”, every little setting and configuration point for “things we might want to tweak in the future”. It all adds up, and at a dangerous rate.

The road to programming hell is paved with “best practices” applied too early. Very few abstractions, extractions, or architectures are inherently bad (although I’ll contend that a few are). But most of them are downright evil if applied before they’re called for.

To take the scare quotes off flexibility, you have to be willing to write no code at all. The “Simplest Thing That Could Possibly Work” and “You’re Just Not Going To Need It” are both sayings to help you get there.

This really does mean not a single parameter to a method that has not yet found a use. No needless public methods that might get reused later (not even for testing!)

The hardest—and yet most important—thing in the world of design is the conviction to say no.

When numbers and words don't add up

Jason Fried
Jason Fried wrote this on 30 comments

I recently purchased a new car. A few days later I got an email from Audi asking me to rate my experience. I clicked the link to the survey and ended up seeing this:

Ok, this should be easy.

“Ease of looking at dealer’s inventory” – great, no problems there. A 10, right? Well… was it OUTSTANDING? How about TRULY EXCEPTIONAL? No, it wasn’t those… I can’t say someone’s inventory was truly exceptional. I can’t put my name on that sort of endorsement. So…?

Comfort in the office where we cut the deal? It was fine – I couldn’t imagine it to be better, but was it TRULY EXCEPTIONAL? No. That doesn’t fit. So does that make it a 6 or 7? No, it was better than that… But… So…?

I see this sort of thing in surveys all the time. A simple 1-10 scale (or 1-5, it doesn’t matter), but the labeling of the numbers is so sensationalized that it turns me off. As far as the number goes, I’m happy to give something the highest rating, but the language overshoots the number and then I don’t know how to respond.

I find these sorts of things great reminders of how important it is to choose the right words. Don’t overshoot, don’t sensationalize. Be modest with language. Find the right fit and leave it alone.

Everything is not equally good

David
David wrote this on 17 comments

When talking shop, there’s a natural tendency to avoid the drama of confrontation by relegating all disputes to Your Mileage May Vary. If we can declare all approaches and techniques to be of value only “under certain circumstances”, then we can avoid the hard work of finding the better alternative and merely stop at different.

I don’t think this serves anyone. Well, that’s not entirely true. It supports the ego of the person proposing the bad idea. It also helps the ego of anyone who bought into it. But it doesn’t help the world move forward to hoist up every bad idea as “just another option”.

Of course, you can’t stop this from happening. Not least because people differ on what’s a bad idea. And that’s fine! There will always be different groups advocating for different things. But as individuals, we shouldn’t be afraid to impart our opinion on ideas.

Ideas are meant to be attacked, torn apart, and put back together again. You may well want to shield your idea from the harsh sunlight at first, but by the time it’s ready to meet the world, it should also be ready for rain or shine. Bad ideas are supposed to wither under the stress of criticism.

Hell, even good ideas are supposed to wither in the winter of their life. Precious few ideas are immortal, and even those should be constantly tested to ensure their hearts still beat vibrantly.

The reason we get rid of bad ideas is to make room for new ones. If your catalogue of techniques is brimming with YMMV charity cases, you’re less likely to come up with or entertain new entrants. Hoarding bad ideas that might come in handy when the full moon shines purple is just that. Hoarding.

The flow of new ideas is far more important. Throw ‘em up, bat ‘em out. Declaring “oh well, that didn’t work out like I thought” is an incredibly liberating feeling. I might even go as far as to say it’s motivating. It’s like clearing your desk or emptying your inbox. Ahh, a fresh start!

It takes a strong ego to let go of bad ideas that you originated, but rarely people will think less of you for it. Which is more than can be said of clinging endlessly to bad ideas past their due.

The five programming books that meant most to me

David
David wrote this on 28 comments

There are so many programming books out there, but most focus on specific technologies and their half-life is incredibly short. Others focus on process or culture. Very few focus on the timeless principles of writing good code, period. The following five books had the biggest influence on my programming style and development:

  • Smalltalk Best Practice Patterns: Incredibly practical advice for what constitutes good OO code. It’s done in Smalltalk, but the principles are mostly universal. Probably my favorite nuts’n’bolts of programming design book. Very granular.
  • Refactoring: The fundamental before/after book. Here’s some code that could be better, here’s how to make it better. The trick to reading this book is to carefully read through every single refactoring pattern and then try to apply it on your code base (you don’t have to commit if it doesn’t fix things). You can’t just blow through it or you won’t really learn it. And you can’t just say “oh, I’ll look up a refactoring when I need it” — because then you don’t know what to look for.
  • Patterns of Enterprise Application Architecture: Great inventory of many of the patterns that underpin Rails itself, as well as descriptions of many of the “new” approaches that people advocate today (like transaction scripts and service layers). You won’t necessarily implement most of these patterns yourself, but it’s an invaluable resource to understanding the differences in architectures and why framework work the way they do. (Funny anecdote: before I created Rails, I redrew many of the diagrams in OmniGraffle for Martin Fowler because I liked the book so much.)
  • Domain-Driven Design: This is probably the least readable book of the bunch. It’s a slug to work through, but the ideas are worth it. It’s a great primer on how to turn a problem space into a beautiful OO domain model. What should your models be called? What logic goes where? How do we reproduce reality into an object model.
  • Are Your Lights On?: This isn’t technically a programming book, but it deals with the biggest problem facing developers none the less: What is the problem we’re trying to solve? Is it the right problem? Could we solve a different problem instead and that would be just as good? Nothing has increased my programming productivity more than being able to restate hard problems as simple ones.

If you consider programming to be a subset of writing, and I certainly do, then you would also do well to read Elements of Style and On Writing Well. I’ve found reading those made me a better programmer as well.

Reading these five to seven books will give your programming chops more vitamins and nutritional value than a couple of year’s worth of blog posts and tutorial.

Getting hyper about hypermedia APIs

David
David wrote this on 56 comments

Using URLs instead of ID references in your APIs is a nice idea. You should do that. It makes it marginally more convenient when writing a client wrapper because you don’t have to embed URL templates. So you can do client.get(response[:person][:url]) instead of client.get("/people/#{response[:person][:id]}"). But that’s about it.

The recurrent hoopla over hypermedia APIs is completely overblown. Embedding URLs instead of IDs is not going to guard you from breakage, it’s not going to do anything materially useful for standardizing API clients, and it doesn’t do much for discoverability.

Preventing breakage
According to hypermedia lore, you will be able to willy nilly change your URLs without needing to update any clients. But that’s based on the huge assumption that every API call is going to go through the front door every time and navigate to the page they need. That’s just not how things work.

If I want to request a message off a project in Basecamp, I would have to do something like this GET /projects, GET /projects/1, GET /projects/1/messages, GET /projects/1/messages/2. That’s great for the first fumbling in the dark discovery, but it doesn’t work as soon as I bookmark that last URL because I want to send comments to it later.

Just like bookmarks in the browser break if you change the URL, so will any client that’s stored a URL for later use.

Because breaking URLs is such a bad idea, people tend not do it. If you look at the successful APIs on the web, they’ve stayed remarkably stable because that’s the best way to prevent breakage. Like the W3C says: Cool URIs don’t change. Which means this isn’t much of a problem in the wild and even if it was, hypermedia APIs would still have big holes with direct links break.

Enabling discoverability
Good API docs explain what all the possible attributes of a resource are. They explain the possible values of those attributes. The options available and so forth. Thinking that we can meaningfully derive all that by just telling people to GET / and then fumble around to discover all the options on their own just doesn’t gel with me.

How do I know that the data I happen to be stumbling across includes everything that’s possible to do? What if the project I request doesn’t have any documents attached with it? How do I know how to find those and how to add new ones?

Standardizing API clients
The idea that you can write one client to access multiple different APIs in any meaningful way disregards the idea that different apps do different things. Just because there’s a standard way to follow a resource to a sub-resource doesn’t mean that you can just write one generic client that then automatically knows how to work with any API.

Any generic API will not know what to do with the things it get. It won’t know the difference between Flickr photos and Basecamp projects. The assistance of being able to follow a link to go from photo to comments and project to messages is nice, but as explained in the beginning, not exactly earth shattering.

Every single application is still going to need a custom API client. That client needs to know what attributes are available on each resource and what to do with them.

In summary, here’s a low-fi solution to these three problems that doesn’t require a spec or involving the IETF:

  1. Don’t change your API URLs.
  2. Document your API.
  3. Provide a custom client wrapper (you’ll have to write one anyways).

On top of that, be a chap and use URLs in IDs because convenience is nice and it doesn’t take too much effort if you’re using something like jbuilder anyway. But don’t go thinking that you’ve magically solved all these problems just because you did.

We’ve been down this path to over-standardization of APIs before. It lead to the construction of the WS-deathstar. Let’s not repeat the same mistakes twice. Some times fewer standards and less ceremony is exactly what’s called for.

Put chubby models on a diet with concerns

David
David wrote this on 47 comments

Different models in your Rails application will often share a set of cross-cutting concerns. In Basecamp, we have almost forty such concerns with names like Trashable, Searchable, Visible, Movable, Taggable.

These concerns encapsulate both data access and domain logic about a certain slice of responsibility. Here’s a simplified version of the taggable concern:

module Taggable
  extend ActiveSupport::Concern

  included do
    has_many :taggings, as: :taggable, dependent: :destroy
    has_many :tags, through: :taggings
  end

  def tag_names
    tags.map(&:name)
  end
end

This concern can then be mixed into all the models that are taggable and you’ll have a single place to update the logic and reason about it.

Here’s a similar concern where all we add is a single class method:

# current_account.posts.visible_to(current_user)
module Visible
  extend ActiveSupport::Concern

  module ClassMethods
    def visible_to(person)
      where \
        "(#{table_name}.bucket_id IN (?) AND
          #{table_name}.bucket_type = 'Project') OR
         (#{table_name}.bucket_id IN (?) AND
          #{table_name}.bucket_type = 'Calendar')",
        person.projects.pluck('projects.id'),
        calendar_scope.pluck('calendars.id')
    end
  end
end

Concerns are also a helpful way of extracting a slice of model that doesn’t seem part of its essence (what is and isn’t in the essence of a model is a fuzzy line and a longer discussion) without going full-bore Single Responsibility Principle and running the risk of ballooning your object inventory.

Here’s a Dropboxed concern that we mix into just the Person model, which allows us to later to route incoming emails to be from the right person:

module Dropboxed
  extend ActiveSupport::Concern

  included do
    before_create :generate_dropbox_key
  end

  def rekey_dropbox
    generate_dropbox_key
    save!
  end

  private
    def generate_dropbox_key
      self.dropbox_key = SignalId::Token.unique(24) do |key|
        self.class.find_by_dropbox_key(key)
      end
    end
end

Now this is certainly not the only way to slice up chubby models. For Visible concern, you could have Viewer.visible(current_account.posts, to: current_user) and encapsulate the query in a stand-alone object. For Dropboxed, you could have a Dropbox stand-alone class.

But I find that concerns are often just the right amount of abstraction and that they often result in a friendlier API. I far prefer current_account.posts.visible_to(current_user) to involving a third query object. And of course things like Taggable that needs to add associations to the target object are hard to do in any other way.

It’s true that this will lead to a proliferation of methods on some objects, but that has never bothered me. I care about how I interact with my code base through the source. That concerns happen to mix it all together into a big model under the hood is irrelevant to the understanding of the domain model.

We’ve been using this notion of extracting concerns from chubby models in all the applications at 37signals for years. It’s resulted in a domain model that’s simple and easy to understand without needless ceremony. Basecamp Classic’s domain model is 8+ years old now and still going strong with the use of concerns.

This approach to breaking up domain logic into concerns is similar in some ways to the DCI notion of Roles. It doesn’t have the run-time mixin acrobatics nor does it have the “thy models shall be completely devoid of logic themselves” prescription, but other than that, it’ll often result in similar logic extracted using similar names.

In Rails 4, we’re going to invite programmers to use concerns with the default app/models/concerns and app/controllers/concerns directories that are automatically part of the load path. Together with the ActiveSupport::Concern wrapper, it’s just enough support to make this light-weight factoring mechanism shine. But you can start using this approach with any Rails app today.

Enjoy!

Why I learned to make things

Noah
Noah wrote this on 19 comments

Two years ago this week, I started working at 37signals. I couldn’t make a web app to find my way out of a paper bag.

When I started working here, my technical skills were in tools like Excel, R, and Matlab, and I could muddle my way through SQL queries. I had the basic technical skills that are needed to do analytics for a company like 37signals: just enough to acquire, clean, and analyze data from a variety of common sources.
At the time I started here, I knew what Ruby and Rails were, but had absolutely no experience with them – I couldn’t tell Ruby from Python or Fortran. I’d never heard of git, Capistrano, Redis, or Chef, and even once I figured out what they were I didn’t think I’d ever use them – those were the tools of “makers”, and I wasn’t a maker, I was an analyst.

I was wrong.

Continued…

Dancing Without A Partner

Ryan
Ryan wrote this on 35 comments

Interface design is a two-person dance. By definition it connects two things—the customer experience and the hidden machinery. As a designer, you need a programmer to accomplish anything significant.

I’ve been thinking a lot about teaching UI lately. How do you teach interface design if you can’t get anything done without a programmer at your side? Pair beginner programmers with beginner designers? Sounds like a mess.

Then I remembered my own experience. When I started making interfaces in sixth grade, I didn’t need a programmer because I had Hypercard. Shortly after that it was Filemaker and Microsoft Access. These tools let me connect with data and display it in different ways without convincing a programmer to work with me. It was plenty to learn the fundamentals.

I haven’t seen a UI course that starts with a tool like Filemaker. And Hypercard doesn’t even exist anymore.

If I was designing an introductory interface design course, I think I would start with this kind of tool. Something that lets you gain the experience of putting affordances on the screen, accepting input and displaying output, moving around and enabling tasks.

That way students could get a feel for interfaces without getting into the complicated dance of communication, programmer languages and shared requirements. That all can come later.