The Effective Engineer

  1. Focus on High-Leverage Activities
    • leverage = impact produced / time invested
    • use leverage to measure the effectiveness
    • leverage can be increased by 1) reducing time to complete the task, 2) increase the output, and/or 3) shifting to a higher leverage activity
    • for a meeting
      • default to a half-hour meeting
      • prepare agenda and set goals beforehand
      • if an in-person meeting isn’t actually necessary, replace it with an email discussion
    • the single most valuable lesson I’ve learned in my professional life is to always focus on high-leverage activities
    • high leverage activities require consistent application over long periods to achieve high impact
  2. Optimize for Learning
    • optimizing for learning is a high-leverage activity
    • adopt a growth mindset over a fixed mindset
    • accept responsibility and take control of your story
    • invest in your rate of learning
      • compounding leads to exponential growth, slow at first but rapid growth later
      • earlier is better
      • small deltas in interest can make big difference
    • joining an unchallenging 9-to-5 job is getting paid to accept lower intellectual growth rate
    • growing 1% a day means you will be 37x better by the end of the year
    • seek work environments conducive to learning
      • fast growth: a lot of problems to solve and ample opportunity to make a difference and increase responsibilities
      • training: onboarding and mentorship shows team prioritizes professional growth
      • openness: employees can challenge each other and incorporate feedback.
      • pace: quick iteration results in a faster feedback cycle
      • people: work with smarter, more talented and creative people who can be teachers and mentors
      • autonomy: the freedom to choose what you work on, usually more at smaller companies
    • dedicate time on the job to develop new skills
      • maybe one-to-two hour chunks each day
      • study code for core abstractions written by best engineers
      • write more code
      • go through technical, educational materials
      • master the programming language
      • send code review to harshest critics
      • enroll in classes
      • participate in design discussions of projects you’re interested in
      • work on a diversity of projects
      • make sure you’re on a team with at least a few senior engineers
      • jump fearlessly into code you don’t know
    • always be learning
      • new programming languages and frameworks
      • invest in high demand skills
      • read books
      • join a discussion group
      • attend talks, conference, meetups
      • build and maintain a strong network of relationships
      • follow bloggers who teach
      • write to teach. provides a mindful reflection on what you learned.
      • tinker on side projects. creativity from combining disparate ideas.
      • pursue what you love. don’t watch tv.
    • be motivated to learn about the things that excite you
  3. Prioritize Regularly
    • always more tasks to do than time
    • prioritization is hard work and requires practice
    • significantly increases your chance of success
    • track to-dos in a single easily accessible list
      • brain optimized for processing, not storage
      • always be asking if there is something that is higher-leverage
    • focus on what directly produces value
      • time and effort not necessarily correlated to the value
      • what matters most is the value you created
      • products shipped, users acquired, business metrics moved, etc
      • make sure the effort you invest is proportional to the expected impact
      • defer and ignore tasks that don’t add value
      • learn to say no
    • focus on the important and non-urgent
      • easy to ignore since no hard deadline
      • carve out time to invest in skills development
      • label everything on todo with quadrant it falls into
    • protect your maker’s schedule
      • need continuous blocks of uninterrupted time
      • cluster meetings and block time for yourself
      • say no to unimportant activities
    • limit the amount of work in progress
      • work on too many things results in a lot of context switching
      • use trial and error to find how many things you can manage at once
      • resist the urge to work on too many projects at once
    • fight procrastination with If-Then Plans
      • identify ahead of time things you need to do when
      • when the cue triggers (reaches scheduled time) the “then” behavior follows automatically
      • procrastination primarily from reluctance to expend the initial activation energy on a task
    • make a routine of prioritization
      • it is a common pitfall for engineers to neglect revisiting priorities
      • make it a habit
      • come up with your own system to review and reassess
      • prioritization is a very high-leverage activity
  4. Invest in Iteration Speed
    • continuous delivery is an example of a way to increase iteration speed
      • reduces overhead
      • allows quick debugging or investigation in production
      • small diffs are easier to debug
    • faster you iterate faster you can learn what does and doesn’t work
    • invest in time-saving tools
      • Bobby Jonson, former Facebook Director of Infrastructure Engineering “[A] very good indicator of future success if the first thing someone did on a problem was to write a tool”
      • if you have to do something manually more than twice, write a tool for the third time
      • iteratively identify bottlenecks and figure out tools that allow for faster iteration
      • pays big dividends in long-term
      • speeding up compilation time another example that can boost productivity
      • ability to evaluate expressions quickly i.e. interactive programming environment
      • hot code reloads
      • time-saving properties scale with team adoption
      • sometimes may need to reduce switching costs e.g. plug-in to IDE people already use
      • one side benefit of proving time-saving benefit is earning leeway with managers and peers to explore more ideas
      • time-saving tools provide measurable benefits
    • shorten your debugging and validation loops
      • wire up the application to drop you into problematic areas
      • add the ability to configure through URL to drop you to the relevant report
      • may feel reluctant because the last thing you want to do is add more work, but the investment may help you resolve the issue faster vs paying the tax every iteration
      • Mike Krieger, co-founder, and CTO Instagram “Effective engineers have an obsessive ability to create tight feedback loops for what they’re testing”
    • master your programming environment
      • basic tools stay the same
      • minor improvement compound
      • identify everyday actions that slow you down
      • get proficient with your favorite text editor or IDE. learn and practice
      • learn at least one productive high-level language
      • get familiar with UNIX shell commands (grep, sort, uniq, wc, awk, sed, xargs, find)
      • prefer the keyboard over the mouse
      • automate your manual workflows. once you’ve done something more than three times, think about how to automate
      • test ideas on an interactive interpreter
      • make it fast and easy to run the unit tests
      • allows you to shift limited time from mechanics of programming to more important problems
    • don’t ignore your non-engineering bottlenecks
      • proactively try to fix processes inside your sphere of influence
      • the sooner you acknowledge that you need to personally address the bottleneck, the more likely you’ll be able to adapt your goals or establish consensus on the functionality’s priority
      • communication is critical for making progress on people-related bottlenecks
      • projects fail from under-communicating
      • review/approval processes can be another bottleneck, see if you can communicate with the decision-makers or people who have worked closely with them
      • plan/coordinate e.g. with QA and make sure timelines match up
  5. Measure What you Want to Improve
    • metrics can help determine what to prioritize
    • use metrics to drive progress
      • can use to assess your own effectiveness and prioritizing your work
      • help focus on the right things and if you actually achieve your objectives
      • can help guard against future regressions
      • can help drive forward progress and improvements
      • measure effectiveness over time
      • just because it’s hard to measure doesn’t mean it’s not worthwhile
    • pick the right metric to incentivize the behavior you want
      • selecting what you measure is as important as measuring itself
      • the wrong metric can be ineffective or counterproductive
      • examples
        • hours worked vs productivity
        • click-through rate vs long click-through rate (google search)
        • average response time vs 95th or 99th percentile
        • bugs fixed vs bugs outstanding
        • registered users vs growth rate
        • weekly active users vs active rate by age of the cohort
      • the magnitude of goal matters and may greatly influence decisions and behaviors
      • when deciding what to measure 1) maximize impact, 2) actionable, and 3) responsive yet robust
    • instrument everything to understand what’s going on
      • without instrumentation flying blind and can’t know what’s going on
      • need to know where issues, errors, or bugs start
      • Etsy “measure anything, measure everything”
      • successful companies make it easy for engineers to measure, monitor and visualize system behavior
      • open-source tools like Graphite, StatsD, InfluxDB, Ganglia, Nagios, Munin
      • Managed solutions like New Relic or AppDynamics
    • internalize useful numbers
      • knowledge of useful numbers provide a valuable shortcut for knowing where to invest the effort to maximize gains
      • takes upfront work, but long-term payoffs are high
      • understand common numbers or industry averages can help you build intuition about where to direct effort
    • Be Skeptical About Data Integrity
      • all data can be abused
      • the best defense is skepticism
      • consider if result roughly makes sense and compare the numbers with your intuition to see if they align
      • tracking metrics or logging can be less robust
      • log data liberally in case it is useful later on (like Netflix)
      • build tools to iterate on data accuracy sooner
      • write end-to-end integration tests to validate your entire analytics pipeline
      • examine collected data sooner
      • cross-validate data accuracy by computing the same metrics in multiple ways
      • when a number does look off, dig into it early
    • make sure your data is reliable
  6. Validate Your Ideas Early and Often
    • validating early and often helps us get the right things done
    • find low-effort ways to validate your work
      • longer the iteration cycle, the more likely it is that incorrect assumptions and errors will compound
      • Zach Brock, engineering manager at Square recommends doing the riskiest part of the project first
      • think about how to expend a small fraction of total effort to collect some data and validate what you’re doing will work
      • potentially 10% more work, but could save 90% of wasted effort
      • can spend 10% of effort building an informative prototype
      • can fake full implementations e.g. fake sign-up button
    • continuously validate product changes with A/B testing
      • helps you decide which variation to launch and how much better it is
      • encourage iterative approach and validation of theories
      • articulate a hypothesis, construct an A/B test, iterate based on what you learned
      • Free or opensource A/B testing frameworks: Etsy’s feature-flagging API, Vanity, Genetify, Google Content Experiments
      • Paid software: Optimizely, Apptimize, Unbounce, and Visual Website Optimizer
      • as you run more experiments, you’ll be able to prioritize better
      • helps transform user behavior into understandable and actionable knowledge
    • beware the one-person team
      • adds friction to process of getting feedback
      • possible for an engineer to spend a lot of time doing something incorrectly
      • seed up necessary feedback channels
        • be open and receptive to feedback. optimize for learning and use as an opportunity for improvement
        • commit code early and often
        • request code reviews from thorough critics
        • ask to bounce ideas off teammates
        • design the interface or API of a new system first
        • send out a design document before devoting your energy to your code
        • if possible, structure ongoing projects so there is some shared context with teammates i.e. see if you can work on same project together in parallel
        • solicit buy-in for controversial features before investing too much time. earlier feedback is extremely valuable.
      • software engineering is a team sport
    • build feedback loops for your decisions
      • important for any decisions you make
      • consider for all aspects of your job
      • many of our work decisions are testable hypotheses
      • be willing to run experiments
      • formulate a hyupotehesis, design an experiment, think about what good and bad outcomes look like, run experiment and learn from results
      • transform what would be guess work to informed decision-making
  7. Improve Your Project Estimation Skills
    • 44% of projects delivered late, overbudget, or missing requirements
    • 24% fail to complete
    • average slipped project overruns its time budget by 79%
    • project estimation is one of hardest skills, but it’s crucial to master
    • important for business for planning
    • how long we think project will take affects decisions about what to work on
    • use accurate estimates to drive project planning
      • project schedules slip because we allow the target to alter the estimate
      • estimates should inform project planning vs the other way around
      • hold the date constant and deliver what is possible or push back the date
      • strategies
        • decompose the project into granular tasks. further break down tasks taking more than two days
        • estimate based on how long task will take not how long you or someone want it to take
        • think of estimates as probability distributions not best case scenarios
        • let the person doing the task do the estimation
        • beware of anchoring bias. avoid commiting to number based on someone else’s guess
        • use multiple approaches: decompose, historical data, number of subsystems and avg time for each
        • beware of mythical man-month: adding people doesn’t necessarily reduce time due to communication overhead and ramp up
        • validate estimates against historical data
        • timebox tasks that can grow in scope
        • allow others to challenge estimates
      • iteratively revising estimates can lead to better project outcomes
      • measure actual time vs estimate time helps reduce error bounds for future
      • discovering you’re falling behind allows you to adjust by cutting lower-priority features or push back deadlines
    • budget for the unknown
      • vacations, more difficult than expected, bugs, high priority customer requests, new product development, etc
      • disastrous schedule slippage usually due to termites not tornadoes
      • longer a project is the more likely unexpected problems arise
      • engineers spend a lot of time on non-engineering work: meetings, interviews, bugs, one-on-ones, pager-duty, mentoring, emails, one-off interuptions, etc
      • need to buffer in time for unexpected interruptions
      • be explicit about how much time per day each member will realistically spend on a given project
    • define specific project goals and measureable milestones
      • helps you separate the must-haves from the nice-to-haves
      • builds clarity and alignment across key stakeholders / make sure you’re all on the same page
      • helps team members align on main goals so they can make consistent tradeoffs
      • outline mesasureable milestones: specified set of features and target completion dates keeps us honest and more accurately measures whether we’re on track
      • helps scrutizine/prioritize every task and determine if it’s a prerequisite for the milestone
      • milestones act as checkpoints on progress
      • can revise plan by cutting tasks or moving deadline
    • reduce risk early
      • tempting to get started on easy part
      • if problem turns out to be harder than expected better to find out and adjust early
      • tackling riskiest areas help identify any estimation errors sooner
      • system integration almost always takes longer than planned
        • do end-to-end scaffolding and system testing earlier
        • forces you to think more about necessary glue
        • if something breaks can fix along the way
        • amortizes cost of integration throughout development process
      • revise estimates as we gain more information
      • shifting highly variable work to earlier reduces risk and gives us more time and information to make effective project plans
    • approach rewrite projects with extreme caution
      • very common for engineers to want to rewrite something from scratch
      • rewrites are some of the riskiest projects
      • same project planning and difficulties as other software projects
      • because we’re familiar with it, tend to underestimate rewrite projects
      • easy and tempting to bundle additional improvements
      • while rewrite is in progress need to add new features or improvements as well
      • may proceed with less caution and overcomplicate on the second system
      • engineers who successfully rewrite tend to do by converting to a series of smaller projects
      • may increase overall work, but dramatically reduces risk
      • if not possible to run new and old version at same time, can try to do in phases.
      • e.g. Upstartle (google docs) 1) converted from C# to Java and 2) refactored after integration with Google
    • Don’t Sprint in the Middle of a Marathon
      • increasing hours worked doesn’t neccessarily mean hitting the launch date
      • hourly productivity decreases with more hours worked
      • you’re probably more behind than you think
      • if you underestimated the beginning parts of the project, you likely underestimated the remaining part of the project
      • additional hours can burn out team members resulting in more error, burnout, turnover
      • working extra hours can hurt team dynamics e.g. someone who can’t put in the extra hours
      • communication overhead increases as deadline looms meaning less time to work
      • sprint incentivizes technical debt which is work that must be prioritized against future critical projects
      • best strategy is redefine what to include in launch or postpone deadline
      • if you are going to do overtime increase probabilty it accomplishes your goal
        • make sure everyone understand why slippage
        • develop a realistic and revised version of project plan and timeline
        • be ready to abandon the sprint as its unlikely working harder is going to fix things
  8. Balance Quality with Pragmatism
    • software quality boils down to a matter of tradeoffs
    • think in terms of what does and doesn’t work
    • establish a sustainable code review process
      • helps catch bugs or design shortcomings early (one study shows it removes 85% of remaining bugs)
      • increases accountability
      • positive modeling of how to write good code
      • shared working knowledge of code base
      • increase long-term agility
      • code review process can be on a continuum (review all code changes vs reviewing no code changes)
      • experiment and find right balance that works for you
    • manage complexity through abstraction
      • lets engineers focus on what they actually care about
      • reduces complexity
      • reduces maintenance cost
      • solves hard problems once
      • takes more time upfront
      • high-leverage to focus on areas people spend a lot of time on
      • overinvesting or building a poor abstraction can be costly
      • good abstractions are easy to learn, esay to use without documentation, hard to misuse, powerful to satisfy requirements, easy to extend, appropriate to the audience
      • designing good abstractions take work
      • study other people’s abstractions e.g. open source projects
    • automate testing
      • time required for manual testing can become prohibitive
      • suite of tests can smooth out error/bug spikes for each release
      • allows for safer refactorings
      • executable documentation
      • 100% code coverage is difficult
      • focus on areas where it will save you most time and have biggest impact
      • often writing the first one is the hardest
    • repay technical debt
      • can slow down iteration speed if not payed down
      • some technical debt is unavoidable because you will learn more about your problem space
      • often up to individual engineer to argue for and justify tech debt work
      • start off small if less confident
      • not all technical debt is worth paying down
      • focus on areas that are frequently read, invoked and modified
      • code that is rarely used, modified, or doesn’t change much may not affect development speed
      • focus on debt with the highest leverage
  9. Minimize Operational Burden
    • enhance operational simplicity
      • often ask if this is the simplest way to do this
      • complex architectures with many different/new technologies imposes maintenance costs
        • engineering expertise gets splintered
        • new engineers face a steeper learning curve
        • effort towards improving abstractions, libraries and tools get diluted
      • fine to experiment for protoype or toy project, but think hard before using in a new production system
      • research new technologies and see if it solves the problem you’re facing
      • weigh existing tool vs custom solution. complexity vs simplicity through standardization
    • build systems to fail fast
      • default parameter values, catch-all exception handlers, swallowing unexpected return values cause slow failures
      • makes it harder to identify where issues are arising from
      • when a system fails fast, it fails immediately and visibility
      • examples of fast failing
        • crash at startup time for config errors
        • validate software inputs
        • bubbling up an error from an external service
        • throw exeception as soon as possible
        • assert key invariants
        • alerting for any invalid or inconsistent program state
      • the more compelx a system, the more time the fail fast technique can save
      • don’t neccessarily need to crash program, log error for engineers and fail gracefully for user
    • relentlessly automate mechanical tasks
      • easy to push off
        • no time right now
        • tragedy of commons because manual work spread across multiple engineers
        • lack of familiarty with automation tools e.g. UNIX
        • underestimate future frequency of task
        • don’t internalize the time savings over the long-term
      • always think about if it’s something a machine can do
      • difference between automating mechanics and automating decision-making
      • focus on automating mechanics, automating decision-making is harder
    • make batch processes idempotent
      • as automation grows probability of failure increases
      • try to make idempotent so you can easily retry
      • can also try to make retryable or reentrant
      • idempotence also allows you to run a ninfrequent process more frequently
      • idempotence and reentrancy can reduce complexity and recurring costs associated in maintaining automated and batch processes
    • hone your ability to respond and recover quickly
      • at some point more leverage in trying to recover quickly than preventing failures
      • even though cost of failure is high often don’t devote enough resources because happens infrequently
      • recovery processes tend to be inadequate
      • “scripting for success”: come up with plans for what to do in various scenarios. moves decision making process away from stressful times
      • consider many “what if” scenarios
      • practice in other ares of software engineering as well:
        • project planning
        • critical team member leaves
        • if user revolts against feature
  10. Invest In Your Team’s Growth
    • as you get higher up, your success is tied to your teams
    • your career success depends largely on your company
    • invest in their success and make hiring a top priority
    • make hiring everyone’s responsibility
      • adding a strong engineer is an extremely high leverage activity
      • should screen for the type of people likely to do well on teh team and get them excited
      • focus on qualities most correlated with success on your team
      • take time to identify with your team what you care about: coding aptitude, master yof programming languages, algorithms, data structures, product skills, debugging, communication, culture fit, etc
      • discuss how effective the current recruiting and interviewing process is and iterate
      • design problems with multiple layers of difficulty
      • control pace and maintain high signal-to-noise ratio / don’t let them get stumped
      • scan for red flags
      • periodicallys shadow or pair with another team to calibrate and give each other feedback
      • don’t be afraid to use unconventional approaches
    • design a good onboarding process
      • as team grows harder for recent hire to figure out what to learn first without guidance
      • quality onbaording process is powerful leverage point
      • training a new engineer for an hour or two a day for the first month genrates much more organizational impact than working on another project
      • lost productivity if recent hire takes long to ramp up
      • when creating onboarding process, identify goals you want your team to achieve
      • iterate on your process
      • consider assigning mentors who give guidance, feedback and starter projects
    • share ownership of code
      • benefits your entire team
      • when you’re the bottleneck you lose flexibility to work on other things
      • investing in your team helps you in the long run
      • increases bus factor
      • shared ownership eliminates silos and enables engineers to step in for others so everyone can focus on whatever produces the most impact
    • build collective wisdom through Post-Mortems
      • often don’t pause to reflect how effectively we spent our time or whate we could have done better
      • aside from post-mortems for issues, consider doing on projects and launches as well
      • builds collective wisdom and helps repeating costly mistakes
      • predicated on honest conversation and avoiding assignment of blame
    • build a great engineering culture
      • empowers engineers
      • makes them happy and productive
      • shared context and ramework for decision-making
      • helps recruiting
      • work-in-progress so keep refining and improving
  11. Epilogue
    • “Time is our most finite asset, and leverage– the value we produce per unit time– allows us to direct our time toward what matters most”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s