Booknotes are just that, notes from books I’ve read, sometimes with comments
Measure What Matters
OKRs - The Simple Idea That Drives 10x Growth
OKRs at the individual level
Over the following weeks and months, thousands of Googlers will formulate, discuss, revise, and grade their team and individual OKRs. As always, they’ll have carte blanche to browse their intranet and see how other teams are measuring success.
Effectiveness vs expertise
It almost doesn’t matter what you know. It’s what you can do with whatever you know or can acquire and actually accomplish [that] tends to be valued here.
When people think about saving for their first home, the focus is always on the down payment. While a sizeable down payment is a worthwhile goal, by itself it isn’t a great indicator of home ownership readiness. There are two related metrics you should be tracking when deciding if you can afford to buy a home: emergency fund size and the rate at which you can refill your emergency fund.
An emergency fund is a liquid asset that acts as a safety net for unexpected expenses in life. Your emergency fund should be easy to access on short notice and free of fluctuations in value. In other words, a dip in the stock market should not translate to a dip in your fund size. Standard advice suggests an emergency fund size of 3-6 months of living expenses. There are lots of good articles and tools to help calculate the size of your emergency fund.
While preparing to buy a home, your emergency fund should be at least 6 months of expenses. Also, your definition of an average “month of expenses” must be recalculated based on what your budget will look like after your home purchase. This is an important point and worth repeating. Your emergency fund size will change over time, especially after significant events like a home purchase. You must recalculate regularly and adjust your savings as necessary.
Once you’ve calculated your sizeable down payment and fully updated emergency fund, now’s the time to force yourself to do a hard numbers gut-check. Start asking questions like “What if I have to replace a major appliance in the first 6 months?” or “What happens if I get laid off and am unemployed for 5 months?” You’re probably tempted to say “my emergency fund will cover it” and consider it resolved.
Unfortunately that isn’t going to cut it. While having an emergency fund is absolutely key to surviving tough situations financially intact, the recovery is not complete until you’re finishing refilling your emergency fund. Forecast the effects of any large drain on your emergency fund in terms of “How long will it take to refill?” or more importantly “Can I refill my emergency fund before the next emergency happens?” If you spend $5,000 on some unexpected repair and you can put $200/month towards your emergency fund, it is going to take 2 years to get back to normal. How confident are you that you won’t have another unexpected large expense in the next two years. Double the size of the repair and throw in some temporary unemployment and you’ll start to see how easily things can get out of control.
As you try to model these hypotheticals and estimate how much you’ll be able to save after an emergency, stay open to the idea that you might need to redefine what price home you consider affordable. It may be the case that now is not the right time for you to buy or you need to drastically lower your maximum purchase price.
Owning a home is guaranteed to be stressful at times for many reasons, but if you are honest with yourself about what you can handle financially, you can avoid adding money to that list of reasons.
What are the best indicators of a developer’s ability to contribute meaningful work to your organization?
Ability to understand your product domain.
An engineer should be able to understand the Why, How and What of your business’ core product. They should quickly grasp core concepts and visualize high level models that represent those concepts.
Ability to digest domain-specific code and understand the limitations.
Given an example implementation of one of your domain’s core functional areas, a good engineer should be able to talk through some of the anticipated complexities inherent in the example code. They should be able to spot edge cases and foresee ways to break your code with unanticipated usage.
Ability to collaboratively brainstorm and communicate potential solutions to #2.
It is extremely important that an engineer can speak both intelligently and plainly about your product domain.
Your hiring process should mimic a pared down version of your onboarding process.
Write a product specification for an MVP version of your application. Outline a few typical use cases and ask the engineer to write a concise implementation of the domain model and exercise that model with tests. The code should prove they understand the different domain objects and the relationships between them.
Extract actual code and tests from your repository related to one of the more complicated functional areas of your application. Remove the implementation from a few of your methods, leaving just the method signature and remove a few other required methods entirely. Provide an interface for an dependent service but no implementation. Make sure to leave in code representing some legacy trade-offs to encourage discussion. Ask the engineer to fill in the missing implementation and expand the test coverage for edge cases. Ask the engineer to complete the implementation and add tests where they see fit.
Ask the engineer specific questions about your code samples from #2. How might this break? Can you anticipate a use case that is unsupported by this design? What might you have done differently?
One final important cornerstone of your hiring process should be complete transparency. You should be completely open and honest about the state of your codebase, your backlog and your overall development environment. A new hiring should never be surprised by anything they learn during their first weeks at your company.
Too often code is written with little empathy towards those who will follow us and need to understand, modify and replace it. After the functional priorities (correct, stable, testable, etc.) your highest priority should be writing readable code that is easy to understand. Let’s look at a simple example.
While this code probably works fine, it relies on a few bad assumptions and obfuscates functionality behind those assumptions. First, the default value of 0 for the professorId parameter implies a professor isn’t required for this method to work properly. In other words, our database unique IDs probably start at 1 and go up. Second, the code assumes the ProfessorRepo.Find() method will return some usable value (that Classroom.Courses() knows how to handle) when the given professorId isn’t found in the database (rather than throwing an Exception).
Of course, I’m not arguing you shouldn’t write code that’s aware of how dependent code work, that would be unreasonable. My advice is to make it easier for future readers of your code to understand that underlying behavior without first having to dig through it. With that in mind, let’s rewrite the above snippet and get rid of some of those hidden assumptions.
Not much has changed, right? We changed the type of the professorId parameter to a nullable integer and we changed its default value to null. We also explicitly checked for that default null value before attempting to load a Professor instance from the Repository.
An explicit indication (default of null) and check (== null) of whether an optional parameter has a value makes the behavior of the underlying code that much more obvious to an unfamiliar reader. I no longer have to know that 0 is not a valid value for a professorId. I also no longer have to know what ProfessorRepo.Find() is going to do with that invalid value. We’ve also managed to avoid an unnecessary round trip to the database to confirm that a professorId of 0 is invalid (assuming Find() doesn’t do a short-circuit check).