Overall Review of Best Practices

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

Thank you for reading. If you find this article helpful, feel free to share it with your friends.