by Andrew Hunt and David Thomas
“The Pragmatic Programmer: From Journeyman to Master” by Andrew Hunt and David Thomas is a highly regarded guide for software developers, providing practical advice and best practices to improve their craft.
This post provides a summary, and I elaborate on some points based on my experience, such as the part that talks about DRY vs WET.
Continuous learning
The authors emphasize the importance of being a lifelong learner, as the field of software development is always evolving. Developers should invest in their knowledge by reading books, attending conferences, and learning new programming languages.
A software developer decides to learn a new programming language, programming technique (TDD, Design Pattern, programming paradigm), or problem-solving technique each year, expanding their knowledge and skills. They also attend workshops, webinars, and conferences to stay updated with industry trends and innovations.
DRY principle
“Don’t Repeat Yourself” is a foundational concept in the book, which encourages developers to avoid duplicating code or functionality. By adhering to the DRY principle, developers can reduce complexity, minimize errors, and make maintenance easier.
Instead of writing the same code snippet for handling user authentication/authorisation in multiple parts of an application, the developer creates a reusable function that can be called whenever user authentication/authorization is needed. That could be a library shared among many teams.
Please note abusing DRY can lead to highly coupled systems, so it's necessary to find a balance between DRY and WET (Write Everything Thrice). If you're not sure, wait for duplication to happen at least 3 times where changes in one place require the exact same change in 2 other places.
Orthogonality
This concept suggests that components within a system should have a single, well-defined responsibility and should operate independently of each other. This approach minimizes dependencies and side effects, making systems easier to understand and maintain.
The developer designs a system where the BillingComponent, NavigationComponent, and CustomerReminder back-end cronjob has a single responsibility and can be modified independently, reducing the risk of unintended side effects when changes are made.
This is similar to the "S" part of SOLID: The Single-responsibility principle by Uncle Bob (Robert Cecil Martin).
Design by contract
The authors advocate for clearly defining the expectations and responsibilities between software components. By specifying input and output conditions, developers can create more robust and reliable software.
In a software library, the developer clearly documents the expected input types, ranges, and output formats for each function. This ensures that other developers using the library understand how to interact with the functions and avoid unexpected behaviour. That documentation can be through a document but should preferably use typing or self-documenting code through the art of Duck Typing, a common practice in the JavaScript world for those who don't use TypeScript.
Incremental development
The book recommends using an iterative and incremental approach to software development. By breaking tasks into smaller, manageable pieces and frequently integrating code, developers can identify and resolve issues early in the process.
Here's an example of a team I've worked with in the past, a team working on a payment system for the app. They breaks the problem into smaller tasks:
- Integrate with the provider using Postman.
- Send the information through the UI with basic HTML input elements.
- Implement the design of the screen using CSS.
- Implement a retry mechanism preventing double charges so you don't get a call from your CEO
- Integrate the screen into the website's global navigation.
That allows the team to focus on completing and integrating one task at a time and parallelize where necessary; the software is always in a working state, albeit not in a very useful state for the final user. This allows the team to identify and fix issues early, preventing a buildup of bugs and reducing overall development time. It also allows you to deploy the code to production under a feature flag so that you can test all your delivery processes.
Automate repetitive tasks
The authors encourage developers to automate repetitive tasks, such as testing, building, and deployment. Automation can save time, reduce errors, and ensure consistency across the development process.
A developer sets up automated scripts to run tests, compile code, and deploy updates, ensuring that these tasks are performed consistently and efficiently while minimizing manual errors.
However, never automate a task where the Return on Investment can't be justified.
Code reviews and pair programming
The book highlights the benefits of code reviews and pair programming, as these practices can help identify issues, share knowledge, and foster a collaborative environment.
Two developers work together on a challenging piece of code, sharing ideas and insights. After completing the task, they review each other’s work, identifying potential issues and learning from each other’s approaches.
However, the review might come too late, and one of the devs might have built up code on an assumption that goes in the wrong direction. Pair Programming the task from beginning to end in one screen and one task allows for the feedback to happen earlier and for both devs to build a mental model of the problem so they can perform better over time.
Testing and quality assurance
The authors emphasize the importance of thorough testing and quality assurance processes. By writing and maintaining comprehensive test suites, developers can catch errors early and ensure the stability and reliability of their software.
The development team writes and maintains a comprehensive test suite, including unit tests, integration tests, and end-to-end tests. This helps catch errors early and ensures that new features do not introduce regressions.
Manage technical debt
The book advises developers to be aware of and manage technical debt, which is the accumulation of suboptimal design decisions and shortcuts taken during development. By addressing technical debt regularly, developers can prevent it from becoming unmanageable and hindering future work.
The team regularly reviews their codebase, identifying areas where shortcuts or suboptimal design decisions were made. They allocate time to refactor and improve the code, preventing technical debt from becoming unmanageable and slowing down future development.
Technical debt is not really a bad thing if you use it correctly.
Adaptability and pragmatism
The authors encourage developers to be adaptable and pragmatic in their approach to problem-solving. Rather than rigidly adhering to specific methodologies or tools, developers should be open to new ideas and willing to change course when necessary.
When a new project management tool gains popularity, the development team evaluates its features and potential benefits. They decide to adopt the new tool, even though it requires changing their established workflow because it offers significant improvements in efficiency and collaboration.
By embracing the principles and practices outlined in “The Pragmatic Programmer,” software developers can enhance their skills, increase their effectiveness, and advance their careers.
Thanks for reading. If you have feedback, contact me on Twitter, LinkedIn or Github.
Top comments (0)