Overall Review: Reconsidering “Best Practices” #
Hello, I am Zheng Ye.
I have delivered all the promised content to you, congratulations on completing the entire column! I hope that through studying these contents, you have gained a fresh understanding of “how to do software well”.
In this column, I have introduced many industry best practices to you, such as testing, continuous integration, and so on. However, due to the narrative style of this column, some related practices were explained in different modules.
Therefore, in this lecture, we will reconsider these contents from the perspective of best practices. I will connect these knowledge points again and help you with an overall review of the column.
Product #
When it comes to product development, often it is about solving problems in the face of uncertainty. The best practice in this area is currently “Lean Startup”. The simplest way to understand Lean Startup is to “try”. There is also a method to try, Lean Startup proposes a feedback loop of “build - measure - learn”, through which validated learning can be obtained.
Since it is about trying uncertain product features, the best approach is to try at a low cost. In Lean Startup, the Minimum Viable Product (MVP) is a low-cost trial method. The Minimum Viable Product is a product that “just” meets the needs of users. The key to understanding this statement lies in trying feasible paths at minimal cost.
In the process of refining a product, user testing can be used to directly observe how users use the product. As programmers, we should try to “eat our own dog food” as much as possible, even if the product we are developing is not for our own use, we can still strive to get close to the users.
-
Lean Startup - Related reading: “06 | Lean Startup: What should you do as a product manager when you can’t rely on your intuition?”
-
Minimum Viable Product (MVP) - Related reading: “19 | How to build a product at minimal cost?”
-
User testing, validating product features, eating our own dog food - Related reading: “26 | As a programmer, you should also listen to the voice of the user”
Requirements #
When we decide to develop a product feature, it is important to describe the requirements properly. The most common problem with listing requirements in a product backlog is that the overall picture of the requirements is unclear.
User stories are a good way to describe requirements: as a certain role, I want to do a certain thing, in order to achieve a certain outcome.
In user stories, acceptance criteria are crucial. Even if user stories are not used to describe requirements, it is still recommended to define acceptance criteria clearly.
Development teams often have an overly broad understanding of requirements, treating them as a single theme. Before development, it is important to break down requirements into smaller, more granular user stories. One standard to evaluate the appropriateness of breaking down a user story is the INVEST principle. Once user stories are broken down, estimation can be done. Estimation is a process of deepening our understanding of the requirements, and if a user story is too big, it should be further broken down.
Once we have broken down the requirements, we can discuss their priorities. It is important to prioritize tasks based on their importance rather than attempting to complete all requirements at once. Only by clarifying the priority of the requirements can we effectively manage them.
-
User Stories - Related reading: “04 | What should you do first when you receive a requirement task?”
-
Decomposition and Estimation of Requirements - Related reading: “17 | Can programmers also remove requirements?”
-
Requirement Management and Prioritization - Related reading: “18 | Requirement Management: What to do when too many people assign tasks to you?”
Continuous Integration #
In software development, writing code is not the end. We need to integrate the code together. Integration should be done frequently, and the smaller the code changes, the more frequent the integration can be done, even after every commit. This is called continuous integration.
Continuous integration has evolved into a complete set of development practices. To do continuous integration well, you need to remember that the key to continuous integration is “fast feedback.”
- How to get feedback quickly.
- How to provide effective feedback.
Continuous integration can be further extended to include production deployment, which is called continuous delivery. If we take one step further with continuous delivery, we can combine it with product validation.
The key points of continuous delivery are validating the release package and automating deployment in different environments. Different environments make up the continuous delivery pipeline, and automated deployment is where DevOps capabilities come into play. The development of continuous delivery has transformed the deliverable from a simple release package into a Docker image with a complete environment.
Continuous integration and continuous delivery can integrate many practices together, such as unit testing, software design, task decomposition, main branch development, DevOps, and so on. Therefore, if a company wants to make process improvements, continuous integration is a good starting point.
-
History of continuous integration - Read more: “05 | Continuous Integration: Integration itself should be a part of writing code”
-
Fast feedback - Read more: “24 | Fast Feedback: Why is your company always bad at continuous integration?”
-
Continuous integration, integrating many practices - Read more: “Q&A | Continuous integration, a thread running through many practices”
-
Continuous delivery - Read more: “32 | Continuous Delivery: Is continuous integration enough?”
-
Combining with products: Continuous validation - Read more: “Q&A | Continuous integration, continuous delivery, and then what?”
Test #
Testing is a typical pitfall for programmers, as many mistakenly believe that testing is solely the responsibility of testers. Once we understand the cost of software changes and the importance of built-in quality, we should realize that testing should be integrated into every stage of development. The manifestation of this concept in development is automated testing.
To write good automated tests, you need to first understand the testing pyramid, where different tests have different costs. In order to have more comprehensive and extensive test coverage, we need to write more unit tests.
There are many ways to write tests, and one common practice is Test-Driven Development (TDD). The rhythm of TDD is to write tests first, then write code, and finally refactor: Red-Green-Refactor. The essence of TDD is test-driven design, so writing testable code is a prerequisite.
To excel in TDD, an important prerequisite is task decomposition, breaking them down into very small micro-operations. Learning task decomposition is a prerequisite for becoming an excellent programmer.
To write good tests, we need to understand what good tests look like and avoid common pitfalls. Good tests have a benchmark: A-TRIP.
We not only need to write good unit tests, but also write tests from the perspective of the application. This is acceptance testing. The more systematic way to conduct acceptance testing nowadays is Behavioral-Driven Development (BDD), which allows you to describe tests using business language.
-
Unit testing, automated testing, taco and ice cream model - Related reading: “12 | Is testing also the responsibility of programmers?”
-
Test-Driven Development - Related reading: “13 | Is writing tests first equivalent to Test-Driven Development?” - Related reading: “14 | Work Secrets of Master Programmers”
-
Test exercises - Related reading: “15 | Let’s practice together: Step-by-step task decomposition”
-
Simple tests, common test smells, A-TRIP - Related reading: “16 | Why aren’t your tests good enough?”
-
Acceptance testing, writing good acceptance test cases - Related reading: “32 | Continuous Delivery: Is continuous integration enough?”
-
External system testing, isolating with interfaces - Related reading: “Q&A | How to introduce new concepts in practical work?”
Coding and Design #
Coding and design are the most important part of software development. In my opinion, coding and design are interconnected. Only by thinking clearly can we write good code. Many programmers strive to write good code, but they lack a good standard to measure the quality of the code. Combined with some design principles, I will provide you with a step-by-step guide to writing good code, hoping that you can reach the level of writing code in business language.
Writing code in business language requires a good understanding of software design. When it comes to design, people’s initial impression is “high cohesion and low coupling”, but this is an abstract description that may be too high-level. The SOLID principles are a more practical guiding principle. With these principles as guidance, we can have a better understanding of design patterns.
With the foundation principles, we will know how to divide different code into separate parts, thus creating layers. Good layering can build abstractions, and others can continue to develop on these abstractions. For programmers, building their own core abstractions is the most critical step.
Currently, the best way to build core abstractions is Domain Driven Design (DDD). It brings our thinking to the business level, divides the system into different contexts through strategic design, and guides us to effectively design each domain model through tactical design.
However, no matter how we design, the prerequisite is to use appropriate technology to solve appropriate problems. Do not make technology complex and lead the team into a quagmire.
-
Coding in Business Language - Related reading: “21 | Who is your code written for?”
-
Architecture Design - Related reading: “34 | How did your code become chaotic?”
-
Layering and Abstraction - Related reading: “35 | Always talking about MVC layered architecture, but do you really understand layering?”
-
Business and Technology - Related reading: “36 | Why do some people think they can build another Taobao with 50,000 RMB?”
-
Microservices - Related reading: “37 | Let’s focus on DDD first before talking about microservices, it’s just a deployment form”
Project Preparation #
When starting a project from scratch, a good practice is to have everything prepared. Iteration 0 is such a practice that prepares everything for iterations, from requirements to technology. By doing sufficient preparation before starting the project, you will appear calm and composed. In terms of technology, the most important preparation work for iteration 0 is to build a script, which serves as the foundation for many subsequent tasks, such as continuous integration.
-
Iteration 0, laying the groundwork - Relevant reading: “10 | Iteration 0: What Should You Prepare Before Starting Development?”
-
Build script, enabling automation from the very beginning of the project - Relevant reading: “30 | What Should a Good Project Automation Look Like?”
Other Best Practices #
In addition to the best practices discussed at length, we also mentioned many other different best practices.
Definition of Done (DoD) #
The Definition of Done (DoD) is a practice that ensures a common understanding among all parties involved. It is a checklist composed of individual criteria that are actually verifiable. With the DoD, there are only two states for a task: done and not done.
- Definition of Done, DoD - Related reading: “03 | The Value of DoD: Why Are They Still Unsatisfied When You’ve Completed the Work?”
Daily Stand-up Meeting #
A daily stand-up meeting is a lightweight form of meeting used to synchronize the day’s activities. Generally, there are only three things discussed: what was done yesterday, what will be done today, and any obstacles encountered.
- Stand-up Meeting - Related reading: “22 | Lightweight Communication: Are You Always in Meetings?”
Kanban Board #
A kanban board is a project management tool that visualizes ongoing work. Through the use of a kanban board, many issues with the team’s ongoing work can be identified. Kanban boards can be physical or electronic and can be chosen based on the specific characteristics of one’s project.
- Kanban - Further reading: 23 | Visualization: A More Intuitive Way of Communication
Review Meeting #
A review meeting is a retrospective practice that allows team members to review what happened during a specific period. Review meetings generally consist of three parts: stating the facts, identifying key points, and designing actionable items. However, before the review begins, a safety check is conducted to ensure that everyone can speak the truth freely.
- Review Meeting - Related reading: “25 | What should we do when problems keep arising during development?”
- Safety Check in Review Meetings - Related reading: “Q&A | Continuous Integration: a thread running through many practices”
Refactoring #
Refactoring is a fundamental skill for programmers, breaking the process of code adjustment into several separate “refactoring” actions that can be performed step by step. The premise of refactoring is to identify the code’s “smells” or bad smells. To ensure that the behavior of the code remains unchanged, testing should be used in conjunction with refactoring. The direction of refactoring is to refactor to patterns. The best practice for refactoring is to work in tandem with the process of writing code, and the best approach is to use test-driven development.
-
Refactoring - Related Reading: “Extra Helpings | Do You Really Understand Refactoring?”
-
Refactoring in Test-Driven Development - Related Reading: “13 | Is Writing Tests First the Same as Test-Driven Development?”
Branch Development #
Branch development model is a problem that every team has to face. There are two common branch models in the industry, one is the trunk-based development model, and the other is the branch development model. Branch development model is intuitive, but not the best practice. The main branch development model is the best pattern when combined with other practices, but it also requires developers to have good development habits. If developing multiple features in parallel, consider using Feature Toggle and Branch by Abstraction.
-
Branch Development - Related reading: Master Programmer’s Work Secrets
-
Feature Toggle and Branch by Abstraction - Related reading: How to Break Down a Technical Task You Don’t Understand
Fail Fast #
Fail Fast is an important programming principle: when encountering a problem, report an error as soon as possible. Don’t try to accommodate strange problems in order to build a robust system, allowing bugs to hide.
- Fail Fast - Related Reading: “27 | Exposing Problems Early: Why Are You Always Blamed?”
Thank you for reading. If you find this article helpful, feel free to share it with your friends.