Deciding to decide when the time is right

Never before in history were so many people required to make decisions so often and of such far-reaching consequences. Where only a handful of wise men used to choose for everybody else, today we’re all decision makers. From the CEO to the junior programmer, everyone’s decisions can send ripples across the globe. We have to learn when and how to decide.

See just how significantly mentions of “decision” have increased since the outset of World War II.

Times when our days were pre-defined, we knew how to crank a widget and how many we were expected to crank to make a day’s pay, are over. Many of us in IT and elsewhere work with systems used by millions, where one bad decision could start mayhem. Welcome to the twenty first century – the age of empowerment and decisions.

Decision road sign

decision
noun
A conclusion or resolution reached after consideration.

Oxford Dictionary

I especially like the bit saying “after consideration“. Without proper consideration a decision is a gamble taken at the mercy of mere chance. Consideration requires data – facts, figures, the knowns and the unknowns, and enough of it to make a decent judgment. Nobody said this better than Sherlock Holmes:

It is a capital mistake to theorise before one has data. Insensibly one begins to twist facts to suit theories, instead of theories to suit facts.

Sherlock Holmes, Adventures of Sherlock Holmes

But we can’t be sitting there all day, collecting facts, while the world moves on. Our competitors surely will come up with something that’ll sweep the rug from under our feet and before we know it we’ll be out of business!

Not necessarily.

Nowhere are timely decisions so important as in the military. Making one too early will give your enemy ample time to prepare. Making it too late will have you overrun by their forces. In either case lives will be lost and destruction will ensue. General Colin Powell, former United States Secretary of State and Chairman of the Joint Chiefs of Staff says decisions should be made as late as possible, but not later.

Don’t rush into decisions – make them timely and correct.

Time management is an essential feature of decision-making. One of the first questions a commander considers when faced with a mission on the battlefield is “How much time do I have before I execute?” Take a third of that time to analyze and decide. Leave two-thirds of the time for subordinates to do their analysis and make their plans. Use all the time you have. Don’t make a snap decision. Think about it, do your analysis, let your staff do their analysis. Gather all the information you can. When you enter the range of 40 to 70 percent of all available information, think about making your decision. Above all, never wait too long, never run out of time.

In the Army we had an expression, OBE—overtaken by events. In bureaucratic terms being OBE is a felonious offense. You blew it. If you took too much time to study the issue, to staff it, or to think about it, you became OBE. The issue has moved on or an autopilot decision has been made. No one cares what you think anymore – the train has left the station. [emphasis mine]

Colin Powell, It Worked for Me

Further down Powell shares the steps of collecting data:

  • tell me what you know
  • tell me what you don’t know
  • tell me what you think
  • always distinguish which from which

Colin Powell, It Worked for Me

These should be printed out on large sheets, posted next to every manager’s desk, facing anybody coming in with a report or request.

Return to the world of software, where bad decision-making may not kill anybody, but “merely” derail companies, sending hordes of people into unemployment. Any sort of Agile methodology preaches making important decisions at the right time.

  • what is the next most valuable thing we should build?
  • whom are we building this for? what problem are we solving?
  • how will we measure success?
  • what are we not going to build?
  • when should we release this to users?

The worst thing one can do is what, unfortunately, comes most naturally to programmers: jump straight into coding. Programmers hate discussing, debating and researching. They want to code already!. Which leads to messy, unwanted products, delivered too late to the wrong people.

Take time to ask questions, research answers and make decisions when they need to be made.

  • Order your stories, use cases or requests into a backlog, find out which of them are the most important and take the time to decide on how to build those correctly. Postpone any decisions on the remaining items until the first ones get done. Delivering them will change the value of all the other requests and spending time debating things other than immediate work will likely turn to waste.
  • Be very open about what you don’t know. Not sure how a business process looks like? How to work with some technology? State it explicitly, refuse to accept the story into the iteration and create a spike instead. This should allow you to spend a time-boxed amount of work on researching missing pieces. In our current process we even created a specific type of sub-task that represents Questions and Concerns, just to have them prominently visible.
  • Prototype with proofs of concept. Building any serious piece of software is a test for how suitable the chosen technology is. Start out by building a minimal, full-flow, disposable Proof of Concept piece that will test the critical portions. Put some pressure on it to see how it scales, so that if it fails, it does so early. And by the way: make sure everybody is aware that it’s disposable and will be built again correctly, right after disposal.

Keep asking yourself whether you have enough data and work to verify whether what you think you know is true. Learn and practice how to make decisions. If you avoid them, somebody else will step in and their decisions may not be to your liking.

API thinking vs. client thinking

Have an API? No? So obscure. Everybody has one these days as APIs were the foundation of online success in the last decade. But building a good API is hard. In fact, the mindset that’s required is peculiar enough to consider separating people who will build it from those who will use it.

APIs were all the rage that, along with AJAX, kicked off Web 2.0. By allowing others to tap into the features and data of your application, you could spark a whole community of clients and mash-ups, making you the platform. Twitter is a well known child of this era, where an API was built first, then Twitter’s own clients as well as all the independent ones on top of it.

APIs, APIs everywhere

This obviously takes away control of the application’s future from its creators, putting it into the hands of a broader community. Example being again Twitter, where features such as retweets were only added to the platform once they became widely used in independent clients. At some point Twitter decided to reclaim control of its brand and user experience, which started to diverge between applications. Certain requirements were imposed on how tweets may be displayed and what functions should be available. Break those and you may be kicked off the API completely.

For System Architects, APIs are the panacea in a multi-device world. With the variety of client applications being demanded – web, native, embedded, large-screen, tiny-screen etc. – we want to keep complexity low by reusing as much code as possible. A properly written API can be shared between all clients and even allow for gracefully dropping support for a legacy generation, like a browser that’s becoming obsolete.

Trello makes excellent use of this graceful degradation pattern:

[T]he website is just a face that chats with the Trello API and that the iOS and Android apps are also just faces and you can make your own face.
(…)
[T]here’s a special face out there for people using Internet Explorer 9.

There’s the API shared by all official and unofficial clients, each one called a “face”, and there’s a special, older version of the web face that’s left to support the remaining users of Internet Explorer 9. Brilliant.

  • Yes! I want to build an API. How do I go about it?
  • With foresight and planning.

APIs are a special case of Separation of Concerns and here’s where I’m starting to think that APIs and clients should be built by different people:

  • clients are focused on their immediate needs; I’m building feature X and need data A, B and C formatted this way.
  • APIs are catering for many clients and their different, often incompatible needs.

If the same person writes the client and the API, or even if they’re separate but on one, tightly knit team, they are much more likely to reconcile the conflict by leaning towards the immediate need of the client, away from the broader needs of the ecosystem. Every subsequent client that comes in with their needs will receive their own, special endpoints. Soon you’ll have an explosion of similar, oddly named methods for very specific use cases, little reusability, where a simple change may require modifications to hundreds of lines of code. In other words, you’ll have built a monolith where “API” will merely be a different name for the application’s model layer, and since that model will be separate from the rest of the application, complexity becomes even worse.

Then, once it’s in production, you’re dead in the water, because:

Public APIs are forever.

Joshua Bloch, How to Design a Good API

Anyone can use a public API and you’ll have to maintain backwards compatibility for a long, long time.

However, if you task different people with building APIs and clients, you’ll get a lot of conversations, often conflicts, which are essential for getting the best result for the broadest amount of use cases.

Make sure the API team consists of people who have as wide a perspective as possible. Keep thinking well beyond the immediate requests they receive, weighing those against all similar requests in the past and thinking forward into the future. What else could be required from this method later? What else might someone want to extract from this particular data set? Will it need filtering, sorting, paging?

Building a good API requires following guidelines, which are not the ones usually proposed for client design:

  • violate YAGNI – think of what might be useful in the future, but leave out things that are easy to add, because removing anything is much harder;
  • write a broader than usual set of features for the method, weighing the possible performance penalties against power;
  • displease everyone equally – clients will often times need to curb their requirements, to allow for broader reusability;
  • document extensively – your documentation will become a guide to understand the contract of each method – what it expects and returns. Without it, you’ll be swamped by questions and complaints.

Joshua Bloch, creator of, among others, the Java Collections API, shares a number of excellent recommendations for building APIs in a Tech Talk he gave years ago at Google. It’s well worth the hour to see it:

If the API is done right, it’s an investment that pays back many times the effort put into it. The multitude of clients that can use it, the flexibility to rapidly build features that weren’t previously thought of. For any regular software company it’s possibly the most complex task it will handle and you should put your best, brightest people on it. And make sure they spark conflicts with all the developers building clients, because that means they’re having real conversations about how to build the best solution for everyone.

Coding is cheating

Programming is perhaps the only job where lying, cheating and deceiving will not only get you paid but also praised for being innovative and creative. That’s because computers are severely limited. We’re literally fitting square pegs (real world) into round holes (0′s and 1′s).

Assuming you already know that everything in the computer world is represented in binary – combinations of 0′s and 1′s – consider the simplest example – trying to store the value 0.2:

0.2 decimal = 0.00110011... binary

There is no precise representation in binary for the decimal 0.2. Instead it’s a repeating pattern of 0011 after the mark. To make matters worse, a computer will only store a limited amount of digits for a number, say 32 for a fraction like the one above. But due to the specifics of number storage, the actual representation will only keep 26 digits from the recurring pattern of 00110011.... The rest will be cut and gone as if it never existed. So the number a computer will actually store is:

0.199999988079071044921875

Close enough to round it off to 0.2, but still, what a cheat!

We continue to work around constraints, this time of memory. All computer memory is limited and we shouldn’t waste it unnecessarily. So when we want to store a value in a program, we often won’t store the actual value, but a pointer instead:

value = "banana"
valuePointer = &value

The exact code will differ depending on the language used, but essentially it says:

  1. save the value banana under the name value, then
  2. assign to the name valuePointer the memory address of value (it points to where the original value is stored).

Pointer illustration

In consequence we’re using much less memory, because the banana is stored only once, but as a side effect (sometimes desired), if we change to value = "kiwi" later, then valuePointer will also suddenly return kiwi.

Let’s look at something more tangible – a sphere.

Sphere

You know how a sphere looks like, you can recognize one if you see it. But a computer is inherently incapable of producing a real sphere (though that’ll change once ray tracing goes mainstream, thanks Marek). For reasons that require a university course to explain, 3D spheres are drawn with… triangles.

Sphere

There’s just so many of them and so tiny that you are fooled and see a smooth surface. In the first 3D games that surfaced in the 90′s you could actually see the edgy surfaces. Nowadays computers have enough horsepower to draw millions of triangles without much sweat.

Another funny concept is lazy loading. We’re usually storing data in some kind of database, which makes it expensive to retrieve. There’s the time needed for a network call, the database engine reading files from disk etc. It all adds up, hence we want to make as few database calls as possible, so that users won’t have to constantly stare at a screen saying “loading”.

Let’s say you want to open up a contract. We’ll represent it in code as an object that includes all relevant information – ID, date of signing, ship-to and bill-to companies etc. We’ll also tell you it has line items, which we may conveniently program as:

getLineItems()

where calling the above function will return the list of line items. However… we don’t really have those line items ready to display, because we purposefully didn’t ask the database for them just yet. You might not need them at all – just want to check some basic details of the contract. So only the moment you ask for line items explicitly, and getLineItems() is called, do we make the query to the database (and let you wait for it), then return and display the list.

Finally, some problems in computing are very hard and extremely expensive to calculate at scale. Even for the modern beastly machines we have available. If you’re using any sort of map application, you’re seeing one such problem: calculating the best route between two points.

In order to perfectly calculate the best route – be that the shortest or the quickest one, whatever the criterion – the computer would have to have to calculate the distances and routes between every single point in the database. The number of calculations to perform would be the square of the number of points. Warsaw alone has thousands of addresses. Think how many points would there be on the route between, say, Warsaw and Berlin.

The trick we use in these hard cases is heuristics which boils down to using extra information we may have, and allowing for suboptimal results, providing the ones we deliver are good enough. For finding the best route on a map, we already know the locations (latitude and longitude) of all points. We can use that information to limit the area in which we’ll calculate the routes, often to a shape resembling an ellipse:

Shortest path calculation area

We won’t consider points and roads outside of this area at all. That’s why when trying to cross Warsaw North (say Marymont) to South (Ursynów), the GPS might offer you a straight line through the city center, while a quicker and more convenient route may lead along the city bypass. But the calculation is much faster.

It’s all cheating. Bending, stretching the material we are working with – computers – in order to deliver bigger, better and more vibrant experiences to users. We’re not sorry, not at all. It’s like solving elaborate puzzles every single day, while getting pay and praise for it. The joy of programming.

Respectfully rejected

“I’m sure somebody will get in touch with you”, sneered the Google developer, closing a phone interview I went through years ago. By then I knew I wouldn’t get the job, but these words and their tone convinced me that I shouldn’t try again for years to come. The way in which a company rejects job candidates speaks tomes about its culture.

Google was merely one of many similar experiences. I once called up a company to ask for my interview’s results, having received no answer. The lady I connected with looked up my application and replied, “oh, says here you know too little about the software development process”. Thanks for telling me.

Rejection happens to the best of us. History knows countless cases where individuals were sent away as unfit for a job, then built exceptional success elsewhere. Without much digging:

Peanuts: Nobody likes me

It’s tempting to think of a candidate who didn’t pass the interview as just not smart or talented enough. That’s almost always bollocks. It’s much more likely that the person you just met either

  1. didn’t work long enough with the domain you interviewed for; or
  2. doesn’t have the right profile – character or set of talents.

That means the same person might become a very good match later on, when he or she gains more experience (1), or a different position opens up, calling for their unique skills (2). Besides, in the rapidly shifting world of business, one day you could again be meeting that same person, and this time you’ll be the one answering questions.

Leaving candidates with a bad memory of the recruitment process is therefore ludicrous, and great companies, like Fog Creek Software, know it:

Recruiting is a series of delicate communications. It’s about managing a candidate’s experience and expectations throughout the interview process. It’s marketing and PR: everyone you talk to leaves with an impression of the company. A recruiter creates the company’s brand, and, if done right, leaves a candidate still wanting to work for you even after they’ve been rejected. [emphasis mine]

Liz Hall, Lights, Camera, Offer!, Fog Creek Software

It’s really very simple, though admittedly not easy. Every candidate should receive

  • honesty – a full evaluation of their interview, time permitting;
  • constructiveness – advice on how they may improve to become ready for the position they applied for; and
  • positivity – all of the above in a friendly, respective manner.

Such experiences provide answers to the often unsaid questions every promising candidate will have: Will I be given freedom to fail and the support to learn from it? How will I be told when I err and how I can correct my ways? Is this a place where I can grow?

Yours may a company that does all that for employees, but you have to make sure it shows just as vividly in your interviews, especially those where someone gets rejected.

People remember. Negative experiences remain in memory much sharper than positive ones, and every rejection by nature is negative already. Don’t make it worse. You want people to see your company as a great place that just may not have been fitting at the time:

Paper has a BIG future

I’m as paperless as it gets. Most of my documents are on Google Drive, I take notes on tablets, read only books available on Kindle and never ever print out emails (can we please drop those “consider the environment…” pledges?). I even mock my wife for leaving written task lists, instead of setting up some cards on our shared Trello board. I’m pretty much like that guy:

The benefits of my digital lifestyle are self-evident. Some of the selfish ones:

  • paper has no search engine,
  • paper documents are only available when I carry them with me,
  • most paper books are clunkier than a Kindle.

The list goes on.

I even endure correcting the insane amount of typos I make, when writing on a touchscreen, though I’m about to put an end to this by acquiring the Microsoft Wedge Mobile Keyboard.

When someone presents me with my favorite gift – a book, I’ll still acquire it for Kindle before reading.

However… I’m a big believer in good, old paper. Turns out it’s excellent for comprehension:

[E]ven when laptops are used solely to take notes, they may still be impairing learning because their use results in shallower processing. In three studies, we found that students who took notes on laptops performed worse on conceptual questions than students who took notes longhand. We show that whereas taking more notes can be beneficial, laptop note takers’ tendency to transcribe lectures verbatim rather than processing information and reframing it in their own words is detrimental to learning. [emphasis mine]

Pam A. Mueller, Daniel M. Oppenheimer, The Pen Is Mightier Than the Keyboard, Psychological Science 2014

That might explain why I had some of my best ideas when scribbling in my Moleskine. It’s free-form. I enhance text with drawings, annotations that would take way too much time to produce on any electronic device. Ask any “creative” person and there’s a good chance he or she uses Moleskines for these very reasons.

Moleskine

I will always print out my travel itineraries, boarding passes, despite having them on all mobile devices I carry. The paper is there when all tech fails, because by Murphy’s laws, batteries tend to die in the least convenient moments. Last thing I want is to be stranded on some airport because I can’t present my boarding pass.

Even in the realm of books, there’s hardly anything as smartly looking as a full bookshelf. Pay attention to the more serious interviews filmed in homes or offices. More often than not, the people talking will have books behind them because these create an aura of intelligence and wisdom. When educated people visit each others’ homes for the first time they’ll often walk over to the bookshelves to inspect them. You are what you read.

And while I love Trello for all the flexibility it adds to managing my work, there’s no way it can compete with a reminder Post-it note, placed on the exit door where I am guaranteed to see it before leaving in the morning, still half-asleep.

Finally, there are important processes that I think always must remain paper-based. Government elections are a prime example. The numerous examples of voting in the past conducted electronically or online come with a rich history of controversies and failures. Anybody who builds computer systems knows they’re never fail- or hack-proof. And government elections are far too important to accept any risk that somebody could abuse the technology.

I’m sure we’re yet about to see advances in technology, that will bridge the gap between paper and digital. Kindle already imitates the look and feel of paper to deliver a superb reading experience. Meanwhile, work is underway on highly interactive computers that will look like sheets of paper:

“The future is already here – it’s just not very evenly distributed.”

For now, going 100% paperless, while possible, would not only rob me of aesthetic pleasures and limit my creativity, but also increase the risk of getting into unpleasant situations in the least expected times. I’m happy to rely on paper for much of my work and will continue doing so.