© Giuliana Carullo 2020
G. CarulloImplementing Effective Code Reviewshttps://doi.org/10.1007/978-1-4842-6162-0_6

6. From Scratch

Giuliana Carullo1 
(1)
Dublin, Ireland
 

You see, but you do not observe. The distinction is clear.

—Sherlock Holmes in Sir Arthur Conan Doyle’s “A Scandal in Bohemia” (1891)

Now that you know what to look for during a review, let’s talk about what to do the moment you start reviewing the code, the architecture, and, equally important, the overall design and the understanding of the problem. Looking at the problem and its high-level requirements is important both before starting to write any code and during development time to ensure the code is scaling and growing in the direction it is meant to.

Hence, this chapter will explore some of the important collateral aspects to look at as regards the overall software design and its requirements.

Note

If you are developing a software and you suddenly come to realize that the system is not performing or acting as expected, please, resist the urge of rewriting the entire code altogether. More likely than not, the work of many developers has been put into that code and not all of it is bad and not responding to an actual need. The only option for completely throwing away a fairly big portion of code and rewriting it in its entirety is if those developers who worked on it went 100% bananas and understood nothing, which is very, very unlikely to happen.

Problem Statement

Uh, Houston, we’ve had a problem.

—Jack Swigert, Apollo 13 Technical Air-to-Ground Voice Transcription (1970)

One of the biggest issues in software design and implementation is when the problem that needs to be solved is not completely and clearly defined. If this happens, several knock-on effects happen.
  • How is the team supposed to write code if the goal and scope of the problem is not clearly defined?

  • Unclear problem statements also lead to unsuccessful tests and code reviews. Indeed, how can you check for correctness (test) and cleanness (code reviews) of the code if you don’t have a clear problem in mind that has been solved with a given piece of code?

  • If you don’t know what the project is supposed to do, how can you define whether or not a project or feature is done? By done, I mean done-done. Not well I coded something.

So, make sure you have a clearly defined problem statement. A clear problem statement ensures common understanding of the solutions to the problem.

A word of caution, done-done does not imply that a problem needs to be sorted in its entirety right away. Incremental solutions are gold for building the right solution, for progress, and for gathering feedback during the development process. However, the end goal and what (i.e., the scope) needs to be achieved in every increment should be clear.

Consider, for example, a car. Ideally, a company might want to provide different versions for a broad brand acquisition: manual and automatic shift, diesel or electric cars.

A car already takes a lot of increments to be assembled: building wheels, engines, and brakes, you name it. Trying to build all possible versions before even starting releasing a simple diesel manual super-basic car will make the company basically file for bankruptcy: it takes a lot of time, and you might end up with producing several variations of a car that customers do not like. What if all customers like a car with red wheels only? Wouldn’t it be easier to have feedback after you built the first version (e.g., usable, safe) of the wheel? Fixing the wheel at this stage helps later in the process. Indeed, designing a single wheel and getting feedback and adoption before moving to other components avoids several issues like having produced 1,000 fully functioning cars to only then figure that you need to change wheels to all of them.

The same reasoning applies to the development process.

Is This Right?

Does the overall solution actually solve the problem? Looks trivial, but it is not. It might be easy enough to not have a clear plan of action to solve the real problem. Always have a clear view of the solution you want to achieve in the end, and carefully plan in advance how to break down everything to be there, on time.

If you are using lean methodologies, always have a clear minimum viable product (MVP).

Minimum Viable Product

A minimum viable product is the smallest set of requirements and relative implementation that needs to be satisfied to start progressing toward the ultimate project goal, while providing a finite, usable functionality.

A word of caution is needed here anyway. Figure 6-1 shows how to correctly implement MVP iterations. Please, do not just ship functionalities. Always consider a nice slice up to the top of the pyramid. Indeed, instead of focusing on each layer bottom up (e.g., all functionalities first in the left pyramid), always consider each iteration (right pyramid):
  • A piece of functionality

  • Any reliability level that the small functionality you implemented needs

  • Relevant usability

  • The design on the smaller functionality implemented and how it fits in the broader view

../images/485619_1_En_6_Chapter/485619_1_En_6_Fig1_HTML.jpg
Figure 6-1

MVP dos and don’ts

Back to our example of building a car. While the pyramid on the left consists of building a possibly not tested basic car, the right one would build one piece at the time. Again, the wheel
  • Is a piece of functionality.

  • Needs to be reliable and safe to use.

  • Must be usable. For example, a functioning and reliable wheel that does not fit the overall size of the vehicle is not really usable.

  • And, as discussed, our clients really love red wheels. We have to be able to gather feedback and implement it sooner rather than later.

Have order, not entropy, moving each and every time a step closer to the goal: the entire software, clean and with all the right requirements and design executed.

Requirements

In this section, we describe the main requirements that need to be taken into account to understand whether or not we are solving the right problem in the correct manner.

Requirements are functional (i.e., what do we solve) and nonfunctional (i.e., how do we solve it). Even if they are high level and implementation independent, a review process is needed to ensure we are reaching the desired goal.

Since we are focusing on good code, in the following, we will expand our previous discussion on nonfunctional requirements, addressing it, however, from a higher-level perspective rather than implementation-specific point of view.

FURPS+

A common definition of nonfunctional requirements can be summarized by the acronym FURPS+,1 which provides the following categories:
  • Functional: Which includes features, capabilities, and security.

  • Usability: Which includes human factor and human interactions, consistency in interfaces, context help for the user where required, and so on.

  • Reliability: Which includes the impact of failures, how frequent they are and their severity, the recoverability, accuracy, and predictability of the system.

  • Performance: Which includes efficiency, availability, throughput, accuracy, response time, and usage of resources—just to mention some.

  • Supportability: Which includes how easy it is to test, extend, and maintain the system. It also includes other characteristics such as how flexible is the system in terms of adaptation to changes.

The + in the acronym indicates a set of additional requirements:
  • Implementation: Including tools and languages as we will describe later.

  • Interfaces: Imposed by external systems and/or legacy code.

  • Packaging: Including constraints on how the system will actually be delivered.

  • Operations: Including details on how the system will be actually administered once deployed.

  • Legal: Including any legal requirements such as license and regulations.

Note

The ultimate goal of using FURPS+, or any other model for requirements, is to make sure that you are taking a step away from the nitty-gritty details of code and technologies and have a chance to consider what the problem you are trying to solve is.

Validation

Requirements are not only used, as we have seen so far, to validate internal implementation. They are also used to validate that what we offer is in check with clients/users needs and expectations.

The following properties are needed to perform a good validation process:
  • Completeness: Requirements are complete if all possible scenarios (and features) are described.

  • Correctness: Requirements are strictly intended for the contexts needed by the client/end user. No unintended features are described.

  • Consistency: Two or more requirements can’t contradict each other.

  • Unambiguity: A requirement can’t be interpreted in multiple manners.

  • Realistic: The overall system can be implemented within the given constraints.

  • Verifiable: Once implemented, the system can be verified (tested) in a repeatable way.

  • Traceable: Every functionality, or intermediate artifact, can be traced back to its relative requirement.

Note

The ultimate goal of validation is to make sure that the problem you modeled so far is feasible and that it cannot be misinterpreted. Finally, remember, a problem is solved by a project. According to PMBOK, 6th edition, a project is a temporary effort undertaken to provide unique value with a given scope on time and on a budget.2 Validation ensures that you have a project at hand and hence the overall team is ensured progression and completion of the attainment of the requirements and its value.

Technologies

When evaluating if you are solving the right problem, question if the technologies, tools, libraries, and platforms (you name it) you are willing to use are adequate.

Choosing the right technologies comes with some key indicators:
  • Use past experience as a reference, but do not blindly copy paste. Likewise in project management for cost/time estimation, a reference to previously used technologies to solve similar project might be used. However, we should never blindly think that since we used technology X in the past, it suits well the problem on hand.

  • Industry trends might also be a reference. Anyway, just because it is a trend, it does not mean that it fits the specific requirements you have.

  • If the code needs to be portable, scalable, and performing, take these aspects into account.

  • Be open to brainstorming. Even the uttermost skilled person might find beneficial confronting with peers to identify gaps and opportunities.

  • Do not stick with a certain approach just because you are emotionally attached to it.

  • Avoid the when you have a hammer, everything looks like a nail mentality.

What Do You Have? What Do You Need?

When assessing the solution and the technologies you are willing to use to solve a given a problem and how it contributes to the overall software, always assess if the solution fits the problem you are solving.

In almost all scenarios, you will need to cooperate with several other programmers in the team. Assess the core skills both yourself and the team have or lack and how they fit into the overall solution that needs to be implemented. Is the solution feasible? Does the team have some weak points? In such case, work on thinking about the impact of such decisions. As an example:
  • Does an equally good yet more viable solution exist?

  • What is the learning curve of the given solution?

  • What is the impact of the learning curve on the time it will take to develop the solution?

Note

I am totally in for trying something and learning from it, even at the cost of risking failure. Hence, as part of growing as a programmer and as a team, I am not discouraging you from trying different things just because “we always did them in a certain way” or because of any learning curve. Learning is amazing. What I am suggesting is to be mindful about the existence of such potential constraints and to make informed decisions about the solutions you will ultimately strive for. This will make space for better and more productive brainstorming sessions and design with the entire team.

This aspect, between all, also impacts technological choices. For example, you might be setting up the project for failure if you suddenly decide to use a platform that your team is not comfortable (i.e., skilled) with. Evaluating alternatives is the way to go in the short term, as well as starting training others if the wonderful technology might be considered useful for future development. If the business allows so, hire experts in the field to speed up the growth curve.

Warning

I am not discouraging learning or the introduction of new technologies when needed. The key point is to always think about trade-offs (e.g., fit for purpose vs. team knowledge) and the implications that such decisions imply for the broader team.

Processes

The last collateral aspect to consider when reviewing the overall software high-level design is about processes. They should always be
  • Clear

  • Complete

  • Systematic

Most importantly, they should be actionable and aimed at moving forward in the direction of having manageable development. As a personal consideration, I suggest to not mix and match aspects from different methodologies within the same project. Some projects might run better with agile, while others with an iterative or a spiral approach. Always have them clearly defined and stick with them.

Note

I do not mean for you to not try and experiment how to improve processes. If, for example, you figure that agile approaches suit better your development process rather than a waterfall, you should definitely make a switch, learn, and evaluate the improvements obtained. However, strive for long-term consistency.

Approach for Code Reviews

I want to give you an approach template to help you out during design reviews. Always think about reviews as a lifecycle on its own within the SDLC as shown in Figure 6-2.
../images/485619_1_En_6_Chapter/485619_1_En_6_Fig2_HTML.jpg
Figure 6-2

Code reviews lifecycle

The before phase sets the stage for the review and what it will focus on. During is the actual code review phase. It requires some extra steps to be performed to ensure a successful and actionable review. The after phase helps in summarizing the findings of the review and provides enough details to the following prioritization of defects and their removal.

Before You Start

As anticipated, it is really important to apply the same planning concepts and clarity of what code needs to be implemented to code reviews as well. In the following, a set of fields useful to think about before a review can be started:
  • Project name: Project name.

  • Reviewer: Person in charge of performing the review.

  • Technical contact: Person responsible for the project (e.g., gatekeeper).

  • Name of developer(s): All the developers involved in the project.

  • Review scope: Enter the review with a specific scope. Are you reviewing all the components? A subsystem? System of systems? Make it clear and well defined.

  • Review number: Keep track of the number of review iteration performed.

  • Date of review: Date of the review.

  • Date of the previous review: Date of the previous review. I know it might be tough to admit how time went by.

  • Goal of the review: What are the specific objectives you are trying to evaluate? Design options? Fix what’s broken approach? Identify gaps and opportunities for improvement? Changes in requirements (e.g., scalability or performance)?

  • Input documentation: Highlight all the documentation available at the moment of the review, including use cases, scenarios, architecture documentation, and requirements.

In Progress

This phase provides extra steps to be performed during reviews. Likewise you would document the code (do you?) as we will discuss in Chapter 8, it is critical, for analogous reasons, to not rush the review process and take some time to document your findings step by step. Specifically, for each portion of code under review, always document
  • Number of defects: Number of the issues found with the review.

  • Impact: Always rank the impact a defect is having on the overall project’s quality (e.g., minor, medium, high, critical). This will help you out after the review to schedule improvement actions.

After

This is a very critical step, especially for broad reviews like a design one. Always consider to
  • Provide more details for the improvements needed.

  • Provide trade-offs and suggestions when possible.

Completing the review with these last steps will better support the team in doing the required adjustment.

After all this documentation, indeed, better and more informed decisions can be made on how to prioritize the resolution of defects and how to keep up with new code in development while acting upon the findings of code reviews.

Heads Up

Chapter 11 will wrap up both the review and the software development lifecycles together.

Summary

In this chapter, we went a step higher in the abstraction of a problem and relative review. Specifically, we considered how to look at a problem and relative requirements to ensure that
  1. 1.

    You are solving the right problem.

     
  2. 2.

    All constraints and ultimate goal are clear, not ambiguous and feasible.

     
  3. 3.

    Technological and process choices speed up and maximize the effort toward success, instead of hindering it.

     

The main takeaway is to not think about reviews only at development time (e.g., with peer reviews). Embed them at the very early stages of the SDLC. A good start ensures a successful end.

In the next chapter, we will start considering some general guidelines that can and needs to be implemented in any type of code review. Specifically, we will introduce conventions for data and naming.

Further Reading

If you are intrigued about properly thinking about general problems and the frameworks used in project management, definitely read PMI’s PMBOK Guide. Some concepts and flows are very specific to the art of management, of course. But having at least a quick glance at it will help in having a well-structured approach on how to think about the development process and the phases every project should go through.

Code Review Checklist

  1. 1.

    Does the overall design meet the requirements?

     
  2. 2.

    Is the design realistic and feasible in terms of time needed to be implemented (especially in initial phases of development)?

     
  3. 3.

    Are interfaces well suited to deal with both internal and external interactions?

     
  4. 4.

    Are design principles agreed, shared, and cohesive?

     
  5. 5.

    Is the problem statement properly defined?

     
  6. 6.

    Is the design actually solving the issues within the problem statement?

     
  7. 7.

    Is the FURPS+ model (or similar) taken into account?

     
  8. 8.

    Is usability (end-user perspective) considered?

     
  9. 9.

    Is reliability considered?

     
  10. 10.

    Are performances properly described at high level?

     
  11. 11.

    Is supportability with all its facets considered?

     
  12. 12.

    Are operational requirements defined and met?

     
  13. 13.

    Are packaging constraints defined and met? This includes how the code is supposed to be released in production.

     
  14. 14.

    Are legal requirements considered? This is, for example, the case of code released publicly without a proper consideration of intellectual property and the processes around it. It is also the case of any possible copyright infringement from libraries or data reuse.

     
  15. 15.

    Are requirements complete?

     
  16. 16.

    Are they correct?

     
  17. 17.

    Are requirements consistent?

     
  18. 18.

    Is ambiguity removed from them?

     
  19. 19.

    Is the specification realistic?

     
  20. 20.

    Is it verifiable?

     
  21. 21.

    Can be requirements traced back to their relative functionalities?

     
  22. 22.

    Are technologies, platforms, languages, libraries, and tools adequate?

     
  23. 23.

    Does the team have the expertise required to advance the project?

     
  24. 24.

    Are the processes in place complete and actually manageable?

     
  25. 25.

    Is the definition of done appropriate?

     
  26. 26.

    Is the minimum viable product (MVP) clearly defined?

     
  27. 27.

    Is MVP properly defined (i.e., not only functionalities)?

     
  28. 28.

    Does the design show signs of serial hammering?

     
  29. 29.

    Have industry trends and previous experience been thoughtfully considered?

     
  30. 30.

    Is the team skilled based on the project requirements and technologies?

     
  31. 31.

    Is training needed?

     
  32. 32.

    Does the team have the necessary skills?

     
  33. 33.

    What is the impact of any learning curve to the execution of the project?

     
  34. 34.

    Are findings from the review process properly documented?

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.239.46