On independence and non-attachment

From Awareness by Anthony de Mello

What I really enjoy is not you; it’s something that’s greater than both you and me. It is something that I discovered, a kind of symphony, a kind of orchestra that plays one melody in your presence, but when you depart, the orchestra doesn’t stop. When I meet someone else, it plays another melody, which is also very delightful. And when I’m alone, it continues to play. There’s a great repertoire and it never ceases to play.

Support roles need slack (not the chat software :)

People in support roles (QAs, architects, product owners, front-line managers, and others) need slack in time and attention so they can be available to those they support when they’re needed. As you can imagine, this means people in support roles can sometimes catch a lot of shit for not being “busy enough”.

But if they’re fully tasked (i.e. can do literally nothing else), they can’t do their actual job, which is to be available when others need them.

Support roles need slack. It’s our job to be sure they can do their job.

Code is not art

Note: I wrote this when my primary job was writing code. It still reflects my view, more or less, but is intended to belittle neither code nor those who create it. To me, code is no more or less valuable whether you do or do not view it as “art”.

I have often heard software engineers say that code is art. That feels good to hear, I admit.

We like art. Making art is a creative process with infinite choices and nearly as many media in which to make it.

But code is not art.


Code is made to run.

We don’t write code to be admired for its beauty alone. Without an execution context, code is inert. The beauty is in the running.

And in the running, code is designed to help achieve desired quality attributes in a system. “Fast”. “Available”. “Secure”. “Testable”.

Code is not art.


Code achieves the desired quality attributes in a system somewhat, completely, or not at all. This is measurable and measured. Otherwise, an objective measure does not exist, only its potential.

Code can be and often is objectively, measurably bad.

Code is not art.


Code is never “ahead of its time”.

There’s no code that I like because it reminds me of the crisp fall air in Tennessee and that my mom dislikes because it’s “not blue enough”.

Code is not art.


We don’t agree to disagree about code at runtime. Code at rest, maybe, but not once it’s running. Code either does what it’s designed to do or it doesn’t, measurably. Even if it does do what it’s designed to do, it can often do it better, measurably.

Oh, did I say we can agree to disagree about code at rest? Static code analysis would like a word, when you have a moment.

Code is not art.


We can agree to disagree about style then. Is that ok?

No, probably not. Code is designed to be read by humans and communicates to that audience. Function, variable, and class names can be and often are objectively, measurably bad.

Software engineering has a lexicon. A queue is not a “bucket”. We don’t “change” records in a database. We update them.

Code is not art.


I have often heard software engineers say that code is art. That feels good to hear, I admit.

But code is not art.

The Opinionated Software Engineer

Note: I wrote this when my primary job was writing software. It still reflects my views, more or less.

Here at VU, we aim to hire opinionated software engineers.

This is not the Dark Side of being “opinionated” as you may expect. No, this is the Light Side and is about using your opinions for good.

Rather than spend time providing more context, I’m appealing to the engineer in me by jumping right into the details.

The opinionated software engineer…


…has a strong opinion about their tools

A software engineer who is indifferent to their tools is a bad software engineer.

As a software engineer, your tools consist of the languages, frameworks, services, hardware and software you use to do your job.

You have to care about your tools. It’s not optional.

If you don’t care, why not?

Do you not understand your tools well enough to have a strong opinion about them? Fix that by learning. Where do your tools excel? Where do they suck? What tools are they competing with and what’s it like to build software in them?

If you deeply understand the tools you use, then what else is keeping you from caring?

Do you not feel enough ownership of the code you and your team write to have a strong opinion about your tools? Fix that by getting clear on what drives you, owning your authority, and committing to yourself, your team, and the company (or client).

And if you have a strong negative opinion about the languages, frameworks and software you use, fight to get them changed. If that doesn’t work, find another job that uses the languages, frameworks, and software you love.

Life is too short to wield a hammer all day that’s as likely to drive the nail as it is to knock out your front teeth (metaphorically speaking).

With that out of the way, the opinionated software engineer…


…cares about their team

A software engineer who is indifferent to their team is not a software engineer you want on your team.

As a software engineer, your team consists of your fellow devs, your team lead, your QAs, and your product owners.

You depend on these people and they depend on you, so caring about your team is also not optional.

You must care about the quality of your team. It’s your job to help your team improve by learning, by teaching, and by acting as a defender of the quality of your team.

How do we defend our team’s quality here at VU? For one, we have a rigorous hiring process including interviews with leadership and team members as well as a live, extensive coding evaluation.

We actively work to improve this process to ensure that only the smartest, nicest, and most capable make it onto our teams.

Finally, a great opinionated software engineer…


…is open to being wrong

A software engineer who is unwilling to be wrong is a bad software engineer.

A software design shown to be flawed is a gift. It allows us to reevaluate and grow, as long as we can remove our ego and avoid taking it personally.

And we must never take anything personally. A design review is about the design. No one is there for your ego. Your team is there to produce quality software and, so, you must be.

What other qualities does an opinionated software engineer possess?

 

How to Hire Good Devs – Interview Pairing with TDD and OO

I love interview pairing.

In 10+ years of interviewing developer candidates, it’s the most reliable technique I’ve found for hiring the good ones. Without it, you’re just guessing. And if you’ve ever hired a bad dev, you know that guessing is incredibly expensive, both financially and in team morale.

Here, I’ve enumerated The Principles, The Pattern, and The Process behind a simple guarantee: you absolutely can hire good devs every single time.

The Principles

So what makes a good developer? This part is debatable, but here are principles that I require of any developer I sign off on:

  • Good developers write responsible code that doesn’t do more or less than is necessary. It’s simple and self-documenting where possible.
  • Good developers speak the language of software development. They can speak intelligently on encapsulation and coupling and scope and so on.
  • Good developers understand abstraction and object design. Not every system design requires object-orientation but the majority will benefit from it.
  • Good developers can work with others. They are opinionated (as any good engineer should be) but they are open to suggestions and alternative solutions.
  • Good developers can describe their problem-solving process. They can tell you why we need a property and how we might make a function recursive and so on.
  • Good developers can debug their code. They know how to read a stack trace and how to take small, effective steps to uncover the source of the bug.
  • Good developers recognize opportunities for refactoring. They know refactoring patterns and use them appropriately.

These are non-negotiables for me and for our software team.

Interview pairing reveals principles in a candidate that are impossible to reveal in a non-programming interview.

The Pattern

For 60-90 minutes, we write code with the candidate, working on a system with increasingly challenging requirements.

Before doing any design, we review a narrative together that describes the system we’ll be building. This can be a toy problem or you can use a harness that mimics actual requirements you might have for your production domain. That’s up to you.

Before writing any code, we do up-front design together. We brainstorm objects and identify what we think their private members and public interfaces might look like. Whenever possible, we do this on a physical whiteboard and we use an established architecture diagramming technique such as hybrid UML. We talk about design trade-offs and note any concerns.

Then we write code. We ping-pong pair in one direction. This means the interviewer writes the tests (we’re TDDing remember) and the candidate passes the tests. This provides a clear delineation of responsibility and clear expectations of the candidate’s role.

We use an established unit testing framework. For C#, this is MSTest or NUnit. For JavaScript, we use Mocha. For PHP, we can use PHPUnit. And so on.

We test-drive using “red, green, refactor”. We start with a failing test. The candidate writes code to pass the test. Then we present the candidate an opportunity to refactor. Then we write our next failing test. And so on.

We write code using the tools that will be used on the job in an environment as close as possible to actual work conditions.

With that pattern in mind, let’s go step-by-step…

The Process

Here’s the basic script I use.

First, start with the introductions and ground rules.

“Hi, candidate. I’m Mark. Any experience with TDD or unit testing? How about object-oriented design? Ok, cool. Today, we’ll be building some software together. First, we’ll do some up-front design. Then, we’ll test drive our code. I’ll write the tests and you’ll pass them.”

Important points:

    “We’re not testing your ability to recall syntax. If you can describe what you’re trying to do, I’ll give you the syntax to do it.”
    “This isn’t a race and we won’t get all the way through the exercise. That’s ok.”
    “You’re allowed to use Google or you can just ask me. We have resources available in the real world, so why restrict them here?”
    “The up-front design is just a starting point. We can change it at any time as long as you can explain why.”
    “I’m your product owner for this exercise. If any of the requirements are unclear, just ask and I’ll clarify.”

Next, we look at the problem we’re trying to solve.

Ideally, we want a scenario that scales from easy to difficult with ample opportunities for refactoring.

Here’s an example:

Our client, an online retailer, wants to begin selling movies.

Since they have an existing system, they want us to build a new service for handling movie pricing and totals.

Our client’s web site should be able to call our service each time a movie is added to a customer’s cart. When they’re done adding movies, they should be able to get a total from our service.

To start, they’ll only sell Star Wars movies. To encourage sales, they want to discount purchases of multiple movies in the series but only if the movies are different Star Wars episodes.


Here’s what they’ve told us about the pricing and discounts:

One copy of any of the 6 Star Wars movies costs $10.

If you buy two different Star Wars movies, you get a 5% discount on those two movies. Purchasing A New Hope and The Empire Strikes Back, for example, would cost $19.

If you buy 3 different Star Wars movies, you get a 10% discount. So buying one copy of each of the prequels, for example, would total $27.

If you buy 4 different Star Wars movies, you get a 20% discount.

If you buy all 6 Star Wars movies, you get a 40% discount.

Note that if you buy four Star Wars movies, of which 3 are different episodes, you get a 10% discount on the 3 distinct movies, but the fourth movie (the duplicate) still costs $10. See below.


Example Order

1 copy of Star Wars Episode IV: A New Hope
2 copies of Star Wars Episode V: The Empire Strikes Back
1 copy of Star Wars Episode VI: Return of the Jedi

In this case, A New Hope, Return of the Jedi, and one copy of The Empire Strikes Back should be discounted 10%. The second copy of The Empire Strikes Back is full price because we only want to discount purchases of different movies in the Star Wars series.

So the total for this group of movies is $27 + $10 or $37.

Bonus: We should always give the largest discount possible.

What makes this a good problem?

Notice that it starts off very simply with data structure and collection operations. But once those are solved, we get into some interesting grouping and comparison algorithms with plenty of margin for creative approaches.

This is important: starting simply lets the candidate settle into the process and allows us to get comfortable working together.

But we also want an open-ended problem that can’t easily be solved. Many toy problems are just not deep enough to expose flaws in design and technique. So, sorry all, but FizzBuzz is out.

Now we design.

Again, we use a physical whiteboard if at all possible. I like relaxed UML, so I usually do something like the following:

movies_uml

Notice that our Movie implements an interface called Item. This is one of many examples of a practice I’d try to coax out of a candidate. I’ll typically talk through some scenario in which we have access to our client’s existing code base and that it contains something we can either reuse or extend. It’s the candidate’s job to identify what that something is.

For this particular exercise, we’d probably have UML for handling discounts, but we might just as easily defer it until some design emerges during TDD. It depends on the candidate and doesn’t actually matter all that much.

What does matter is that they can design simple objects and understand their dependencies.

Finally, we code.

Almost… I just want to note that everything we’ve done to this point is also part of being a good developer. It’s not just writing code.

For a first test, I think I’d want to know that we have a service and that it correctly returned a total of $0 when we haven’t added any movies. Assuming we’re using C# and NUnit, I might write a first test that looks like this:

// MovieServiceTest.cs

[Test]
public void CalculateTotal_GivenZeroMovies_ShouldReturn0()
{
    MovieService movieService = new MovieService();
    Assert.AreEqual(0m, movieService.CalculateTotal();
}

The candidate would pass this test by creating the MovieService class (if it doesn’t already exist – sometimes I give them the first class for free) and adding a CalculateTotal() method to it. Sort of like this:

// MovieService.cs

public decimal CalculateTotal()
{
    return 0m;
}

Maybe our second test looks like this:

// MovieServiceTest.cs

[Test]
public void CalculateTotal_GivenOneMovie_ShouldReturn8()
{
    MovieService movieService = new MovieService();

    movieService.Add(new Movie());

    Assert.AreEqual(8m, movieService.CalculateTotal();
}

Which the candidate could pass by creating a Movie class and modifying the MovieService class like so:

// MovieService.cs

List<Movie> movies = new List<Movie>();
public decimal CalculateTotal()
{
    return movies.Count * 8;
}

public void Add(Movie movie)
{
   movies.Add(movie);
}

And then we TDD the system until our time is up.

There are obviously many ways to approach these. Any developer who’s done TDD knows that every practitioner does it differently, but that’s a topic for another essay.

Where Do We Go Now?

There are many details and examples I can give, but hopefully this is enough to get you started.

There is no substitute for knowing with certainty that the developer you’re about to hire is actually worth hiring.

Good luck!

Builder of Digital Things