What does it take to be a great software engineer?

I spent the better part of the twenty-teens working as a software developer/engineer. To be honest, I paid very little attention to intentional professional growth during most of that span. We were a relatively small company, and I lacked the confidence and experience to think ambitiously. Being a great software engineer can be satisfying and lucrative, but not if you approach your career like I did.

Now that I’m responsible for a team of software engineers, I find myself in conversations that revolve around what success looks like, and the qualities of a top performer. And while there’s no such thing as perfection when human beings are involved, I have noticed some commonalities among the people that I’ve seen achieve the most success in the world of building software.

1. They’re honest

Being part of a team or organization means you have to be trustworthy. Without honesty, it’s impossible to build the kind of trust required to collaborate on a project. A reputation for not being able to accurately estimate how much time it will take to fix a problem or build a feature is a good way to ensure you never get the opportunity to do the kind of work that progresses your career and puts you in a position for growth.

And being in the habit of taking credit for other people’s work is far more likely to stall your career than it is to move it forward. Believe me, everyone notices that kind of thing, and it’s never appreciated.

2. They are curious

If you got into coding because you wanted a good job, that’s cool. I get it. Nothing wrong with that.

But if you lack the curiosity to explore new technology, experiment and try new (or newly learned) techniques, to leverage what you know to see what’s possible, you’re probably going to hit a career ceiling eventually.

Building software is a creative work, but it’s unique in that it is creativity in service of solving problems. Great software engineers embrace this work … relish it, even.

3. They communicate well in all directions

This isn’t unique to teams that build software. Communication is important in almost every line of work.

But when trying to coordinate engineers, support folks, product managers, marketing, and leaders up the chain of command, all while juggling the work and looming deadlines, good communication is a skill that instantly makes you stand out from the rest.

When working remotely (and I’d argue this is true for co-located teams too), a well written email or technical document is much appreciated by people from every department. It’s efficient (write once, share many times), effective, and can mitigate many of the issues that in person interactions present … like body language, tone of voice, misinterpretation, and our tendency to forget what what said in a conversation.

Master this skill, and people WILL notice.

4. They aren’t driven by ego

No one likes the one who brags about themselves, or steals credit, or exaggerates their share of the work.

It’s a terrible strategy, and it’s not the kind of attention you actually want.

5. They are driven to help

The exact opposite of ego, great software engineers are always looking for opportunities to help.

To help their team/teammates push a project over the finish line.

To help someone write better code.

To mentor someone through a difficult transition.

To share subject matter knowledge.

If you look around, there are always opportunities to help.

6. They leverage process

Great engineers tend to value efficiency. Why waste time arguing about an approach to a problem, over and over again, when you can spend a little time up front developing a value system that can solve problems for you?

Things like OKRs, the Agile Manifesto, team agreements, and even company values … these are all tools that good engineers use to deescalate touchy situations.

Recommended Reading

Measure What Matters: How Google, Bono, and the Gates Foundation Rock the World with OKRs

“That task doesn’t really help us achieve our stated objective for the quarter.”

“We can iterate. Let’s push this out and follow up ASAP to improve the UI.”

“That sounds like a good idea, but maybe it’s not necessary. Let’s ship what we have now, and get some user feedback before committing to do it.”

At Facebook, there’s a saying “Data wins arguments”. In other words, 5 people arguing from the perspective of their own individual gut feeling isn’t particularly effective or scalable. Instead, let’s just look at the data and save some time.

7. They care about their teammates

Things like peer reviews and 360 feedback have made it more important than ever that you develop an empathetic (and sometimes apologetic) attitude toward the people you work with. They’re human beings with complicated lives, and at any given time they could be going through something that makes work problems seem trivial.

Feeling trusted and supported can mean the difference between a good and bad day/week/month/year.

And when Murphy’s Law eventually circles around to you, you’ll be glad to have a teammate that supports you the same way.

But it’s more than just supporting teammates when they’re struggling.

Think about how much more valuable you are as an engineer if, by your influence and impact on your teammates, they get better at their job.

Maybe it’s teaching them a new skill they lacked before.

Or a trick/shortcut that saves them 2 hours per week.

Or a confidence boost that unlocks a willingness to take on a task or responsibility they would have previously avoided.

It could even be volunteering to attend a meeting and write up a summary for your team, instead of everyone attending the meeting themselves.

Recommended Reading

The Five Dysfunctions of a Team: A Leadership Fable

8. They enjoy the work

As I said earlier, becoming an engineer so you can have a healthy paycheck is totally fine. We all have bills to pay.

But this list isn’t about being “an engineer”. It’s about being a great engineer. And if you don’t really enjoy the work, you’re probably going to struggle with mustering up the motivation to do what’s necessary to continue learning, experimenting, and building great software.

This doesn’t mean you won’t have other interests, hobbies, and priorities.

But the likelihood of compartmentalizing “work” into a strict 9 to 5 box, and consistently growing as an engineer, is relatively low.

9. They’re “lazy”

A former boss used to say this about me all the time. But I was never offended.

“Nathan is lazy, but in all the right ways.”

I was never going to do something manually that I could have a machine do.

I was never going to waste time building something that I didn’t think had value. Or at least, I would have pushed back hard on it.

Having the experience and judgement to know what not to do makes you way more valuable than someone who just jumps into projects without giving it any thought.

This can come across as “lazy” to some, but it’s a good kind of lazy.

10. They get stuff done

Look, at the end of the day, you’re just not going to get very far in your engineering career unless you find a way to get stuff done. It’s the core of your responsibilities, and it’s what you should prioritize first.

Your job is to use code to solve problems, so the more problems you solve (without creating new ones) in the same amount of time or with the same amount of effort, the better.

Great athletes challenge themselves though intentional practice, to run a little bit farther or faster, to improve their accuracy, to perfect their form or develop new techniques, all in the pursuit of greatness.

Are you, as a software engineer, challenging yourself to work a little faster or a little smarter, to be more helpful and empathetic, to squash your ego and commit to honesty?

If not, what’s stopping you now?

When is the last time you said “I’m sorry”?

In December of 2012, I officially became a parent. Thinking back on those first years of my daughter’s life (before our other kids), it’s amazing the things you remember and forget (until something reminds you).

Now that she’s a bit older, I see that one of the easy things to forget is what a handful she was as a baby and young toddler.

We learned a lot in those early years, not the least of which was the fact that love and discipline, plus consistency and patience can be a truly magical combination for helping children navigate their emotions while building a deep and lasting bond with them.

A picture of me and my daughters from 2018
My and my girls, 2018

But the ugly side of parenting is that you are forced to come face to face with your own worst flaws.

The mistakes I made as a parent are too many to count, but one thing my wife and I committed to early on was that if we made a mistake with our kids … overreacting, losing our temper, unfair punishments, misunderstanding, misapplication of blame, incorrect assumptions … we would verbally apologize to our children. We would kneel down, look them in the eye, and say the words “I’m sorry, that was wrong. I should not have done that.”

It’s such a humbling (humiliating?) thing to have to do. Me, the parent, apologizing to them, the kid … it feels strange. But it does get easier the more you do it.

Since making this a part of our family’s DNA, it’s amazing how often you notice the mental gymnastics some parents perform to avoid saying “I’m sorry” to their kids, and it’s a good reminder to me how important that small act, that simple phrase, really is.

Instruction + modeling = behavior forming

The best leaders I’ve experienced in my life were great at explaining what needed to be done, and also having the discipline and character to do it themselves.

One of Andy Grove’s 5 responsibilities as a leader in High Output Management is “being a role model”.

“Do as I say …” just doesn’t work.

If you’ve been given any leadership responsibilities, modeling the behavior you want to see from your team is absolutely essential.

Owning Our Mistakes

One quality of a healthy team is adopting a culture that encourages everyone to own their own mistakes.

Sometimes that’s missing a deadline, or shipping a bug to production, or forgetting to do something that you committed to do.

Sometimes it’s being accidentally (or purposefully) insulting, or taking something personally that you shouldn’t have, or snapping at one of your coworkers.

A team culture that allows for mistakes and encourages speedy apologies is a health metric that is at the top of my priority list as a leader.

Recommended Reading

Permission to Screw Up: How I Learned to Lead by Doing (Almost) Everything Wrong

But just wanting that kind of culture doesn’t guarantee it.

Telling your teams that’s what’s expected of them, coaching them to be generous with apologies and forgiveness, giving presentations or recommending books … none of that will be as effective as them seeing you, the leader, practicing what you preach.

Opportunity

So, back to the title of this post: when was the last time you said “I’m sorry”?

Guess what? You’re not perfect. You do make mistakes.

If, for some reason, you believe that the reason you haven’t apologized lately is because you’ve done nothing worth apologizing for, you have bigger problems.

If you aren’t apologizing, it’s not because there’s nothing to apologize for. You’re just so out of practice that you’re not letting things register as mistakes worth apologizing for.

Make it a practice to notice and write down every time you mess something up. Every mistake is an opportunity to learn what not to do, and to model what should be done after the mistake was made.

Own your mistakes as fast as possible, so you can mitigate and correct the damage done, improve your systems to prevent it from happening again, and try not to make the same mistake twice.

Mind how you respond to others’ mistakes

After enough time coaching your team to own their mistakes and say “I’m sorry” when they make them, and of course modeling this behavior yourself, you need to make sure you are reacting properly when people actually start to adopt the practice themselves.

Is your team safe to admit mistakes in front of you?

One of my favorite interview questions to use when chatting with potential hires is “tell me about the last time you made a mistake at work that you had to apologize for?”.

I like this better than “what’s your greatest weakness?”, because for one, it’s unexpected, and two, there’s little room to wriggle out of it with a clever answer. No “I care too much” or “I work too hard / too much” nonsense.

It sets the tone for the team they’d potentially be joining.

It’s OK to fail on this team. Expected, even.

No blame, no bravado.

We apologize, we own our mistakes, and we get better. And most importantly, having the humility to admit a mistake in front of me will never be something you have to be afraid of.

Don’t believe me? You will when you see me apologize as much or more than anyone else.

How to tackle big goals by narrowing your focus with two simple questions

I made some poor decisions in my 20s. Or rather, a series of poor decisions that seemed to stack and compound.

I took on tens of thousands of dollars of credit card, student loan, and tax debt.

I gained 70 pounds since graduating high school, because I ate way too much fast food and pretty much never exercised.

I binged entire series’ of television shows while pushing work off until the last minute.

I would stay up late into the night, and sleep away the mornings.

And because of all this, my wife and I “had to” put off starting a family until we could get our house in order.

Add to all that a sense of angst over current events and politics, my tendency to stress over the security of jobs, the financial crisis that lead to The Great Recession, and a barrage of 24 hour news cycles that can mentally fatigue even the most psychologically resilient among us.

If you’ve ever been in a situation like this (or even just a fraction of this), you probably know the feeling of wanting a change, but feeling like there’s just too much. How do you figure out what to focus on, and what to ignore?

I needed a formula

I’m a big fan of using decision formulas for quickly analyzing things. They’re somewhat subjective, and will need occasional tweaking. But at their core, they can be really useful.

Because I had so many things that I let go off the track, I needed a way of focusing my effort … a way of identifying things that need ignoring, and prioritizing things that need attention.

So I borrowed a lesson from Stoic philosophy, combined it with a question that I often ask other people when they ask for advice, and came up with something that I have found quite useful.

I also inadvertently mirrored part of Steven Covey’s “circle of concern / circle of influence” model, outlined in 7 Habits of Highly Effective People. Oops! He probably says it better. Oh, well!

Question 1: Is this something I can control?

The chief task in life is simply this: to identify and separate matters so that I can say clearly to myself which are externals not under my control, and which have to do with the choices I actually control.

Epictetus, Discourses

There are so many things in my life that I can’t change. I don’t control the weather, I will not live forever, and certain people will just never like me.

But there are a lot of things that I can change. I can plan my activities around the weather, I can make choices that will allow me to live a bit longer, and I can choose who I spend my time with.

Only focus on what you control

Was I in control of banks when they were giving loans to people who couldn’t afford them? Could I control the stock market?

Do I decide if a client chooses to move forward with a project? Or how much money they’re willing to pay? Or if they’ll pay me on time vs. ghosting me after I’ve delivered?

Probably not.

But do I decide what food I put in my body? Do I get to choose how I spend my money? Is it my choice whether or not I get some exercise today? Or stay up until 2:00 AM? Or sleep in until 10:00 AM?

It’s a hard truth to accept. No one did this to me.

It wasn’t the credit card company’s fault.

It wasn’t the restaurant’s fault.

It wasn’t Netflix’s fault.

It was my fault.

These were decisions that I had made, habits that I had formed.

And after letting myself be angry at what I had done, I saw the silver lining: if my actions caused the problem, I was obviously the one in control.

Question 2: How much do I care?

If I decided that it was something I could control, I then have to have a difficult, honest conversation with myself. And I really had to be brutal about it. No aspirational answers, just the raw unpolluted truth.

Do I care enough to do whatever it takes to accomplish this?

When people ask for advice about the usual subjects:

“I want my kids to behave better”

“I want to lose weight”

“I want to get my finances under control”

“I want a promotion at work”

“I want to find love”

“I want to spend more time with my family”.

… it’s possible that they want it, but not badly enough to do what it takes to achieve it. And you know what? That’s fine. It may not be the right time, or there may be more important things that should take priority. The point isn’t to feel guilty about your answer, but to be honest with yourself.

Acknowledging the potentially painful parts of a decision can help us honestly analyze our desire for change.

So, I asked myself …

To have any influence over politics, my best shot was to run for some sort of political office. Was I willing to do that?

Nope.

To fix my procrastination problem, I’d might need to give up my autonomy and get a regular job where I didn’t set my own hours. Was I willing to do that?

Again, no.

To fix my weight and health, I’d need to go on a diet and start exercising regularly. Was I willing to do that?

I tried, and failed, many times. Clearly I was not.

To fix my finances, I’d need to cut up the credit cards, sell a car, and go on a budget. Was I willing to do that?

Turns out, I was! What Now?

Focus!

If the answer is “no” to either of these questions, it’s no longer my focus. It’s a dead issue to me. I won’t be wasting a single minute of effort or thought on it until/unless I can answer “yes” to both questions.

And when the answer to both is “yes”, it’s time to prioritize and focus.

And I mean intense focus. Maximum effort, focus.

I was able to leverage the ability and the desire to change, and give myself permission to ignore the things that don’t pass the test.

And maybe after I’ve conquered one goal, I’d be able to revisit my list from before. Perhaps my answer to the 2 questions will change once I have a win to reference.

So, what happened?

It took me 2 years, but I did eventually pay off all my debt, save enough money to buy a house, and develop good money habits that continue to this day.

And then …

After revisiting my list, turns out I was willing to take a job with a little less autonomy and a little more structure. Great decision, exactly what I needed.

In late 2012, I took on my weight and health. In 6 months, I lost 50 pounds, and I’ve kept it off.

In 2018, I completely revised my sleep schedule. I now wake up between 4:30 and 5:30 AM every day, and I’m able to get more done by 10:00 AM than many people do all day, including my daily budget analysis, reading, writing, etc.

Each goal accomplished sequentially, one at a time, and only when I could honestly answer each of the questions above with a confident YES!

None of it happened because of super-human discipline. If white-knuckle effort was the key to progress, I’d be hopelessly lost.

Luckily for me, it’s about eliminating the unimportant goals to make room for the ones that really matter, then letting the power of focus and compounding take over.

Autonomy, failure, and “pushing down”; what I’m learning about leadership

That title is a lot to digest, but as part of my (ongoing and never ending) journey to master effective leadership, it would be irresponsible not to cover the topic of autonomy.

Human beings have an innate inner drive to be autonomous, self-determined, and connected to one another. And when that drive is liberated, people achieve more and live richer lives.

Daniel Pink, Drive

I’m still very much learning about the less obvious things good leaders do, and how to integrate those things into my own approach and management philosophy.

But here is one of those obvious things that didn’t take very long to learn: few things you in a leadership position will be more patronizing, more insulting, more humiliating than micromanagement.

Nothing says “I don’t trust you” quite as effectively as looking over someone’s shoulder (physically, or virtually) while they’re working on something.

But is it a necessary evil?

Trust and Patience

Imagine being truly great at a sport. Top of your game, physically able to achieve success, game after game.

Then slowly, as you age, you begin losing the power to impose your will with a ball. No longer able to run faster or jump higher, you’re forced to move on from playing professionally. At best, it’s now a hobby.

But then you get a call. A team wants to hire you to be a coach, to help pass on your knowledge and experience to the next generation of able bodied professionals, and hopefully achieve the same level of success in coaching as you did as a player.

Unfortunately, the reality is that very few great players ever become great coaches.

Why is that?

I can’t imagine how difficult it must be to know that in the not-so-distant past, you were so instinctively great at something, having the talent to make split-second decisions with a ball in your hand, seeing what needs to be done and having the ability to execute in real time, suddenly expected to watch from the sidelines, as a coach, during pivotal moments of the game.

To execute as a player takes talent and practice.

To execute as a coach takes trust and patience.

These are skills that you just don’t naturally develop as a player, but they’re essential as a coach.

Trust: to know that when your players leave the huddle, that they remember what you said, that they have the physical ability to make it happen, that they believe you can see what they can’t and will draw up a plan that puts them in a position to win. Oh, and they won’t allow momentary hubris to take over when it comes time to execute the plan.

Patience: to have a vision for what should be. To understand that no one wins 100% of the time. Having the discipline to see failure coming, letting it happen (when appropriate), coaching through the difficulties, and pushing your team to improve iteratively.

The best time to fail

I’ll admit that I have very little tolerance for my own failure. I figure if I think long enough about all the ways something can go wrong, I can mitigate them all. If I just ask enough questions, or do the most research, or have contingency plans for every scenario, nothing could possibly go wrong.

Not only is this an unreasonably heavy burden for a single person, it doesn’t even work!

Recommended Reading

Permission to Screw Up: How I Learned to Lead by Doing (Almost) Everything Wrong

Failure is inevitable.

So when is it appropriate to let your team fail?

How do we optimize our failure for growth?

Fail when the stakes are low.

If you play sports, it’s better to fail in practice, scrimmages, pre-season, and the regular season, than it is to fail in the last seconds of the championship game.

If you’re a carpenter, it’s better to fail when building a birdhouse than it is to fail building an actual house.

You don’t run a marathon without training.

You don’t attempt to free solo El Capitan without first trying it with all the necessary safety gear.

Failure is the best teacher

I still remember the single question I got wrong on my written driver’s test when I was 15 years old. I’ll never forget it. I have no idea what questions I got right, but the one question I missed is forever carved on the inside of my skull.

Better I get it wrong at a desk at the DMV than behind the wheel, right?

And that’s the point. I missed it in the safety of a classroom. The stakes were low. If I failed the test, I’d go back home, study some more, wait a couple of weeks, and try again.

If I missed it on the road, I could end up in the hospital (or worse).

“Pushing down”

My friend Katie (who doesn’t blog) asked a great question in a recent meeting we were in.

“Is it possible to push any of these decisions one level down?”

Katie Childress

She wasn’t suggesting we push every decision all the way down. We can’t ignore the reality that not everyone in every position has all the context needed to make the right call.

Her point was that we sometimes forget to even consider if it’s possible to allow a decision (case by case) to be made by your team, rather than you, or your boss, etc.

Are we asking the right questions? What are the risks? If they fail, if they get it wrong, what’s the worst that could happen?

It’s a lot easier to “push down” a decision when the stakes are low. If they fail, so what? We learn a lesson, we course correct, and we try again. Repeat.

As repeated failure teaches us what not to do, success becomes a more and more likely outcome.

This is how your team earns trust, and learns to trust themselves, for higher stakes situations.

This is how your team can fail productively.

Which brings us back to autonomy

Throwing your team into a high stakes situation, with no experience, and expecting them to know what to do, how and when to do it, and thinking they’ll succeed (under the guise of “autonomy”) could be devastating to both your business and to the team’s confidence.

Being a good coach is about preparing and equipping your team, in low stakes situations, to have the confidence and competence to succeed in the critical moments of their work.

Don’t waste the low stakes moments.

Put ego and fear aside.

Let them try, and sometimes fail.

Then watch with pride as they pop open the Champaign bottle, hoist the trophy, and celebrate a hard earned victory.

Starting over.

I grew up relatively “poor”, at least by US standards. We went without a lot of things that my friends had. We wore thrift store clothes mixed and matched with the occasional new item (if it was on clearance), and ate a lot of potato soup … that is, diced potatoes + milk + chicken broth.

But because my mother was able to get a job teaching pre-K at a private school in our area, my siblings and I were able to attend tuition-free.

It was a relatively small school, I think between 400-500 students at the time (K-12), and so they didn’t split students into kindergarten (K3-K5), elementary (1st-5th), middle (6th-8th), and high school (9th-12th), like many schools in the US.

Instead, 7th through 12th grade was all just considered “high school”.

I remember being in 6th grade, basically the top of the elementary school food chain. We were the oldest kids in the elementary building, and although you wouldn’t think it would, it kind of went to our heads. We felt important.

Then came 7th grade, and our world shifted completely.

We were bigger than we were in 6th grade. We had lockers, and instead of just one teacher, we had one for each subject. There were free periods, and study halls. We had P.E. instead of recess. Everything about our schedule was different, more mature.

And yet we felt smaller, less important.

We now shared a hallway students up to grade 12. We were the smallest kids, the least “important”. No one looked up to us any more, and as a matter of fact, we were a little bit annoying, as we’d find out later when we watched new batches of 7th graders join the hallway.

We were “promoted” to high school, but it felt like starting over, at the bottom.

Nothing lasts forever

Since the mid-2000s, I’ve been building websites and software for WordPress. In 2010, we released the Genesis Framework at StudioPress, and experienced almost immediate success and market leadership.

But in 2018, StudioPress was acquired by WP Engine, and I came over as an engineer to keep working on Genesis products, as did several of the folks I worked with at StudioPress.

And at some point, during our regular conversations about my career and aspirations, my manager and I discussed the potential of moving me into a different kind of role, managing a team of engineers that work on Genesis products.

Would this actually be the right move for me? For my family? For the Genesis products that I’d worked so hard on over the years?

Decisions, Decisions

I’ve only recently realized what I wouldn’t admit to myself back then: I wasn’t enjoying writing code to build software very much lately. I saw my colleagues excitedly share what they had been playing around with over the weekend, all the cool things they were able to create, and just how much they were enjoying the process of learning and experimenting with new things.

That used to be me. I’d lose track of the time, and spend half the night wiring up some crazy idea, or blogging about a new way to enqueue CSS in WordPress, just for fun.

Not so much lately, though.

I realize now that I was losing my passion for writing the code.

But I also realize that I was gaining a passion for something new. I was spending more and more of my free time reading and watching talks on quality teams, effective leadership, and strong communication.

So when the opportunity to move in a managerial role came available, I decided the time was right.

I know nothing

It is impossible for a man to learn what he thinks he already knows.

Epictetus, Discourses, Book II, ch. 17

Picture this: it’s week two of my new career. As I had been doing for a while, I was up early, trying to get a jumpstart on my day before the rest of the team was up and working. I like the head start. It gives me breathing room, and most importantly, it gives me the opportunity to plan my day, sometimes down to the minute.

But as I sat there, before the sun was up, I realized that I had nothing to plan. I’d run out of “things to do”.

I had no one-on-one meetings scheduled for that day. I only had a single 30 minute team standup meeting on the schedule, but I was just an observer now.

Honestly, I kind of panicked. It felt wrong. I was “promoted” to do nothing? My schedule was empty!

To be fair, I was told (several times, from several people) that this would happen. The maker vs. manager schedule transition is tough.

So I went for a walk to clear my head. I just happened to have some audiobooks in the queue, so I figured I’d listen while I walked (a recent habit that I find incredibly efficient and effective). It also just so happened that High Output Management by Andy Grove was next in my queue.

That book really helped me begin to feel better. Why? That’s another blog post for another day.

But now I know that I really know nothing. And knowing I know nothing means I have to re-learn everything.

And that’s OK. Better than OK.

Passion is Passion

I’m currently up on a Sunday morning before the sun, reading about how to be a more effective leader and better career coach, writing this blog post about my recent transition into leadership, hoping that it helps someone realize they might have it in them to take their next right step too.

I’ve discovered a new passion, and while it may not be marathon coding sessions experimenting with the newest tech the world of JavaScript, it’s still a passion.

Different can be good.

It has been for me.

WordPress 5.0 and Gutenberg: A better way to handle CSS overload

As you may know, WordPress 5.0 introduced a new editor experience (for those that haven’t decided to explicitly disable it), and the response has been mostly “ok, cool.” from users, despite the controversial release schedule, and the decision to punt many accessibility and performance issues to subsequent patch releases.

And while I won’t try to overcompensate for the problems that have been pointed out, I will say that I mostly like the new editor experience, both from the perspective of a user (I’m writing this post in Gutenberg) and a developer.

And as a developer, I can’t help but notice that there is a pretty predictable problem staring down its nose at us.

The problem is front-end performance, and to be honest, it’s not really Gutenberg’s fault.

Some background

Gutenberg is a “block based” editor. Every piece of content in your post/entry is a block. Paragraphs, images, headings … all the normal stuff you’d put into entry content is a block.

And this opens up a world of opportunity for users to activate, as needed, new types of blocks.

Need a contact form on your contact page? There’s a block for that.

Need an image gallery? There’s a block for that.

Need a bunch of useful blocks in a single plugin? There’s a block library for that.

Now, in order to meet your needs in creating the kind of content you want, you may end up with several block plugins installed at once, in addition to the plugins you’re already using. Ignoring, for now, the risks of simply having too many plugins active, I want to focus on the bigger problem.

But first …

Waterfalls

When testing the performance of a website as it would appear to a user, developers do something called a waterfall analysis.

It’s basically a chart of every resource your site requires in order to load fully, and the time it took for each of those resources to download.

It’s a really good visual representation of page weight.

Waterfall for WordPress.org

I won’t explain waterfalls in too much detail; there are much better articles for that than this one. But to give a brief summary, each resource download your page uses is represented by a row. Each row has a colored line (far right) that indicates when the asset started downloading, and how long it took. Obviously, bigger files from slower servers are going to take longer, whereas small files from fast servers (like CDNs) will take less time.

In addition to helping you locate assets that are loading slowly (due to size or server speed), the waterfall shows you another useful metric: what resources are blocking other resources from downloading, and ultimately, blocking the page from rendering.

Although there are a few types of render blocking resources, for the purposes of this article, we’re going to focus on the most relevant one, stylesheets (CSS).

Render blocking stylesheets

Because there is currently no way to prevent stylesheets from blocking the render of a page (and for good reason, FOUC is no fun), we’ve basically just had to accept that our stylesheets were going to halt the render of our page until they’ve all downloaded.

Essentially, until all of the CSS is downloaded, nothing on the page will render.

So we invented little tricks to help minimize this issue, like minifying our CSS, combining all the CSS into a single stylesheet (where possible), and relying heavily on browser caching.

And when you have total control over your site, these aren’t terrible options.

But an extensible CMS will complicate things. Your theme loads some CSS, plugins load CSS, WordPress core load some CSS.

It’s not at all surprising to see a WordPress site loading 10+ stylesheets, and that’s just going to get worse with Gutenberg blocks needing their own CSS to render properly on the front end.

What’s worse, these stylesheets are being loaded regardless of whether they’re needed. If a page isn’t using a particular block, the block plugin will still likely load the CSS for that block.

But even if the block plugin were aware that the page was using the block, and only loaded the CSS when the block was being used on a page, we still have a problem! When you register and enqueue a stylesheet in WordPress (the Right Way), it will output to the <head>, as it is designed to do.

The problem is, now a stylesheet designed for a block that is used at the bottom of a blog post is blocking the render of the site header, or menu, or post title, etc.

Why should a block placed well below the fold affect the rendering of the site header?

Let’s Modularize

Conventional wisdom tells us that we need to serve as few CSS files as possible. Every HTTP request includes some network latency, and therefore reducing requests means less time until all our CSS is downloaded and the page is ready to render.

After all, if every CSS file is loaded in the <head>, and blocks the render of the entire page, then why wouldn’t you just combine all your CSS into a single file, a single HTTP request?

Note: although you could make the argument that modularizing your CSS files provides a more efficient cache busting opportunity, and HTTP2 allows for asynchronous CSS downloads, latency is still an issue so it’s still best for performance to combine CSS in production.

But, a couple of months ago, Jason Cohen shared and interesting link to the engineers at WP Engine. An excerpt:

due to a recent change in Chrome (version 69, I believe), and behaviour already present in Firefox and IE/Edge, <link rel="stylesheet" />s will only block the rendering of subsequent content, rather than the whole page.

CSS Wizardry

If all the stylesheets are linked in the <head>, this new information doesn’t really change much. It’s still blocking everything after the link … every visual element on your site.

But what if we split CSS into multiple files, each corresponding to a piece of content that needed styling. And instead of linking them all in the <head>, these CSS files would only be linked directly before the content they were designed to style was present.

It still blocks rendering, just like the traditional method, but because we’re linking the CSS file in the <body> right before the content it’s designed to style, we don’t block rendering of content before that point in the source code.

The practical upshot of this is that we’re now able to progressively render our pages, effectively drip-feeding styles to the page as they become available.

CSS Wizardry

Put another way, we’re drip feeding styles to the page as needed.

It also has the added benefit of strategically blocking the rendering of any content which doesn’t have corresponding CSS dowloaded yet. No FOUC.

Time to first render

So why is this a big deal? Because page speed (the actual time it takes for your full site to load) and perceived page speed (the time it takes for a user to think your site has loaded) are very different things.

And it turns out, users don’t care that much about how long your site actually takes to load. They’re not watching the waterfall, they’re watching the screen.

Anything we can do to reduce the time a user has to wait until they first start to see things loading on our page is a win for visitor retention. Users don’t see the footer when the page first loads. And with more and more traffic coming from mobile, there’s even less that is actually seen when a page is first accessed.

This presents a big opportunity! We can decrease the time to first render, and delay the rendering of elements further down the screen until after their related CSS has been loaded.

So, Blocks?

Admittedly, this is hard. WordPress is very specific about the way it wants you to load your CSS files.

Currently, you have the option to register a stylesheet with one function, and another function enqueues it (it also will do the job of registration, but you should really register and enqueue separately).

When you enqueue styles this way, every stylesheet link gets output to the <head>. Each stylesheet is registered with a unique handle, so the same stylesheet link doesn’t get linked more than once.

I’m not suggesting that we start linking our own stylesheets outside the WordPress way. But something does have to change.

What if you could register stylesheets the same way, but instead of enqueueing them to be output in the <head>, you could call a function manually that would output the stylesheet link (with any dependencies) immediately before a block. Once a link is rendered, the WordPress stylesheet manager could make sure it doesn’t get rendered again.

As it turns out, you can!

Here’s a quick proof of concept (and a gist). It’s using the CTA block from Atomic Blocks as the example, but obviously production code would look a bit different.

// this snippet requires PHP 5.3+
add_action( 'wp_enqueue_scripts', function() {
	wp_register_style( 'atomic-blocks/ab-cta', '/path/to/atomic-blocks/css/ab-cta.css', array(), '1.0.0' );
} );

add_filter( 'render_block', function( $block_content, $block ) {
	if ( 'atomic-blocks/ab-cta' === $block['blockName'] ) {
		ob_start();
		wp_print_styles( $block['blockName'] );
		$block_content = ob_get_clean() . $block_content;
	}

	return $block_content;
}, 10, 2 );

You essentially register the modular CSS as you normally would. Then, leveraging the render_block filter, you can output a stylesheet link “just in time”, so that the content gets CSS to style it before it gets rendered, but the CSS doesn’t block the rendering of anything before it in the source.

This is legitimately amazing. By using wp_register_style() and wp_print_styles(), we are working within the existing WordPress stylesheet loader, and we get all the benefits of doing so. But by not enqueueing the styles, and instead printing them directly where we want them, we can output the stylesheet links right before the block they style, and only if the block is actually used. Yes, we have to use output buffering, but that’s sometimes unavoidable, and in this case, it’s worth it.

Themes?

This method isn’t limited to blocks. Entire themes could be built this way. Instead of a master stylesheet that styles everything, use separate stylesheets for each section of your site and output the stylesheet link right before the section it styles.

Has it ever bothered you that WordPress themes load CSS for the comments section on pages with comments disabled, or on archives, or on the homepage? Yeah, me too.

By only linking a stylesheet when it’s needed, you only load CSS for sections that actually exist on the page. This can significantly decrease total page weight, in addition to the decreased time to first render mentioned before.

Plugins

Plugins have the exact same opportunity that themes and blocks do.

It’s really not complicated. Simply register your stylesheet as you normally would, then use wp_print_styles() to output the CSS as part of any rendering functionality your plugin uses. If your plugin provides a widget, then make sure the widget styles get output when the widget renders … don’t enqueue the stylesheet like you used to!

Gotchas

So what’s the catch?

Currently this method works in all major browsers except Safari. It doesn’t break or anything, it just treats each linked stylesheet as if it were in the <head>. That is, each linked stylesheet is render blocking for the entire page.

So basically, in Safari, we end up with the same outcome we’d have if we didn’t implement this method at all.

Sure, by using this method, you might sacrifice some performance in Safari (until they fix things) by not concatenating all your CSS into a single file, but by having a stylesheet for each major section or content type, and only linking it when that section or content type is actually in use, you also gain some performance by reducing your total page weight.

One possible issue is that on pages where we’re not actually reducing total page weight – a page that uses a lot of sections, blocks, etc. – we might technically be increasing the total pageload time by modularizing our stylesheet loading method. It’s possible that search engines like Google, who prioritize speed, might penalize you for choosing time to first render over time to full render. But in my opinion, this is unlikely.

Am I wrong?

the best way to get the right answer on the internet is not to ask a question; it’s to post the wrong answer.

Ward Cunningham, Cunningham’s Law

So, what did I miss? I want to kick off a discussion of this problem, the proposed solution, and also kick around other ideas.

I’d also love to see actual metrics for this method. I haven’t been able to do a lot of testing, so this post is pretty theoretical when it comes to the performance benefits I’m predicting.

If you want to discuss this on Twitter, you can find me at @nathanrice