Being an effective enginner

Introduction

I have a goal to become better at what I do through personal development. This book brings me a step closer to achieving this through it’s heavy focus on leverage.Leverage, as defined by the Edmond Lau, is the lens through which effective engineers view their activities. The author highlights the areas an engineer can work on to achieve high productivity. In this blog post I’ll share the highlights and learnings made while reading and hope this helps you as it helps me have a deeper understanding.

1. Focus on High-Leverage Activities

Leverage is defined by the author as the amount of value that I produce per unit time. It seeks to provide answers individual questions such as: “How can I complete this activity in a shorter amount of time?”, “How can I increase the value produced by this activity?”, “Is there something else that I could spend my time on that would produce more value?”. An individual’s total output is the sum of the output of individual activities. When I successfully shorten the time required for an activity, increase its impact, or shift to a higher-leverage activity, you become a more effective engineer. This follows the Pareto principle (80/20 rule), the notion that for many activities, 80% of the impact comes from 20% of the work done. That 20% comprises the high-leverage activities, activities that produce a disproportionately high impact for a relatively small time investment. It is this high-leverage activities which require consistent applications of effort over long time periods to achieve high impact.

2. Optimize for Learning

“It’s not about apologizing for where your resume doesn’t line up but rather telling your story— who you are, what skills you’ve built, what you’re excited about doing next and why,”

accepting responsibility for each aspect of a situation that you can change.

It means taking control of your own story. It means optimizing for experiences where you learn rather than for experiences where you effortlessly succeed. And it means investing in your rate of learning. To invest in your own growth, you should carve out your own 20% time. It’s more effective to take it in one- or two-hour chunks each day rather than in one full day each week. The goal is to make investments that will make you more effective in the long run.

The more people you meet, the more you’ll find serendipitous opportunities. Writing also provides an opportunity for mindful reflection on what you’ve learned.

3. Prioritize Regularly

The human brain is optimized for processing and not for storage.Brainpower is much better spent on prioritizing our work and solving engineering problems than on remembering everything we need to do. A single master list is better than an assortment of sticky notes, sheets of paper, and emails, because these scattered alternatives are easily misplaced and make it harder for your brain to trust that they’re comprehensive.

4. Invest in Iteration Speed

Iterating quickly and focusing on impact rather than being conservative and minimizing mistakes. The faster that you can iterate, the more that you can learn about what works and what doesn’t work. You can build more things and try out more ideas.

There are only a finite number of work hours in the day, so increasing your effort as a way to increase your impact fails to scale. Tools are the multipliers that allow you to scale your impact beyond the confines of the work day.

Mastery is a process, not an event, and as you get more comfortable, the time savings will start to build. The key is to be mindful of which of your common, everyday actions slow you down, and then figure out how to perform those actions more efficiently.

Projects fail from under-communicating, not over-communicating. Even if resource constraints preclude the dependency that you want from being delivered any sooner, clarifying priorities and expectations enables you to plan ahead and work through alternatives. Expend slightly more effort in coordination; it could make a significant dent in your iteration speed. Get the ball rolling on the requirements in your launch checklist, and don’t wait until the last minute to schedule necessary reviews.

5. Measure What You Want to Improve

“If you can’t measure it, you can’t improve it.” Good metrics accomplish a number of goals. First, they help you focus on the right things. Additionally, when visualized over time, good metrics help guard against future regressions. It no longer makes sense to tackle small wins if you have a more aggressive goal. The metric you choose influences your decisions and behavior.

Jim Collins, the author of Good to Great, argues that what differentiates great companies from good companies is that they align all employees along a single, core metric that he calls the economic denominator.

An actionable metric is one whose movements can be causally explained by the team’s efforts. In contrast, vanity metrics,

When we don’t have visibility into our software, all we can do is guess at what’s wrong.

The more quickly that teams can identify the root cause of certain behaviors, the more rapidly they can address issues and make progress.

Using data to support your arguments is powerful. The right metric can slice through office politics, philosophical biases, and product arguments, quickly resolving discussions. Unfortunately, the wrong metric can do the same thing— with disastrous results.

Untrustworthy data that gets incorporated into decision-making processes provides negative leverage.

6. Validate Your Ideas Early and Often

The sooner that we gain a better understanding of a risky issue that impedes our progress, the earlier we can either address it to increase our chances of success, or change course to a more promising avenue. Demystifying the riskiest areas first lets you proactively update your plan and avoid nasty surprises that might invalidate your efforts later. Invest a small amount of work to gather data to validate your project assumptions and goals. In the long run, you’ll save yourself a lot of wasted effort. Even a well-tested, cleanly designed, and scalable software product doesn’t deliver much value if users don’t engage with it or customers don’t buy it. A/ B testing enables us to validate our product ideas and transform an otherwise-baffling black box of user behavior data into understandable and actionable knowledge. assures us that our time and effort are well-spent and that we’re achieving our goals. If quantitative data through A/ B testing isn’t available, however, we can still validate our ideas through qualitative feedback.

adds friction to the process of getting feedback— and you need feedback to help validate that what you’re doing will work.

if you don’t find out until the end that you’ve gone in the wrong direction, you’ll waste a lot of effort.

The lows of a project are more demoralizing when you’re working alone. The highs can be less motivating when you’re working alone.

The most direct path to getting feedback is to request it. Explaining an idea to another person is one of the best ways of learning it yourself. Moreover, your explanation might reveal holes in your own understanding.

Prepare beforehand. Make sure that you can articulate the problem that you’re trying to solve and the approaches that you’ve already tried. Investing 10% of your effort to validate the other 90% of work that you plan to do.

The shorter path to earlier feedback is extremely valuable.

Even if you prefer to work independently, you’ll be more effective if you conceptualize your work as a team activity and build in feedback loops.

Validation means formulating a hypothesis about what might work, designing an experiment to test it, understanding what good and bad outcomes look like, running the experiment, and learning from the results.

7. Improve Your Project Estimation Skills

Successful project planning requires increasing the accuracy of our project estimates and increasing our ability to adapt to changing requirements. Is it more important to hold the date constant and deliver what is possible, or to hold the feature set constant and push back the date until all the features can be delivered?

8. Balance Quality with Pragmatism

It’s possible to over-invest in quality, to the point where there are diminishing returns for time spent.Pragmatism— thinking in terms of what does and doesn’t work for achieving our goals— is a more effective lens through which to reason about quality.

It takes less time and energy to address problems earlier in the development process; it costs significantly more after they’ve been deployed to production.

Abstractions, “Pick the right ones, and programming will flow naturally from design; modules will have small and simple interfaces; and new functionality will more likely fit in without extensive reorganization,”while on the other hand “Pick the wrong ones, and programming will be a series of nasty surprises: interfaces will become baroque and clumsy as they are forced to accommodate unanticipated interactions, and even the simplest of changes will be hard to make.” Building a generalized solution takes more time than building one specific to a given problem. To break even, the time saved by the abstraction for future engineers needs to outweigh the time invested. When we’re looking for the right tool for the job and we find it easier to build something from scratch rather than incorporate an existing abstraction intended for our use case, that’s a signal that the abstraction might be ill-designed. Simple things take on one role, fulfill one task, accomplish one objective, or deal with one concept. Designing good abstractions take work. Study other people’s abstractions to learn how to build good ones yourself.

A suite of extensive and automated tests can smooth out the spikes and reduce overall error rates by validating the quality of new code. When fixing a bug, first add a test that the bug breaks. Programmatically— and quickly— run through large numbers of branches to verify correctness. Tests leads engineers to be much more accountable for the quality of their own work. Tests also allow engineers to make changes, especially large refactoring, with significantly higher confidence. When code does break, automated tests help to efficiently identify who’s accountable. Tests offer executable documentation of what cases the original author considered and how to invoke the code. Average familiarity with a codebase decreases as both the code and the team grow, making it difficult to make future modifications without sufficient tests. Just like documentation, writing tests is done more easily by the original authors when their code is fresh in their minds.

Technical debt refers to all the deferred work that’s necessary to improve the health and quality of the codebase and that would slow us down if left unaddressed. Just like financial debt, failure to repay the principal on our technical debt means that increasing amounts of time and energy get devoted to repaying the accumulating interest rather than to building value. Whenever we write software without fully understanding the problem space, our first version will likely end up being less cleanly designed than we’d like. The key to being a more effective engineer is to incur technical debt when it’s necessary to get things done for a deadline, but to pay off that debt periodically. You only have a finite amount of time, and time spent paying off technical debt is time not spent building other sources of value.

9. Minimize Operational Burden

Simple solutions impose a lower operational burden because they’re easier to understand, maintain, and modify. The additional complexity may be a necessary evil— but oftentimes, it’s not. When engineering teams don’t focus on doing the simple thing first, they either end up being less effective over time because their energy is spent on a high upkeep cost, or they reach a point where the operational burden gets so high that they’re forced to simplify their architecture. Always ask, “What’s the simplest solution that can get the job done while also reducing our future operational burden?”. Slowly failing systems muddy the sources of code errors, making it difficult for us to discover what went wrong.

The more directly we can link the feedback to a source, the more quickly that we can reproduce the problem and address the issue.A system that fails fast, when a problem occurs, it fails immediately and visibly. Use fail-fast techniques to surface issues immediately and as close to the actual source of error as possible; and complement them with a global exception handler that reports the error to engineers while failing gracefully to the end user.

tragedy of the commons, in which individuals act rationally according to their own self-interest but contrary to the group’s best long-term interests.

Every time you do something that a machine can do, ask yourself whether it’s worthwhile to automate it. The cost of automating (including learning how to automate) may initially be higher than the cost of doing the job manually.If the experience increases the efficiency with which you can automate in the future, that skill will compound and pay for itself as you use automation for more and more problems.Types of automation: automating mechanics and automating decision-making. Automating the right decisions to make, particularly in the context of building systems that can heal and repair themselves when things go wrong, turns out to be much more challenging. Automation can produce diminishing returns as you move from automating mechanics to automating decision-making.

One technique to make batch processes easier to maintain and more resilient to failure is to make them idempotent. An idempotent process produces the same results regardless of whether it’s run once or multiple times. Structuring a batch process so that it’s at least retry-able or re-entrant can still help. A retry-able or re-entrant process is able to complete successfully after a previous interrupted call. This can be achieved by making each process either fail entirely or succeed entirely.The ability to run infrequent processes at a more frequent rate than strictly necessary helps to expose problems sooner.Idempotence and re-entrancy can reduce some of the complexity and recurring costs involved in maintaining automated and batch processes. They make automation cheaper, freeing you to work on other things.

“The best defense against major unexpected failures is to fail often.”

10. Invest in Your Team’s Growth

people and the team that you work with have a significant impact on your own effectiveness— and you don’t have to be a manager or a senior engineer to influence your team’s direction. The higher you climb up the engineering ladder, the more your effectiveness will be measured not by your individual contributions but by your impact on the people around you. Thinking early in your career about how to help your co-workers succeed instills the right habits that in turn will lead to your own success.

Sharing code ownership benefits not only yourself but your entire team as well. When you’re the bottleneck for a project, you lose your flexibility to work on other things. High-priority bugs get routed to you more frequently because your expertise enables you to fix them faster. That’s a key reason why investing in your team, particularly by teaching and mentoring, helps you in the long run. Shared ownership eliminates isolated silos of information and enables an engineer to step in for another teammate. Share ownership and remove yourself from the critical path to give yourself more opportunities to grow.

Effective teams meet and conduct a detailed post-mortem. They discuss and analyze the event, and they write up what happened, how and why it happened, and what they can do to prevent it from happening in the future.Opportunities for building collective wisdom get lost. Lessons might not get learned; or if they do, they are isolated in a few people’s heads. Costly mistakes are repeated. And when people leave, collective wisdom decreases. Use methodologies like Toyota’s “Five Whys” to understand the root cause of operational issues. Compiling team lessons is predicated upon honest conversation— and holding an honest conversation about a project can be uncomfortable.

Engineering culture consists of the set of values and habits shared by people on the team, and a great culture provides a number of benefits. Great engineering culture isn’t built in a day; nor is it already in place when a company first starts. It begins with the values of the initial team members, and it’s a continual work-in-progress that every engineer helps to shape.