The two qualities of great software architecture

Great software architecture solves a present business need and is easy to change when business needs change. Software architects have developed a number of heuristics: patterns and principles that help to achieve these goals. A software engineer that applies but does not fully understand these heuristics may implement them in situations that run counter to the goal. To write great software, it's important to understand how each pattern and principle contributes to the goal. Entire books have been written on most of these subjects. This is intended to be a brief overview, not an exhaustive list or explanation.  Solving a present business need Most users could look at an application and tell you whether it solves a present business need, aside from some of the more subtle nuances. For example, an application may solve one need but is not secure, which is usually one of the business requirements. Some of the criteria that may roll up to this metric, depending on your business: User ex

The many benefits of working in small increments

If you're a software engineer, you've likely heard of the Single Responsibility Principle  (SRP). I believe it's the single most important principle in software engineering. The simple explanation is that one object should do only one thing and do it well. Having a well defined single responsibility makes code easier to understand, change, delete, and test. The complexity of code grows exponentially with size. Two 100 line classes, with proper segregation of responsibility, are significantly easier to understand than a single 200 line one. SRP is the "work in small increments" principle for code, and the same exponential growth in complexity applies to much more than just code. Working in small increments shortens the feedback cycle, which is the best thing any organization can do to increase its velocity. Small Tasks Every task should be small - small enough to complete in less than two weeks, ideally less than two days. Small tasks are easier to write, understan

Say no to low-value features

In most code bases, you can get 80% of the business value with 20% of the features. Imagine if the time spent on the other 80% of features had been spent on high value features - you'd have four times the business value! This is what Google realized in 2011: they needed more wood behind fewer arrows . I have great respect for Google's willingness to kill products that aren't going to have major impact. So many organizations have struggling features that get blindly maintained and never get killed. This is a tragic mistake and a massive tax on the organization. Engineers are the gatekeepers "The difference between successful people and really successful people is that really successful people say no to almost everything" - Warren Buffett If engineers are the ones implementing tasks, then they are also the gatekeepers of which tasks get done and in what order. However in many organizations, the prioritization process is done with minimal engineering involvement. Som

Feature design process

Every time I start work on a new feature, these are the steps I follow to increase the likelihood it will either be a success or never get released. Understand Why This is always the first step I take because it determines all the follow-up steps. You can't understand how until you understand why . It's often valuable to follow the five whys method. Make sure you really understand the root cause, not just the symptom. If it was raining and you had a leak in the roof of your house, would your first step be to mop up the water, or would it be to stop the leak? The answer depends on the size of the leak. Too many solutions fix one symptom without fixing the real problem. On the other end of the spectrum, it's easy to get bogged down in fixing root causes that aren't worth the effort. You don't always have to solve the root cause, you just need to know what it is. Come up with at least two solutions Engineers are often handed a solution instead of a problem. I believe

Crossing the Rubycon

I first learned Ruby about a year ago and it quickly became my scripting language of choice; a position I doubt it will ever lose, hence the name of this blog post. Here are some of the reasons that I prefer Ruby over Python, NodeJS, and PHP, for most use cases. Testing The primary reason I prefer Ruby is how great writing tests is. Tests in ruby can be incredibly concise and natural. The built in mocking, stubbing, and monkey-patching functionality is very powerful. I particularly love the way contexts can be built up with let(:...) to have very descriptive and concise tests. The philosophy If you look at a language like PHP, it has basically no philosophy behind it, at least not a consistent one. Hence you end up with all sorts of weird behaviors. For example, consider preg_match , which finds matches of a Regex in a string: preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or false on failure. Gross .  Wait, where are the results of the regex match? // 

Building up tests via context and let in Ruby

One of my favorite parts about Ruby is writing tests. Here's a pattern I use frequently, which allows you to use context and let to build up state as you progress deeper into the context tree. This is best described with an example: What's going on here? First of all, I like to always add a describe method block for each public method of the class, and then inside it, declare a subject variable which calls that method. Then I add a let(:...) for each of the arguments to the method. This allows me to setup some sensible defaults for each argument, and only modify the arguments as needed in each context. First, I test the default arguments, like in the context "with defaults". Then I proceed to test modifications to each argument. For example, the context "with nil player" expects the described method to return nil when a nil player is passed in. Where things get more interesting is the context "with other existing character". Here, we have a befor

How to be a better communicator as a software engineer

Communication is one of the most important skills as a software engineer, and one of the hardest to improve. Engineers frequently provide recommendations on improvements for "hard" skills, e.g. through code review, but rarely do for "soft" skills. It takes a lot of self-reflection and practice to improve the soft skills. Code is a form of communication “Programs are meant to be read by humans and only incidentally for computers to execute.” - Donald Knuth The most common form of communication used by software engineers is code. Code communicates intentions to peers and future maintainers. Code is read far more than it is written. Next time you go to write new code or refactor old code, consider how much time you spend reading existing code before writing the new code. When you're writing code, remember the tax that other maintainers are going to have to pay every time they read it. Write code that is easy to read, and easy to replace . There are a few ways to im