Proximity

 I'm the first person that will talk (or yell) about how insane it is that so many people aren't leveraging the power of the internet to build internet products and companies.

Our small team builds, maintains and sells a product used by independent yoga studios across the world, we've helped numerous startups launch their ideas, and we've implemented software solutions for billion dollar companies that have eliminated legacy systems with modern software.

And we do this with a team of people across four states, three countries, and two continents.

The notion that you can't do great things when you're not in the same location as the people you're working with is simply wrong, and getting me to believe otherwise would require me to think that I am living my entire life in an imaginary world.

But nothing is free. And as with everything, there are tradeoffs.

Because the internet is so powerful, and because it enables so much, we can forget about how important proximity is. 

We can in fact lean too much on the internet.

Being on a hangout with someone is not the same as giving them a hug. Sharing emoji in a chat room is not the same as laughing over drinks. And reading an email about a concern someone has is not the same as hearing their voice crack in person as they share their fears.

The past few months I've been reminded that getting together with the people that are important to you, in person, is critical to maintaining healthy relationships.

Our team recently had a retreat in Wisconsin where for the first time most of us got together in one place. It was a pivotal moment for us.

One of our programmers who lives in Europe came to the states for 3 months over the summer, and there's no doubt that our relationship is stronger because we were able to spend time together.

I just came back from a visit with an important customer in California and while we work together very well remotely, there are just some challenges that are easier to tackle when you're in the same room together.

The internet is wonderful. That I am able to run an entire business from a laptop, and that anyone who works with us can work from anywhere in the world that they want, whenever they want, is something that I am grateful for on a daily basis.

I truly believe we are living in magical times. 

But it's important to recognize that when it comes to human relationships, the internet *facilitates* connection. It isn't connection itself.

Proximity matters.

Opt-in to your business logic

  Thanks to Bruno for the section on inheritance.

In a legendary post by Bryan Helmkamp, he talks about seven ways you can refactor fat models. All seven relate to extracting code into separate plain old Ruby objects and using them when needed. And this past week, our team had a discussion about inheritance and how it's frowned upon by some of the experts in the Ruby and Rails fields. After really paying attention to all of this and trying to get to the essence of it, here's what I've learned.

The main idea is this: opt-in to your business logic

Opt-in is synonymous with a white-list. Instead of allowing everything and deciding what to exclude (black-listing), you white-list instead. You make a conscious decision as to what should be allowed. You use a white list when you use attr_accessible. You are allowing certain attributes to be mass assigned.

In the case of your business logic, you have to make a conscious decision as to when business logic should execute. 

If you want to save a model from the console, it shouldn't trigger 5 callbacks.

If you have a bunch of callbacks in your model and all of them include some sort of conditional, that's bad. If you want to do some backend work or a migration, you'll have to trace through your code to figure out if the callbacks will run. You have to ask the question, do I even want these callbacks to run? 

Updating a simple field like the name of something should be an easy task.

The exception to this rule is persistence. Callbacks can be managed nicely if you stick to only using them for persistence and avoid using conditionals. If you have a bunch of conditionals on your callbacks, it means they don't execute every time. If your callbacks don't execute every time, they aren't part of the core domain logic and shouldn't be in the model anyway. 

Here's an example of callbacks with conditionals. I'm sure you've seen some code like this before. To figure out which ones will run, you'd have to also look for and understand what the conditionals will return.

Your object should do one thing and do it right every time.

Granularity matters. If you want to opt-in to your business logic, you should be able to opt-in to any combination. 

For example, if you want to post to social networks after a model is created, you should be able to pick and choose which ones you want. If I want to post to Facebook, it also shouldn't post to Twitter.

Take a look at the example below. If you don't want to post to Twitter, you can simply comment out the TwitterPoster and you're done. It's a much better option to keep these separate rather than use a more generic SocialNetworkPoster..

Inheritance is very rigid, usually there is a better option.

If you're writing some code that will be used by a couple of classes in your app, use inheritance only if you absolutely must.

It is common knowledge among folks who practice object oriented design (not just Rubyists) that 'composition should be preferred over inheritance'. In other words, if you were thinking about making a superclass and subclass objects, don't - most likely you can achieve the same thing by making a Ruby module.

Here's a simple example that nicely shows the limitations of inheritance.

If you use these methods and other to opt-in to your business logic, you'll find yourself enjoying your code more. You'll be able to refactor things more easily. You won't find yourself in callback hell and you'll be able to write classes composed of many smaller units. 

Once a unit works, it should work forever. That's the idea. You'll find that you won't have much churn in your units which leads to better code.

 


An intro to CanCan and managing permissions, authorization

CanCan is our goto library for managing permissions in our applications. Like any library, you have to know how to use it. It comes with its own set of nuances and patterns. If you don't properly organize and manage it, you'll end up with a load of technical debt.

Before getting into details, you should understand a few key details about CanCan. These are details we've run into many times before and it always seems to trip up new people using the CanCan library. 

  1. check_authorization  If you're using CanCan, you'll want to be sure you are checking authorization. This happens in your controllers. Most of the time, it should be an exception if you skip authorization. Why would you define a bunch of permissions and then forget to authorize against them?
  2. load_and_authorize_resource:  Based on the permissions you've defined in your abilities file, CanCan can load and authorize your models in your controllers. For example, if you have a PostsController and you use the index action, CanCan will load all @posts which a user has access to. There are exceptions and loading your index action will fail if you use a block to define permissions.
  3. Ability precedence:  This is one of the most important gotchas and you may lose some time trying to debug this. Make sure you read about ability precedence and experiment with it. It's important to note that with CanCan, manage means any. If you can manage a post, you can perform any action on that post. The first permission you define takes precedent over any that follow.

Here's a block of code to help you understand the points above: 

With the introduction of strong_parameters in Rails 4 (also a great pattern you can use in your Rails 3 projects), you'll want to have a pattern for using it in unison with CanCan. CanCan doesn't natively support strong_parameters yet. CanCan attempts to load params before being filtered by strong_parameters; thus, strong_parameters raises an exception.

For us, we've started to use cancan_strong_parameters  which patches CanCan to allow strong_parameters. We'll try to update this post when CanCan begins to support strong_parameters.

How do you handle strong_parameters with CanCan? Let us know in the comments below. 

 

Software is not bricks

I've had a number of conversations lately with people who are building web products to either support an existing business, or to start a new business entirely. These conversations take place with existing clients, prospective clients, friends and family members. 

We make software, so we have these conversations frequently. But it seems now more than ever everyone has an idea for an app.

One theme that keeps coming up is that people will often compare a software project to some sort of other 'real world' project that they can relate to. This makes sense, because by relating their idea to something they have experience with it helps them to understand the process of building something.

Indeed, we'll often use brick and mortar analogies saying something like "we'll definitely want to clean that up later, but you don't start hanging the paintings before you put up the drywall" if we're explaining why it's not quite time to work on a new icon.

But there are very real and important ways to understand how 'software is not bricks'. If you're thinking of building an application of any kind, I think these are some good things to keep in mind.

Most People have a frame of reference for the cost of bricks, but not for software

Just about everyone pays a monthly rent or mortgage on a home. We also tend to have a general understanding that the city in which you live has an impact on your home. We know that a home in San Francisco is more expensive than Iowa or Nebraska. Because of this, we have a built in frame of reference for how much things cost. 

The exact opposite is true with software.

Most people interact only with software that has had tens of millions of dollars worth of design and development effort put into it, and most people have never used the first version of a beta product. Their frame of reference for how software should work are Facebook, Twitter, Square, iOS, and maybe something like Salesforce and some productivity suite from Microsoft. 

The kicker is that just about no one goes to Facebook and thinks to themselves, 'wow this is some nice software, I bet it cost a fortune to make.' But if you walked into a 4 bedroom single family house in San Francisco that looked over the golden gate bridge you would know it took some real money to purchase. 

The industry helps perpetuate this with stories of 'kids in hoodies' hacking all night and then selling it for a couple million dollars. The difficult work that comes for years after is treated like a footnote.

Value is based primarily on the number of people that use your product

If you spend a million dollars building an office complex and you don't rent it out to anyone, it still has some intrinsic value. It's highly unlikely that the value of the building will reach zero. Likewise, putting 100 people in a small apartment will do nothing to improve the value of the apartment.

Again, software is the opposite.

 You could spend a million dollars having the best development team in the world writing the cleanest code with the perfect design that you imagined. But if no one is using it, or if it's not solving a real problem or providing real entertainment value, then it really doesn't matter how much time or money you spent building the software. A million dollar investment in software could in fact be worth close to nothing.

Of course there's an opportunity here which is that if you can work like crazy to solve real problems and get users, the simple fact that you have customers can help you overcome a lot of other issues, even if your product isn't as robust as you want it to be.

Limitations on software are less obvious

If you were building a house and suddenly decided it might be sweet to have a swimming pool on the roof, you have a built in understanding that this change would require significant effort to accomplish. With software, the limitations are so much less obvious that you have to constrain yourself because you can do just about anything. 

It's possible to do so much, that you can actually do too much.

Software is not bricks

It's not a good or a bad thing that software is not bricks. But if you're thinking of starting a project make sure you're aware that both the risks and rewards are inherently different from those in the physical world, and this reality can work with you or against you.

Build wisely.

 

Do you write bad CSS?

CSS is so powerful because you can do so much with it. It's constantly improving. CSS3 is an amazing advancement for web developers. 

However, since you can write CSS however you'd like, a lot of people aren't very good at writing it - myself included. Over the past few months, I've challenged myself and our team to improve. Here's what I've learned: 

Don't style elements by ID

It's tempting. You can do it. But, you shouldn't. Avoid it at all costs. 

IDs are meant to be unique. If you style an ID tag, it means you're styling a unique element; therefore, you're not writing reusable CSS. Remember the DRY principle? Styling an ID is a blatant violation of the DRY principle. 

Avoid more than three levels of nesting

Deep nesting lends itself to CSS that isn't reusable. If you have more than three levels of nesting, you're probably styling elements based on their container. When you have many levels of nesting, the context of an element dictates its style. Most of the time deep nesting will cause problems.  Deep nesting should be the exception, and not a common pattern.

Naming is hard

Naming is notoriously difficult, and it's just as difficult while writing stylesheets. Try to describe the element you're styling in English. Don't skimp on naming in exchange for less typing, but don't use extremely long class names either. 

Do you want to understand your code in 6 months? Try hard to improve naming. 

Think of elements in terms of modules or components

If you start thinking in terms of modules and components, you'll start to write better CSS. Sometimes, context matters; and therefore, calls for you to do some nesting. More often than not, nesting is bad. 

Components should be reusable. If you want to put a component on a different page in a different context, it should still look the same. If it doesn't look the same, it's either a slight variation of the component or its a completely new component altogether. 

Split components into separate files

Have you ever worked on a project with one massive, ugly, disorganized stylesheet? I think we all have - and it's no fun. A good practice is organizing your stylesheets by component. Styling some tabs to be used throughout your application? Use tabs.css as a filename. What about a header component? Use header.css.

If you're worried about including many stylesheets in production, don't. You should be using stylesheet compilation. If you're using Rails, we have the asset pipeline to help us do this.  If you need a standalone solution, try YUI compressor.