Key Takeaways
1. Master Conscious Competence Through Active Learning
The Missing README will teach you these skills.
Learning to Learn. Software engineering demands continuous learning. To move from unconscious incompetence to conscious competence, embrace active learning strategies. Front-load your learning by understanding company-specific processes and tools early on.
Diverse Learning Methods. Experiment with code, read documentation and codebases, watch presentations, and attend meetups. Shadow experienced engineers and engage in side projects to broaden your skillset. Don't just passively consume information; actively apply what you learn.
Asking Effective Questions. When stuck, research thoroughly before asking for help. Frame questions clearly, showing the work you've already done. Prefer asynchronous communication to avoid interrupting colleagues. By combining independent learning with targeted questions, you'll accelerate your growth.
2. Code with Empathy: Write Operable Software
Writing operable code helps you deal with the unforeseen.
Defensive Programming. Protect your systems by writing code that anticipates and handles potential failures. Avoid null values, make variables immutable, use type hinting, and validate inputs rigorously. Employ exception handling to gracefully manage errors.
Logging, Metrics, and Configuration. Implement robust logging to track application behavior. Use standard metrics libraries to measure performance and identify bottlenecks. Manage configuration carefully, providing defaults and validating inputs.
Operability as Compassion. By writing operable code, you're showing consideration for those who will run and maintain your software. This includes yourself! Invest in these practices to create systems that are easier to debug, monitor, and evolve.
3. Manage Dependencies to Avoid Project Chaos
Thanks to the viral nature of transitive dependencies, thousands and thousands of open source and commercial codebases had a critical dependency on this fairly trivial library.
Dependency Management Basics. Understand the fundamentals of dependency management, including semantic versioning and transitive dependencies. Use dependency reports to visualize the full dependency tree of your projects.
Avoiding Dependency Hell. Prevent dependency conflicts by isolating dependencies, pinning versions, and scoping dependencies narrowly. Be wary of circular dependencies and take steps to avoid them.
Deliberate Dependency Choices. Before adding a dependency, carefully consider its value, maintenance status, and potential risks. By managing dependencies proactively, you'll keep your projects stable and maintainable.
4. Test Thoroughly to Ensure Reliability
Code never lies. Comments sometimes do.
The Many Uses of Tests. Tests serve multiple purposes beyond verifying code correctness. They protect against regressions, encourage clean code, document behavior, and provide a playground for experimentation.
Types of Tests. Employ a variety of testing methods, including unit, integration, system, performance, and acceptance tests. Each type serves a different purpose and provides valuable insights into your software's behavior.
Writing Effective Tests. Write clean, focused tests that fail meaningfully. Avoid overdoing testing or chasing arbitrary coverage metrics. Address nondeterminism in tests by seeding random number generators, injecting clocks, and cleaning up leftover state.
5. Code Reviews: A Collaborative Path to Quality
A culture of high-quality code reviews helps engineers of all experience levels grow and promotes a shared understanding of the codebase.
Why Review Code? Code reviews catch bugs, improve code quality, spread knowledge, document decisions, and ensure compliance. They are a critical part of a healthy development process.
Getting Your Code Reviewed. Prepare your review carefully, keep changes small, and provide clear descriptions. Be receptive to feedback and don't get attached to your code.
Reviewing Code Effectively. Triage review requests, block off time for reviews, and understand the change thoroughly. Give comprehensive feedback, acknowledge good work, and drive to a conclusion.
6. Deliver Software Incrementally and Safely
You should understand how your code winds up in front of users.
Software Delivery Phases. Understand the different phases of software delivery: build, release, deployment, and rollout. Each phase has its own best practices and considerations.
Branching Strategies. Choose a branching strategy that supports your team's development style. Trunk-based development is often preferred, but feature branch-based development may be necessary in some cases.
Safe Rollouts. Employ rollout strategies such as feature flags, circuit breakers, canary deployments, and blue-green deployments to minimize risk and ensure a smooth user experience.
7. On-Call: Be Prepared, Responsive, and Clear
Your best ability is availability.
How On-Call Works. Understand the on-call rotation, paging systems, and handoff procedures. Develop essential on-call skills such as availability, attention, prioritization, and communication.
Handling Incidents. Follow a structured approach to incident response: triage, coordination, mitigation, resolution, and follow-up. Document your actions and communicate clearly throughout the process.
Providing Support. Respond to support requests promptly and professionally. Use support interactions as an opportunity to learn and improve your software. Avoid the temptation to be a hero and burn yourself out.
8. Design with Purpose: A Structured Approach
In preparing for battle I have always found that plans are useless, but planning is indispensable.
The Technical Design Process Cone. Embrace a cyclical design process that alternates between independent work and collaborative discussion. Refine your design iteratively, gathering feedback at each stage.
Thinking About Design. Define the problem clearly, conduct thorough research, experiment with prototypes, and give yourself time to think creatively.
Writing Design Documents. Document consequential changes, keep the goal and audience in mind, practice writing, and keep your documents up-to-date. Use a design document template to structure your thinking and ensure completeness.
9. Architect for Evolution: Embrace Change
Complexity is anything related to the structure of a system that makes it hard to understand and modify the system.
Understanding Complexity. Recognize the characteristics of complex systems: high dependency, high obscurity, and high inertia. Strive to reduce complexity in your designs.
Design for Evolvability. Apply design principles such as YAGNI, the principle of least astonishment, and encapsulation to create systems that are easy to change.
Evolvable APIs and Data. Design APIs that are small, well-defined, compatible, and versioned. Isolate databases, use explicit schemas, automate schema migrations, and maintain schema compatibility.
10. Agile Planning: Adapt and Deliver Value
At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
The Agile Manifesto. Embrace the core values of Agile development: individuals and interactions, working software, customer collaboration, and responding to change.
Agile Planning Frameworks. Understand the key practices of Scrum, including sprints, user stories, tasks, story points, backlog triage, stand-ups, reviews, and retrospectives.
Continuous Improvement. Use retrospectives to identify areas for improvement and adjust your team's processes accordingly. Embrace experimentation and measure the results.
11. Manage Your Manager: Build a Productive Relationship
The primary thing that any technology startup must do is build a product that’s at least ten times better at doing something than the current prevailing way of doing that thing.
What Managers Do. Understand the roles and responsibilities of engineering managers: people management, product planning, and process improvement.
Communication, Goals, and Growth Processes. Take advantage of management processes such as 1:1s, PPPs, OKRs, and performance reviews to communicate your needs and track your progress.
Managing Up. Proactively seek feedback, give feedback, discuss your goals, and take action when things aren't working. Build a strong working relationship with your manager.
12. Navigate Your Career: To Senior and Beyond
The primary thing that any technology startup must do is build a product that’s at least ten times better at doing something than the current prevailing way of doing that thing.
Career Advice. Be T-shaped, participate in engineering programs, steer your promotion, change jobs carefully, and pace yourself.
Continuous Growth. Focus on developing your technical skills, communication abilities, and leadership qualities. Seek out opportunities to learn and grow throughout your career.
Long-Term Perspective. Remember that your career is a marathon, not a sprint. Pace yourself, prioritize your well-being, and enjoy the journey.
Last updated:
Review Summary
The Missing README receives overwhelmingly positive reviews, with readers praising its comprehensive coverage of software engineering practices. Many describe it as an essential guide for new developers, bridging the gap between academic knowledge and industry experience. Experienced engineers also find value in its concise explanations and practical advice. Reviewers appreciate the book's clear organization, helpful summaries, and additional resource recommendations. Some note that while it's most beneficial for those new to the field, it serves as a valuable reference for professionals at all levels.
Download EPUB
.epub
digital book format is ideal for reading ebooks on phones, tablets, and e-readers.