# Table of Contents - [Introduction | Clean code](#introduction-clean-code) - [What Is Clean Code? | Clean code](#what-is-clean-code-clean-code) - [How to write clean code? | Clean code](#how-to-write-clean-code-clean-code) - [Why is clean code so important? | Clean code](#why-is-clean-code-so-important-clean-code) - [Conventions | Clean code](#conventions-clean-code) - [Meaningful Names | Clean code](#meaningful-names-clean-code) - [Functions | Clean code](#functions-clean-code) - [Classes | Clean code](#classes-clean-code) - [Comments | Clean code](#comments-clean-code) - [Exception handling best practices | Clean code](#exception-handling-best-practices-clean-code) - [Formatting | Clean code](#formatting-clean-code) - [Unit Tests | Clean code](#unit-tests-clean-code) - [Objects and Data Structures | Clean code](#objects-and-data-structures-clean-code) - [Simple Design Rules | Clean code](#simple-design-rules-clean-code) - [Concurrency | Clean code](#concurrency-clean-code) - [Code Smells | Clean code](#code-smells-clean-code) - [Write Short Units of Code | Clean code](#write-short-units-of-code-clean-code) - [Keep Unit Interfaces Small | Clean code](#keep-unit-interfaces-small-clean-code) - [Write Code Once | Clean code](#write-code-once-clean-code) - [Error Handling | Clean code](#error-handling-clean-code) - [Write Clean Code | Clean code](#write-clean-code-clean-code) - [Automate Tests | Clean code](#automate-tests-clean-code) - [YAGNI Principle | Clean code](#yagni-principle-clean-code) - [Fail Fast principle | Clean code](#fail-fast-principle-clean-code) - [Hollywood Principle | Clean code](#hollywood-principle-clean-code) - [DRY Principle | Clean code](#dry-principle-clean-code) - [Library vs Framework | Clean code](#library-vs-framework-clean-code) - [Write Simple Units of Code | Clean code](#write-simple-units-of-code-clean-code) - [Coupling and Cohesion | Clean code](#coupling-and-cohesion-clean-code) - [LoD Principle | Clean code](#lod-principle-clean-code) - [Technical Dept | Clean code](#technical-dept-clean-code) - [How to learn software Design and Architecture - Roadmap | Clean code](#how-to-learn-software-design-and-architecture-roadmap-clean-code) - [Building an AOP framework | Clean code](#building-an-aop-framework-clean-code) - [OOP Design Pattern | Clean code](#oop-design-pattern-clean-code) - [AOP - Aspect-Oriented Programming | Clean code](#aop-aspect-oriented-programming-clean-code) - [SRP - Single Responsibility Principle | Clean code](#srp-single-responsibility-principle-clean-code) - [SOLID Principle | Clean code](#solid-principle-clean-code) - [OCP - Open-Closed Principle | Clean code](#ocp-open-closed-principle-clean-code) - [LSP - Liskov Substitution Principle | Clean code](#lsp-liskov-substitution-principle-clean-code) - [ISP - Interface Segregation Principle | Clean code](#isp-interface-segregation-principle-clean-code) - [DIP - Dependency Inversion Principle | Clean code](#dip-dependency-inversion-principle-clean-code) - [Microservcies | Clean code](#microservcies-clean-code) - [Defining the scope of a microservice | Clean code](#defining-the-scope-of-a-microservice-clean-code) - [Step-by-Step: How to Identify Over-Scoped Microservices | Clean code](#step-by-step-how-to-identify-over-scoped-microservices-clean-code) - [Benefits of Grouping or Consolidating Microservices | Clean code](#benefits-of-grouping-or-consolidating-microservices-clean-code) - [A practical step-by-step plan to consolidate microservice | Clean code](#a-practical-step-by-step-plan-to-consolidate-microservice-clean-code) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Meaningful Names | Clean code](#meaningful-names-clean-code) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [SOLID Principle | Clean code](#solid-principle-clean-code) - [Write Short Units of Code | Clean code](#write-short-units-of-code-clean-code) --- # Introduction | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/overview/intro.md) . Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to be that way. Writing clean code is what you must do in order to call yourself a professional. There is no reasonable excuse for doing anything less than your best. The code is clean if it can be understood easily by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility, and maintainability. About the Clean code book[](https://gpcoder.gitbook.io/clean-code#about-the-clean-code-book) --------------------------------------------------------------------------------------------- You are reading this book for two reasons. First, you are a programmer. Second, you want to be a better programmer. Good. We need better programmers. _**Clean Code**_ is divided into three parts: * The first describes the principles, patterns, and practices of writing clean code. * The second part consists of several case studies of increasing complexity. Each case study is an exercise in cleaning up code—of transforming a code base that has some problems into one that is sound and efficient. * The third part is the payoff: a single chapter containing a list of heuristics and “smells” gathered while creating the case studies. The result is a knowledge base that describes the way we think when we write, read, and clean code. Readers will come away from this book understanding: * How to tell the difference between good and bad code. * How to write good code and how to transform bad code into good code. * How to create good names, good functions, good objects, and good classes. * How to format code for maximum readability. * How to implement complete error handling without obscuring code logic. * How to unit test and practice test-driven development. About the gitbook[](https://gpcoder.gitbook.io/clean-code#about-the-gitbook) ----------------------------------------------------------------------------- This is my **summary** of the [**Clean Code**](https://learning.oreilly.com/library/view/clean-code-a/9780136083238/) book - A Handbook of Agile Software Craftsmanship by **Robert C. Martin** (Uncle Bob). In the book, Robert C. Martin introduces the **disciplines, techniques, tools, and practices of** **true software craftsmanship**. In this Gitbook, I **summarize the key principles and strategies** in the book "Clean Code" and give some examples to make the principles more clear. Also, I summarize some guidelines from the "[Building Maintainable Software](https://learning.oreilly.com/library/view/building-maintainable-software/9781491955987/) " book by **Joost Visser** that helps to write cleaner and more maintainable code. The Clean Code book is mostly written from a Java perspective. About me[](https://gpcoder.gitbook.io/clean-code#about-me) ----------------------------------------------------------- * Linked in: [https://www.linkedin.com/in/gpcoder/](https://www.linkedin.com/in/gpcoder/) * GitHub: [https://github.com/gpcodervn](https://github.com/gpcodervn) * Blog: [http://gpcoder.com/](http://gpcoder.com/) References[](https://gpcoder.gitbook.io/clean-code#references) --------------------------------------------------------------- * [Clean Code: A Handbook of Agile Software Craftsmanship](https://learning.oreilly.com/library/view/clean-code-a/9780136083238/) * [Building Maintainable Software](https://learning.oreilly.com/library/view/building-maintainable-software/9781491955987/) [NextWhy is clean code so important?](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important) Last updated 1 year ago --- # What Is Clean Code? | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/overview/what-is-clean-code.md) . There are probably as many definitions as there are programmers. I choose one of them that is the most valuable to me. > _Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. It provides one way rather than many ways for doing one thing. It has minimal dependencies, which are explicitly defined, and provides a clear and minimal API. Code should be literate since depending on the language, not all necessary information can be expressed clearly in code alone._ > > \-- “Big” Dave Thomas, founder of OTI, godfather of the Eclipse strategy -- **The code is clean if it can be understood easily by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility, and maintainability.** ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252FgN5ARWeSqnzyaO3WW7Hh%252Fimage.png%3Falt%3Dmedia%26token%3D97b0c950-2be0-41f2-9670-0c7d334f404b&width=768&dpr=3&quality=100&sign=df296a8532044fbeb2899aedf54be435&sv=3) ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252FuxUkgPfhJewXAqsbkH7V%252Fimage.png%3Falt%3Dmedia%26token%3D4d5bc77d-afeb-43e7-9ae4-c5971712436c&width=768&dpr=3&quality=100&sign=61594cd191904fbfd3ef58dc0594c276&sv=3) [PreviousWhy is clean code so important?](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important) [NextHow to write clean code?](https://gpcoder.gitbook.io/clean-code/overview/how-to-write-clean-code) Last updated 3 years ago --- # How to write clean code? | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/overview/how-to-write-clean-code.md) . Writing clean code is a lot like painting a picture. Most of us know when a picture is painted well or badly. But being able to recognize good art from bad does not mean that we know how to paint. So too being able to recognize clean code from dirty code does not mean that we know how to write clean code! A programmer who writes clean code is an artist who can take a blank screen through a series of transformations until it is an elegantly coded system. There are two parts to learning clean code: **knowledge** and **work**: * You must have knowledge of the principles, patterns, practices, and experience that a craftsman knows. * You also have to grind those skills through hard work and practice. Clean code consists of: * Your developer mindset (empathy, craftsmanship, growth mindset, design thinking) * Your coding conventions (naming things, refactoring, testing, etc) * Your skills & knowledge (of patterns, principles, and how to avoid code smells and anti-patterns) Follow clean code principles[](https://gpcoder.gitbook.io/clean-code/overview/how-to-write-clean-code#follow-clean-code-principles) ------------------------------------------------------------------------------------------------------------------------------------ The most important principles to keep our code clean: * [**SOLID**](https://gpcoder.gitbook.io/clean-code/bonus/solid-principle) **\***: **S**ingle Responsibility Principle (SRP), **O**pen-Closed Principle (OCP), **L**iskov substitution principle (LSP), **I**nterface Segregation Principle (ISP), and **D**ependency Inversion Principle (DIP). * Design principles, this is a topic in itself but mastering the **SRP** will already help us in a tremendous way. * KISS (**K**eep **I**t **S**imple **S**tupid): * Simplicity should be a key goal in design, and unnecessary complexity should be avoided. * The question to ask when you're writing code is "can this be written in a simpler way?” * [DRY](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) (**D**on't **R**epeat **Y**ourself): * Each piece of knowledge must have a unique, unambiguous, authoritative representation in a system. * When the DRY principle is applied successfully, a modification of any single element of a system does not require a change in other logically unrelated elements. * [YAGNI](https://gpcoder.gitbook.io/clean-code/bonus/yagni-principle) (**Y**ou **A**ren't **G**onna **N**eed **I**t): * A developer should not add functionality unless deemed necessary. * Always implement things when you actually need them, never when you just foresee that you need them. * Boy-scout rule: Always leave the code better than you found it. * Don't reinvent the wheel: There are already tons of libraries that can help solve our problems so we don't have to do it again. * [Design Patterns](https://gpcoder.gitbook.io/clean-code/bonus/oop-design-pattern) : There are tons of design patterns out there, and some people already resolved our problem. * Coding Standards/Conventions: So we don't end up having different codes with different coding styles among our team. Create the habits of clean coding[](https://gpcoder.gitbook.io/clean-code/overview/how-to-write-clean-code#create-the-habits-of-clean-coding) ---------------------------------------------------------------------------------------------------------------------------------------------- * Follow standard conventions. Keep them clear and concise. * Be consistent. Use the same names in similar functions (Get vs Fetch, Set vs Update, Add vs Append). * [If you copy-paste code multiple times, consider better ways to make your code more efficient](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once) . * If you feel that a piece of code is too complex or not the best way to do it, then stop! Give yourself a few moments to rethink the process and see if you can come up with a better way. * Review with colleagues. Compare their code with yours, and be open to suggestions. * Self-review code/ Peer review code. * Always find the root cause. Always look for the root cause of a problem. * Refer to the key principles of the Clean Code book. * [When writing a new unit, never let it grow beyond 15 lines of code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code) . * [Limit the number of branch points per unit to 4](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-simple-units-of-code) . * [Limit the number of parameters per unit to at most 4](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small) . [PreviousWhat Is Clean Code?](https://gpcoder.gitbook.io/clean-code/overview/what-is-clean-code) [NextConventions](https://gpcoder.gitbook.io/clean-code/overview/conventions) Last updated 3 years ago --- # Why is clean code so important? | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important.md) . There will be code[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#there-will-be-code) ----------------------------------------------------------------------------------------------------------------------- Remember that code is really the language in which we ultimately express the requirements. We may create languages that are closer to the requirements. We may create tools that help us parse and assemble those requirements into formal structures. But we will never eliminate necessary precision—so there will always be code. Bad code that brought the company down[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#bad-code-that-brought-the-company-down) --------------------------------------------------------------------------------------------------------------------------------------------------------------- Have you ever worked on a codebase where it felt like "the more code I add, the more complex it gets"? Adding more and more features, the code got worse and worse until they simply could not manage it any longer. _It was the bad code that brought the company down._ We spend most of our time reading code[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#we-spend-most-of-our-time-reading-code) --------------------------------------------------------------------------------------------------------------------------------------------------------------- Programmers think they spend most of their time writing code when, in reality, they spend a lot more time reading and reviewing code, documenting, figuring out what to do and how to do it, debugging, etc. When we optimize something, we start with what is easy to change, will take less time to modify, and will have the most impact. Code feeds on our time[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#code-feeds-on-our-time) ------------------------------------------------------------------------------------------------------------------------------- Another big misconception is that the code we type is the core value of our product, when in fact, the real value of the product is its' final, working state. The code is just a medium we use to translate an idea into a thing with which we can interact. With every line of code, we add to an application, we take the risk of adding bugs, doing more testing, and failing. So the code actually feeds on our time. The Total Cost of Owning a Mess[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#the-total-cost-of-owning-a-mess) ------------------------------------------------------------------------------------------------------------------------------------------------- As the mess builds, the productivity of the team continues to decrease, asymptotically approaching zero. The more code, the higher complexity. The higher complexity, the more expensive. ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252Ffcgdzy5mFJQ5ZDBz7Naw%252Fimage.png%3Falt%3Dmedia%26token%3D18bcb53b-3c68-4bf5-be39-5a7b2dbbf8d2&width=768&dpr=3&quality=100&sign=3eb328b2139968700dec117c4764d86e&sv=3) Technical debt: it’s the result of prioritizing speedy delivery over perfect code. Read more [Technical Dept](https://gpcoder.gitbook.io/clean-code/bonus/technical-dept) ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252FcU8z0s4RYLP5uysoEMAO%252Fimage.png%3Falt%3Dmedia%26token%3D24e19614-89b5-4b1a-b7e8-4fe0197a3c19&width=768&dpr=3&quality=100&sign=69c4239796b4dddb847842b079a8b757&sv=3) The Grand Redesign in the Sky: expend the resources on a whole new redesign of the project. Shit Rolls Downhill[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#shit-rolls-downhill) ------------------------------------------------------------------------------------------------------------------------- As developers, we are on the front line. Bad code will just roll downhill and negatively affect every other aspect of the product (Infras team, operation team, ...) ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252FkSFXjabVlM8BrqWJKbzu%252Fimage.png%3Falt%3Dmedia%26token%3D16ce1063-cbbd-4924-82e1-246ac3bd4d59&width=768&dpr=3&quality=100&sign=c9e6ceead4078e6be99f081d9a7bbe81&sv=3) Miss the deadline[](https://gpcoder.gitbook.io/clean-code/overview/why-is-clean-code-so-important#miss-the-deadline) --------------------------------------------------------------------------------------------------------------------- We have lots of explanations for it: * Change requirements * Deadline * Not enough experience * Attitude The mess will slow you down instantly, and will force you to miss the deadline. The _only_ way to make the deadline—the only way to go fast—is to keep the code as clean as possible at all times. If you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read. [PreviousIntroduction](https://gpcoder.gitbook.io/clean-code) [NextWhat Is Clean Code?](https://gpcoder.gitbook.io/clean-code/overview/what-is-clean-code) Last updated 3 years ago --- # Conventions | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/overview/conventions.md) . In this gitbook, you will find two types of text boxes that distinguish between good and bad practices. Bad practices appear in a box like this. Good practices appear like this. Occasionally you will find a blue box of comments. Important comments appear in a blue box. [PreviousHow to write clean code?](https://gpcoder.gitbook.io/clean-code/overview/how-to-write-clean-code) [NextMeaningful Names](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names) Last updated 4 years ago --- # Meaningful Names | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names.md) . Use intention-revealing names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#use-intention-revealing-names) ------------------------------------------------------------------------------------------------------------------------------------------------------- The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent. What does the list represent? Copy List theList; // The list of users Copy List users; Avoid disinformation[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-disinformation) ------------------------------------------------------------------------------------------------------------------------------------- Programmers must avoid leaving false clues that obscure the meaning of code. We should avoid words whose entrenched meanings vary from our intended meaning. Of what type is the account list? String? Array of strings? Array of objects? accountList accounts The lower-case `L` or uppercase `O` ? or they look almost entirely like the constants one and zero, respectively. Copy int a = l; if ( O == l ) { a = O1; } else { l = 01; } Avoid similar shapes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-similar-shapes) ------------------------------------------------------------------------------------------------------------------------------------- How long does it take to spot the subtle difference? class ControllerForEfficientHandlingOfStrings class ControllerForEfficientStorageOfStrings Make meaningful distinctions[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#make-meaningful-distinctions) ----------------------------------------------------------------------------------------------------------------------------------------------------- How do these different names convey different meanings? class Product class ProductInfo class ProductData Use pronounceable names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#use-pronounceable-names) ------------------------------------------------------------------------------------------------------------------------------------------- How can you discuss it without sounding like an idiot? class CstmrRcrd class CustomerRecord Use Searchable Names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#use-searchable-names) ------------------------------------------------------------------------------------------------------------------------------------- Single-letter names and numeric constants have a particular problem in that they are not easy to locate across a body of text. What is the number `34` , `4` or `5`? Copy for (int j = 0; j < 34; j++) { s += (t[j] * 4) / 5; } Copy private static final int REAL_DAYS_PER_IDEAL_DAY = 4; private static final int WORK_DAYS_PER_WEEK = 5; private static final int NUMBER_OF_TASKS = 34; public static int sumOfRealTaskWeeks(int[] taskEstimates) { int sum = 0; for (int j = 0; j < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimates[j] * REAL_DAYS_PER_IDEAL_DAY; int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } return sum; } Avoid Encodings[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-encodings) --------------------------------------------------------------------------------------------------------------------------- It hardly seems reasonable to require each new employee to learn yet another encoding “language” in addition to learning the (usually considerable) body of code that they’ll be working in. void tạoNgườiDùng() void createUser() Member Prefixes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#member-prefixes) --------------------------------------------------------------------------------------------------------------------------- Don’t need to prefix member variables with m\_ anymore. Your classes and functions should be small enough that you don’t need them. Copy class Part { private String m_dsc; // The textual description void setName(String name) { m_dsc = name; } } Copy class Part { private String description; void setDescription(String description) { this.description = description; } } Interfaces and Implementations[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#interfaces-and-implementations) --------------------------------------------------------------------------------------------------------------------------------------------------------- interface IShapeFactory {} class ShapeFactory implements IShapeFactory {} interface ShapeFactory {} class ShapeFactorImpl implements ShapeFactory {} or interface ShapeFactory {} class CShapeFactor implements ShapeFactory {} I don’t want my users knowing that I’m handing them an interface. I just want them to know that it’s a ShapeFactory. So if I must encode either the interface or the implementation, I choose the implementation. Avoid Mental Mapping[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-mental-mapping) ------------------------------------------------------------------------------------------------------------------------------------- This is a problem with single-letter variable names. Certainly, a loop counter may be named `i` or `j` or `k` (though never `l`!) if its scope is very small and no other names can conflict with it. This is because those single-letter names for loop counters are traditional. However, in most other contexts a single-letter name is a poor choice. Copy List l = getStudents(); for (Student i : l) { i.doSomething(); } Copy List students = getStudents(); for (Student student : students) { student.doSomething(); } **Class Names**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#ch2lev1sec9) ----------------------------------------------------------------------------------------------------------------------- Classes and objects should have noun or noun phrase names. class Customer class WikiPage class Account Avoid words (in the name of a class)[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-words-in-the-name-of-a-class) ------------------------------------------------------------------------------------------------------------------------------------------------------------------- Manager Processor Data Info Core Helper Common Utilities JwtHelper MediaType { public static final String APPLICATION\_PDF\_VALUE = "application/pdf"; public static final String IMAGE\_JPEG\_VALUE = "image/jpeg"; public static final String APPLICATION\_JSON\_VALUE = "application/json"; } HttpMethod {GET, POST, PUT} HttpStatus {CREATED, ACCEPTED, NO\_CONTENT} StringUtils RandomUtils TagUtils The class name means the class does more than one thing. It doesn't say anything specific **Method Names**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#ch2lev1sec10) ------------------------------------------------------------------------------------------------------------------------- Methods should have verb or verb phrase names like `postPayment`, `deletePage`, or `save`. Accessors, mutators, and predicates should be named for their value and prefixed with `get`, `set`, and `is` according to the **J**avaBean standard. void postPayment() void deletePage() void save() Prefer methods to constructors overloaded[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#prefer-methods-to-constructors-overloaded) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- When constructors are overloaded, use static factory methods or builders with names that describe the arguments. Copy class User { private String firstname; private String lastName; private int age; public User() { } public User(String firstname) { this.firstname = firstname; } public User(String firstname, String lastName) { this.firstname = firstname; this.lastName = lastName; } public User(String firstname, String lastName, int age) { this.firstname = firstname; this.lastName = lastName; this.age = age; } } User user1 = new User("GP"); User user2 = new User("GP", "Coder"); User user3 = new User("GP", "Coder", 32); Copy class User { private String firstname; private String lastName; private int age; public static class UserBuilder { private User user; public UserBuilder withFirstName(String firstName) { user.firstname = firstName; return this; } public UserBuilder withLastName(String lastName) { user.lastName = lastName; return this; } public UserBuilder withAge(int age) { user.age = age; return this; } public User build() { return user; } } } User user1 = new User.UserBuilder() .withFirstName("GP") .withLastName("Coder") .withAge(32) .build(); Adjust the length of a name to the size of its scope[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#adjust-the-length-of-a-name-to-the-size-of-its-scope) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Is it obvious outside the class body that WD is an acronym for work days per week? public static final int WD public static final int WORK\_DAYS\_PER\_WEEK If a variable or constant might be seen or used in multiple places in a body of code, it is imperative to give it a search-friendly and meaningful name. Avoid using the same name for different purposes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#avoid-using-the-same-name-for-different-purposes) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- What does add mean? Concate strings? Insert a record in a table? Append a value to the end of an array? function add(value) function concate(value) function insert(value) function append(value) Use Solution Domain Names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#use-solution-domain-names) ----------------------------------------------------------------------------------------------------------------------------------------------- Remember that the people who read your code will be programmers. So go ahead and use computer science (CS) terms, algorithm names, pattern names, math terms, and so forth. The name `AccountVisitor` means a great deal to a programmer who is familiar with the Visitor Pattern. Use problem domain names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#use-problem-domain-names) --------------------------------------------------------------------------------------------------------------------------------------------- What does the term "document" mean in the archives domain? Are photos considered documents? document record Add Meaningful Context[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#add-meaningful-context) ----------------------------------------------------------------------------------------------------------------------------------------- There are a few names which are meaningful in and of themselves—most are not. Instead, you need to place names in context for your reader by enclosing them in well-named classes, functions, or namespaces. When all else fails, then prefixing the name may be necessary as a last resort. What does a comma `,` mean? How to change all of them for a specific context? Copy public static final String COMMA = ","; String extractCountry(String address) { final int COUNTRY_INDEX = 0; return address.split(COMMA)[COUNTRY_INDEX]; } void parseCsv(String csvLine) { String[] parts = csvLine.split(COMMA); } Copy public static final String ADDRESS_SEPARATOR = "," String extractCountry(String address) { final int COUNTRY_INDEX = 0; return address.split(ADDRESS_SEPARATOR)[COUNTRY_INDEX]; } public static final String CSV_SEPARATOR = ","; void parseCsv(String csvLine) { String[] parts = csvLine.split(CSV_SEPARATOR); } Don’t Add Gratuitous Context[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#dont-add-gratuitous-context) ---------------------------------------------------------------------------------------------------------------------------------------------------- package com.gpcoder.entity.obnk; class ObnkConsentEntity {}; class ObnkAdrEntity {}; package com.gpcoder.entity.obnk; class ConsentEntity {}; class AdrEntity {}; Shorter names are generally better than longer ones, so long as they are clear. Add no more context to a name than is necessary. Add context by using prefixes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names#add-context-by-using-prefixes) ------------------------------------------------------------------------------------------------------------------------------------------------------- What does the state represent? Condition or country? state addressState The names `accountAddress` and `customerAddress` are fine names for instances of the class `Address`, but could be poor names for classes. If you need to differentiate between MAC addresses, port addresses, and Web addresses, consider PostalAddress, MAC, and URI. [PreviousConventions](https://gpcoder.gitbook.io/clean-code/overview/conventions) [NextFunctions](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions) Last updated 4 years ago --- # Functions | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions.md) . Small[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#small) ------------------------------------------------------------------------------------------------ The first rule of functions is that they should be small. The second rule of functions is that _they should be smaller than that_. Copy public static List getUserReportDtos() { List users = CsvUtils.read(new File("user.csv"), User.class); List userReportDtos = new ArrayList<>(); if (users != null && !users.isEmpty()) { for (User user : users) { UserReportDto reportDto = UserReportDto.builder() .withName(user.getName()) .withEmail(user.getEmail()) .build; userReportDtos.add(reportDto); } } return userReportDtos; } Copy // First level of abstraction public static List getUserReportDtos() { List users = readUsersFromCsvFile("user.csv"); return mapToUserReportDtos(users); } // Second level of abstraction private List readUsersFromCsvFile(String csvFileName) { return CsvUtils.read(new File(csvFileName), User.class); } // Second level of abstraction private List mapToUserReportDtos(List users) { List userReportDtos = new ArrayList<>(); if (!isValid(users)) { return userReportDtos; } for (User user : users) { UserReportDto reportDto = mapToUserReportDto(user); userReportDtos.add(reportDto); } return userReportDtos; } // Third level of abstraction private boolean isValid(List users) { return users != null && !users.isEmpty(); } // Third level of abstraction private UserReportDto mapToUserReportDto(User user) { return UserReportDto.builder() .withName(user.getName()) .withEmail(user.getEmail()) .build(); } Refer to [Write Short Units of Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code) Do One Thing[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#do-one-thing) -------------------------------------------------------------------------------------------------------------- One way to know that a function is doing more than “one thing” is if you can extract another function from it with a name that is not merely a restatement of its implementation. See examples in the "[Small](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#small) " section. One Level of Abstraction per Function[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#one-level-of-abstraction-per-function) ---------------------------------------------------------------------------------------------------------------------------------------------------------------- In order to make sure our functions are doing “one thing,” we need to make sure that the statements within our function are all at the same level of abstraction. Abstraction is a fundamental concept in OOPS. It talks about hiding the “how” part and only exposing “what” to the outer world. According to SLAP (Single Level of Abstraction Principle), source code inside each method should refer to concepts and mechanisms relevant to just one level of “operational complexity” of your application. Apply refactoring technique "Extract Method". See examples in the "[Small](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#small) " section. Reading Code from Top to Bottom: The Stepdown Rule[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#reading-code-from-top-to-bottom-the-stepdown-rule) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- We want every function to be followed by those at the next level of abstraction so that we can read code from top to bottom. See examples in the "[Small](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#small) " section. Avoid nested structures[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#avoid-nested-structures) ------------------------------------------------------------------------------------------------------------------------------------ Copy public boolean isUserValid(UserDto userDto) { if (userDto != null) { if (userDto.getPassword() != null) { if (userDto.getEmail() != null) { return !userService.isEmailExists(userDto.getEmail()); } } } return false; } Copy public boolean isUserValid(UserDto userDto) { if (userDto == null) { return false; } if (userDto.getPassword() == null) { return false; } if (userDto.getEmail() == null) { return false; } return !userService.isEmailExists(userDto.getEmail()); } Avoid negative conditionals[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#avoid-negative-conditionals) -------------------------------------------------------------------------------------------------------------------------------------------- Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives. Copy if(!isNotEmpty(users)) {} Copy if(isEmpty(users)) {} Switch Statements[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#ch3lev1sec4) ------------------------------------------------------------------------------------------------------------------ It’s hard to make a small `switch` statement. By their nature, `switch` statements always do _N_ things. Unfortunately, we can’t always avoid `switch` statements, but we _can_ make sure that each `switch` statement is buried in a low-level class and is never repeated. We do this, of course, with **polymorphism**. There are several problems with the switch statement. * First, it’s large, and when new enum types are added, it will grow. * Second, it very clearly does more than one thing. * Third, it violates the Single Responsibility Principle (SRP) because there is more than one reason for it to change. * Fourth, it violates the Open Closed Principle (OCP) because it must change whenever new types are added. Copy enum VehicleType { BICYCLE, CAR, AIRPLANE } class Vehicle { String name; VehicleType type; void ride() {} void fly() {} } void perform(Vehicle vehicle) { switch (vehicleType) { case BICYCLE: vehicle.ride(); break; case CAR: vehicle.drive(); break; case AIRPLANE: vehicle.fly(); break; default: break; } } Copy interface VehicleAction { void perform(); } abstract class Vehicle implements VehicleAction { String name; } class Bicycle extends Vehicle { void ride() {} @Override public void perform() { ride(); } } class Car extends Vehicle { void drive() {} @Override public void perform() drive(); } } // App void perform(VehicleAction vehicleAction) { vehicleAction.perform(); } **Use Descriptive Names**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#ch3lev1sec5) -------------------------------------------------------------------------------------------------------------------------- Don’t be afraid to make a name long. A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment. Copy public void createPrd(); // Create a product Copy public void createProduct(); Be consistent in your names. Use the same phrases, nouns, and verbs in the function names you choose for your modules. beforeEach(); afterEach(); beforeAll(); afterAll(); Prefer fewer arguments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#prefer-fewer-arguments) ---------------------------------------------------------------------------------------------------------------------------------- The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway. void createUser(String username, String password, Gender gender, int roleId); Apply refactoring technique "**Replace Method Parameters with Method Object**": When a function seems to need more than two or three arguments, it is likely that some of those arguments ought to be wrapped into a class of their own. Copy void createUser(UserDto userDto) { } class UserDto { private String username; private String password; private Gender gender; private int roleId; } Functions that take variable arguments can be monads, dyads, or even triads. But it would be a mistake to give them more arguments than that. Arguments are even harder from a testing point of view. Imagine the difficulty of writing all the test cases to ensure that all the various combinations of arguments work properly. Sometimes we want to pass a variable number of arguments into a function. Consider to use Argument Lists public String format(String format, Object… args); String.format(”%s worked %.2f hours.”, name, hours); Read more: [Keep Unit Interfaces Small](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small) Avoid flag arguments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#avoid-flag-arguments) ------------------------------------------------------------------------------------------------------------------------------ Function with flag argument does more than one thing. It does one thing if the flag is true and another if the flag is false! Copy public execute(boolean isTestSuite) { if (isSuite) { // do something for suite } else { // do something for single test } } Copy public void executeForTestSuite() { // do something for suite } public void executeForSingleTest() { // do something for single test } Split the method into several independent methods that can be called from the client without the flag. Have No Side Effects[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#have-no-side-effects) ------------------------------------------------------------------------------------------------------------------------------ Side effects are lies. Your function promises to do one thing, but it also does other hidden things. The side effect is the call to update(). The get user function, by its name, says that it gets the user by email. The name does not imply that it updates the last access of the user. Copy public User getUserByEmail(String email) { User user = userRepository.getUserByEmail(email); user.setLastAccess(now()); userRepository.update(user); return user; } Output Arguments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#output-arguments) ---------------------------------------------------------------------------------------------------------------------- Anything that gets modified or mutated but is not returned by the function. An array/object passed to a function, which changes the body of the array or changes the data of the object but does not return it, then it is the output argument. Copy public User createUser(UserDto userDto) { userDto.setRole("ADMIN"); return userRepository.createUser(userDto); } class UserDto { private String email; private String password; private String role; } Output arguments should be avoided. If your function must change the state of something, have it change the state of its owning object. public void appendFooter(StringBuffer report); appendFooter(report); report.appendFooter(); Separate command from query[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#separate-command-from-query) -------------------------------------------------------------------------------------------------------------------------------------------- Functions should either do something or answer something, but not both. public boolean set(String attribute, String value); if (set("username", "gpcoder")) {} if (attributeExists("username")) { setAttribute("username", "gpcoder"); } Prefer exceptions to returning error codes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#prefer-exceptions-to-returning-error-codes) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returning error codes from command functions lead to deeply nested structures and maybe a violation of command query separation. Copy public void sendShutDown() { DeviceHandle handle = getHandle(DEV1); // Check the state of the device if (handle != DeviceHandle.INVALID) { // Save the device status to the record field retrieveDeviceRecord(handle); // If not suspended, shut down if (record.getStatus() != DEVICE_SUSPENDED) { pauseDevice(handle); clearDeviceWorkQueue(handle); closeDevice(handle); } else { logger.log("Device suspended. Unable to shut down"); } } else { logger.log("Invalid handle for: " + DEV1.toString()); } } Copy public void sendShutDown() { try { tryToShutDown(); } catch (DeviceShutDownError e) { logger.log(e); } } private void tryToShutDown() throws DeviceShutDownError { DeviceHandle handle = getHandle(DEV1); DeviceRecord record = retrieveDeviceRecord(handle); pauseDevice(handle); clearDeviceWorkQueue(handle); closeDevice(handle); } private DeviceHandle getHandle(DeviceID deviceID) { throw new DeviceShutDownError("Invalid handle for: " + deviceID); } Another exmaple: Copy public void performLogin(UserDto userDto) { ResponseCode status = login(userDto); switch (status) { case BAD_REQUEST: log.error("Bad request"); break; case USER_NOT_FOUND: log.error("Invalid username or password"); break; case WRONG_PASSWORD: log.error("Invalid username or password"); break; case SUCCESS: log.error("Login success"); redirect(); break; default: log.error("Unknown response"); break; } } public ResponseCode login(UserDto userDto) { if (userDto.getEmail() == null || userDto.getPassword() == null) { return ResponseCode.BAD_REQUEST; } User user = userRepository.get(userDto); if (user == null) { return ResponseCode.USER_NOT_FOUND; } if (notMatchPassword(user.getPassword, userDto.getPassword())) { return ResponseCode.WRONG_PASSWORD; } setUserSession(user); return SUCCESS; } Copy public void performLogin(UserDto userDto) { try { login(userDto); } catch(Exception ex) { log.error(ex.getMessage(), ex); } redirect(); } public void login(UserDto userDto) { if (userDto.getEmail() == null || userDto.getPassword() == null) { throw new BadRequestException("Bad request"); } User user = userRepository.get(userDto); if (user == null) { throw new UserNotFoundException("Invalid username or password"); } if (notMatchPassword(user.getPassword, userDto.getPassword())) { throw new UserNotFoundException("Invalid username or password"); } setUserSession(user); } When you use exceptions rather than error codes, then new exceptions are _derivatives_ of the exception class. They can be added without forcing any recompilation or redeployment. It is better to extract the bodies of the `try` and `catch` blocks out into functions of their own. Put all code inside a try block[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#put-all-code-inside-a-try-block) ---------------------------------------------------------------------------------------------------------------------------------------------------- If the keyword try exists in a function, it should be the very first word in the function and there should be nothing after the catch/finally blocks. Copy public void performLogin(UserDto userDto) { try { login(userDto); } catch(Exception ex) { log.error(ex.getMessage(), ex); throw new BadCredentialExceptoin(); } redirect(); // Should move to try block } Copy public void performLogin(UserDto userDto) { try { login(userDto); redirect(); } catch(Exception ex) { log.error(ex.getMessage(), ex); throw new BadCredentialExceptoin(); } } The DRY principle[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#the-dry-principle) ------------------------------------------------------------------------------------------------------------------------ Refer to [DRY Principle](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) Structured Programming[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#structured-programming) ---------------------------------------------------------------------------------------------------------------------------------- Every block within a function should have one entry and one exit. Following these rules means that there should only be one `return` statement in a function, no `break` or `continue` statements in a loop, and never, _ever,_ any `goto` statements. If you keep your functions small, then the occasional multiple `return`, `break`, or `continue` the statement does no harm and can sometimes even be more expressive than the single-entry, single-exit rule. On the other hand, `goto` only makes sense in large functions, so it should be avoided. Write, test, and refine[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions#write-test-and-refine) ---------------------------------------------------------------------------------------------------------------------------------- > When I write functions, they come out long and complicated. But I also have unit tests that cover every one of those clumsy lines of code. So then I massage and refine that code, splitting out functions, changing names, eliminating duplication. > > — Robert C. Martin [PreviousMeaningful Names](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names) [NextClasses](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes) Last updated 3 years ago --- # Classes | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes.md) . **Class Organization**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#ch10lev1sec1) ---------------------------------------------------------------------------------------------------------------------- Following the standard Java convention**.** Copy package com.gpcoder; import java.time.LocalDate; import java.time.LocalDateTime; /** * Class documentation comment... */ public class ClassOrganization { /** * Class ( static) variables */ public static String PUBLIC_STATIC_VAR = ""; protected static String PROTECTED_STATIC_VAR = ""; static String DEFAULT_STATIC_VAR = ""; private static String PRIVATE_STATIC_VAR = ""; /** * Instance variables */ public String publicStaticVar = ""; protected String protectedStaticVar = ""; String defaultStaticVar = ""; private String privateStaticVar = ""; /** * Constructors */ public ClassOrganization() { } /** * Methods *

* These methods should be grouped by functionality rather than by scope or accessibility. * For example, a private class method can be in between two public instance methods. * The goal is to make reading and understanding the code easier. */ public void doSomething1() { task1(); task2(); } private void task1() { } private void task2() { } public void doSomething2() { task3(); } private void task3() { } } Refer to: [https://www.oracle.com/java/technologies/javase/codeconventions-fileorganization.html](https://www.oracle.com/java/technologies/javase/codeconventions-fileorganization.html) **Encapsulation**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#encapsulation) ------------------------------------------------------------------------------------------------------------------ We like to keep our variables and utility functions private, but we’re not fanatic about it. Sometimes we need to make a variable or utility function protected so that it can be accessed by a test. **Classes Should Be Small!**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#ch10lev1sec2) ---------------------------------------------------------------------------------------------------------------------------- The first rule of classes is that they should be small. The second rule of classes is that they should be smaller than that. The name of a class should describe what responsibilities it fulfills. In fact, naming is probably the first way of helping determine class size. If we cannot derive a concise name for a class, then it’s likely too large. The more ambiguous the class name, the more likely it has too many responsibilities. For example, class names including weasel words like `Processor` or `Manager` or `Super` often hint at unfortunate aggregation of responsibilities. Copy public final class CommonUtils { private CommonUtils() { } public static String toJson() { } public static T fromJson(String json, Class tClass) { } public static String toJson(Object obj) { } public static String concat(String delimiter, String... str) { } public static boolean isNotBlank(String str) { } public static List subList(List list, int start, int numberOfElement) { } public static String randomString(int length) { } } Copy public final class JsonUtils { private JsonUtils() { } public static String toJson() { } public static T fromJson(String json, Class tClass) { } public static String toJson(Object obj) { } } public final class StringUtils { private StringUtils() { } public static String concat(String delimiter, String... str) { } public static boolean isNotBlank(String str) { } } public final class CollectionUtils { private CommonUtils() { } public static List subList(List list, int start, int numberOfElement) { } } public final class RandomUtils { private RandomUtils() { } public static String randomString(int length) { } } We should also be able to write a brief description of the class in about 25 words, without using the words “if,” “and,” “or,” or “but.” Avoid God class[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#avoid-god-class) ------------------------------------------------------------------------------------------------------------------ God class—or, alternatively, god object—is an anti-pattern that consists of having a class that does too much. A god class is usually a huge class that concentrates a lot of responsibilities, controls and oversees many different objects, and effectively does everything in the application. There are several problems with God Class: * Violate SOLID * Make Your Code Fragile * Harm Testability * Harm Performance * Make the Code Harder to Understand **The Single Responsibility Principle**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#the-single-responsibility-principle) -------------------------------------------------------------------------------------------------------------------------------------------------------------- The Single Responsibility Principle (SRP) states that a class or module should have one, and only one _reason to change_. This principle gives us both a definition of responsibility and guidelines for class size. **Classes should have one responsibility—one reason to change.** Refer to [SRP - Single Responsibility Principle](https://gpcoder.gitbook.io/clean-code/bonus/solid-principle/srp-single-responsibility-principle) for details. **Cohesion**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#cohesion) -------------------------------------------------------------------------------------------------------- Classes should be cohesive — cohesion results in many small classes**.** Classes should have a small number of instance variables. The more variables a method manipulates the more cohesive that method is to its class. Try to separate the variables and methods into many small classes such that the classes are more cohesive. There are 2 types of Cohesions: Low Cohesion and High Cohesion. Refer to [Coupling and Cohesion](https://gpcoder.gitbook.io/clean-code/bonus/coupling-and-cohesion) for details. Follow principles & patterns[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes#follow-principles-and-patterns) ---------------------------------------------------------------------------------------------------------------------------------------------- * [SOLID](https://gpcoder.gitbook.io/clean-code/bonus/solid-principle) * [AOP](https://gpcoder.gitbook.io/clean-code/bonus/aop-aspect-oriented-programming) * [LoD](https://gpcoder.gitbook.io/clean-code/bonus/lod-principle) * [Design Patterns](https://gpcoder.gitbook.io/clean-code/bonus/oop-design-pattern) [PreviousFunctions](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/functions) [NextComments](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments) Last updated 4 years ago --- # Comments | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments.md) . If our programming languages were expressive enough, or if we had the talent to subtly wield those languages to express our intent, we would not need comments very much—perhaps not at all. Inaccurate comments are far worse than no comments at all. They delude and mislead. They set expectations that will never be fulfilled. They lay down old rules that need not, or should not, be followed any longer. **Truth can only be found in one place: the code. Only the code can truly tell you what it does. It is the only source of truly accurate information.** Therefore, though comments are sometimes necessary, we will expend significant energy to minimize them. Explain Yourself in Code[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#explain-yourself-in-code) ------------------------------------------------------------------------------------------------------------------------------------- Rather than spend your time writing the comments that explain the mess you’ve made, spend it cleaning that mess. Copy // Check to see if the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) Copy if (employee.isEligibleForFullBenefits()) Good Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#ch4lev1sec3) ------------------------------------------------------------------------------------------------------------- ### Legal Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#legal-comments) Sometimes our corporate coding standards force us to write certain comments for legal reasons, for example, copyright and authorship. // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved. // Released under the terms of the GNU General Public License version 2 or later. ### Informative Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#informative-comments) In this case the comment lets us know that the regular expression is intended to match a time and date. Copy // format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher = Pattern.compile(“\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*”); ### Explanation of Intent[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#explanation-of-intent) Sometimes a comment goes beyond just useful information about the implementation and provides the intent behind a decision. Copy // This is our best attempt to get a race condition // by creating a large number of threads. for (int i = 0; i < 25000; i++) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag); Thread thread = new Thread(widgetBuilderThread); thread.start(); } ### Clarification[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#clarification) Sometimes it is just helpful to translate the meaning of some obscure argument or return value into something that’s readable. In general, it is better to find a way to make that argument or return value clear in its own right; but when its part of the standard library, or in code that you cannot alter, then a helpful clarifying comment can be useful. Copy assertTrue(a.compareTo(a) == 0); // a == a assertTrue(a.compareTo(b) != 0); // a != b assertTrue(ab.compareTo(ab) == 0); // ab == ab ### Warning of Consequences[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#warning-of-consequences) Sometimes it is useful to warn other programmers about certain consequences. Copy // Don't run unless you have some time to kill. public void _testWithReallyBigFile() { writeLinesToFile(10000000); String responseString = output.toString(); assertSubString("Content-Length: 1000000000", responseString); assertTrue(bytesSent > 1000000000); } public static SimpleDateFormat makeStandardHttpDateFormat() { // SimpleDateFormat is not thread safe, // so we need to create each instance independently. SimpleDateFormat df = new SimpleDateFormat(”EEE, dd MMM yyyy HH:mm:ss z”); df.setTimeZone(TimeZone.getTimeZone(”GMT”)); return df; } ### TODO Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#todo-comments) `TODO`s are jobs that the programmer thinks should be done, but for some reason can’t do at the moment. It might be a reminder to delete a deprecated feature or a plea for someone else to look at a problem. It might be a request for someone else to think of a better name or a reminder to make a change that is dependent on a planned event. Whatever else a `TODO` might be, it is _not_ an excuse to leave bad code in the system. The `TODO` comment explains why the function has a degenerate implementation and what that function’s future should be. Copy // TODO-MdM these are not needed // We expect this to go away when we do the checkout model protected VersionInfo makeVersion() throws Exception { return null; } ### Javadocs in Public APIs[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#javadocs-in-public-apis) There is nothing quite so helpful and satisfying as a well-described public API. The java-docs for the standard Java library are a case in point. It would be difficult, at best, to write Java programs without them. Copy /** * A subclass of {@link MimeType} that adds support for quality parameters * as defined in the HTTP specification. * * @author Arjen Poutsma * @author Juergen Hoeller * @since 3.0 * @see * HTTP 1.1: Semantics and Content, section 3.1.1.1 */ public class MediaType extends MimeType implements Serializable { private static final long serialVersionUID = 2069937152339670231L; /** * Public constant media type that includes all media ranges (i.e. "*/*"). */ public static final MediaType ALL; } Avoid redundant comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#avoid-redundant-comments) ------------------------------------------------------------------------------------------------------------------------------------- A comment is redundant if it describes something that adequately describes itself. Comments should say things that the code cannot say for itself. Copy // Create a directory public void createDirectory(String name) { } public abstract class ContainerBase { /** * The background processor delay for this component. */ protected int backgroundProcessorDelay = -1; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); } Misleading Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#misleading-comments) --------------------------------------------------------------------------------------------------------------------------- Copy // Utility method that returns when this.closed is true. // Throws an exception if the timeout is reached. public synchronized void waitForClose(final long timeoutMillis) throws Exception { if (!closed) { wait(timeoutMillis); if (!closed) { throw new Exception("MockResponseSender could not be closed"); } } } /** The version. */ private String info; The method does not return _when_ `this.closed` becomes `true`. It returns _if_ `this.closed` is `true`; otherwise, it waits for a blind time-out and then throws an exception _if_ `this.closed` is still not `true`. Give up mandated comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#give-up-mandated-comments) --------------------------------------------------------------------------------------------------------------------------------------- It is just plain silly to have a rule that says that every function and variable must have a comment. Comments like this just clutter up the code. Copy /** * Add CD * * @param title The title of the CD * @param author The author of the CD * @param numberOfTracks The number of tracks on the CD * @param durationInMinutes The duration of the CD in minutes */ public void addCD(String title, String author, int numberOfTracks, int durationInMinutes) { } Remove journal Comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#remove-journal-comments) ----------------------------------------------------------------------------------------------------------------------------------- Sometimes people add a comment to the start of a module every time they edit it. These comments accumulate as a kind of journal, or log, of every change that has ever been made. Nowadays, however, we have source code control systems that did it for us. They should be completely removed. Copy * Changes (from 11-Oct-2001) * -------------------------- * 11-Oct-2001 : Re-organised the class and moved it to new package * com.jrefinery.date (DG); * 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate * class (DG); * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate * class is gone (DG); Changed getPreviousDayOfWeek(), * getFollowingDayOfWeek() and getNearestDayOfWeek() to correct * bugs (DG); * 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG); * 29-May-2002 : Moved the month constants into a separate interface * (MonthConstants) (DG); * 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG); * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG); * 13-Mar-2003 : Implemented Serializable (DG); * 29-May-2003 : Fixed bug in addMonths method (DG); * 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG); * 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG); Don't make noise[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#dont-make-noise) -------------------------------------------------------------------------------------------------------------------- Noise comments restate the obvious and provide no new information. Copy /** * Default constructor. */ protected AnnualDateRule() { } /** The day of the month. */ private int dayOfMonth; /** * Returns the day of the month. * * @return the day of the month. */ public int getDayOfMonth() { return dayOfMonth; } Don’t Use a Comment When You Can Use a Function or a Variable[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#dont-use-a-comment-when-you-can-use-a-function-or-a-variable) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Copy // does the module from the global list depend on the // subsystem we are part of? if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem())) Copy List moduleDependees = smodule.getDependSubsystems(); String ourSubSystem = subSysMod.getSubSystem(); if (moduleDependees.contains(ourSubSystem)) Avoid position markers[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#avoid-position-markers) --------------------------------------------------------------------------------------------------------------------------------- There are rare times when they make sense, but in general they are clutter that should be eliminated. Copy ///////////////////////////////////////////////// // PROPERTIES, PRIVATE AND PROTECTED ///////////////////////////////////////////////// private String name; private int age; protected void doSomething() { showInfo(); } private String showInfo() { } ///////////////////////////////////////////////// // PUBLIC ///////////////////////////////////////////////// public void save() { } Avoid closing brace comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#avoid-closing-brace-comments) --------------------------------------------------------------------------------------------------------------------------------------------- If you find yourself wanting to mark your closing braces, try to shorten your functions instead. Copy public class App { public static void main(String[] args) { try { while ((String line = in.readLine()) != null) { } // End while } // End try catch (IOException e) { } // End catch finally { } // End finally } // End main } // End class Avoid HTML comments[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#avoid-html-comments) --------------------------------------------------------------------------------------------------------------------------- It makes the comments hard to read in the one place where they should be easy to read—the editor/IDE. Copy /** * Task to run fit tests. * *

* This task runs fitnesse tests and publishes the results. *

* *

    *
    * Usage:
    *
    * <taskdef name="execute-fitnesse-tests"
    *
    *     classname="fitnesse.ant.ExecuteFitnesseTestsTask"
    *
    *     classpathref="classpath" />
    *     
    * 
*/ Remove Commented-Out Code[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#remove-commented-out-code) --------------------------------------------------------------------------------------------------------------------------------------- Few practices are as odious as commenting-out code. Don’t do this! Copy InputStreamResponse response = new InputStreamResponse(); response.setBody(formatter.getResultStream(), formatter.getByteCount()); // InputStream resultsStream = formatter.getResultStream(); // StreamReader reader = new StreamReader(resultsStream); // response.setContent(reader.read(formatter.getByteCount())); Don't give too much information[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#dont-give-too-much-information) -------------------------------------------------------------------------------------------------------------------------------------------------- Don’t put interesting historical discussions or irrelevant descriptions of details into your comments. Copy /* RFC 2045 - Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies section 6.8. Base64 Content-Transfer-Encoding The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. When encoding a bit stream via the base64 encoding, the bit stream must be presumed to be ordered with the most-significant-bit first. That is, the first bit in the stream will be the high-order bit in the first 8-bit byte, and the eighth bit will be the low-order bit in the first 8-bit byte, and so on. */ Function Headers[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#function-headers) --------------------------------------------------------------------------------------------------------------------- Short functions don’t need much description. A well-chosen name for a small function that does one thing is usually better than a comment header. Copy /** * Save product only, if the given object is not a product, then throw a ClassCastException * * @param obj The product */ public void save(Object obj) { Product product = (Product)obj; ProductEntity productEntity = mapToEntity(product); productRepository.save(productEntity); } Copy public void saveProduct(Product product) { ProductEntity productEntity = mapToEntity(product); productRepository.save(productEntity); } Javadocs in Nonpublic Code[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#javadocs-in-nonpublic-code) ----------------------------------------------------------------------------------------------------------------------------------------- As useful as Javadocs are for public APIs. Generating Javadoc pages for the classes and functions inside a system is not generally useful, and the extra formality of the Javadoc comments amounts to little more than cruft and distraction. Don’t offer systemwide information[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments#dont-offer-systemwide-information) -------------------------------------------------------------------------------------------------------------------------------------------------------- If you must write a comment, then make sure it describes the code it appears near. Don’t offer systemwide information in the context of a local comment. The following example, aside from the fact that it is horribly redundant, also offers information about the default port. Copy /** * Port on which fitnesse would run. Defaults to 8082. * * @param fitnessePort */ public void setFitnessePort(int fitnessePort) { this.fitnessePort = fitnessePort; } [PreviousClasses](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/classes) [NextError Handling](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling) Last updated 4 years ago --- # Exception handling best practices | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices.md) . Be careful what you log[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#be-careful-what-you-log) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Software developers must always be mindful of the customer’s security and privacy rights. One can move data logged by a Java application to various low-cost storage system, to be viewed by developers and administrators as they attempt to solve a bug. However, you must ensure no protected data is written in the log files. Otherwise, your company will be out of compliance, and you might be out of a job. Don't swallow thrown exception[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#dont-swallow-thrown-exception) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Don’t catch an exception and then do nothing with it. That’s known as burying an exception, and it is definitely not a Java exception handling best practice. At the very least, log the name of the exception and the message associated with it. That way you or others can extract information about an exceptional situation from the logs. Swallow exceptions makes troubleshooting Java applications extremely hard. Copy try { readFile(); } catch (IOException ex) { log.warning("Error while reading file"); } // OR try { readFile(); } catch (IOException ex) throw new SystemException("System error"); } Use a global Exception handler[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#use-a-global-exception-handler) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- There will always be uncaught RuntimeExceptions that creep into your code. Always include a global Exception handler to deal with any uncaught exceptions. This will not only enable you to log and potentially handle the Exception, but it will also stop your app from crashing when a runtime exception is thrown. If you're using SpringBoot Framework, you can read more at [Error Handling for REST with Spring](https://www.baeldung.com/exception-handling-for-rest-with-spring) . Explicitly define exceptions in the throws clause[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#explicitly-define-exceptions-in-the-throws-clause) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Lazy developers use the generic Exception class in the throws clause of a method. Doing so is not a Java exception handling best practice. Instead, always explicitly state the exact set of exception a given method might throw. This allows other developers to know the various error handling routines they can employ if a given method fails to execute properly. Example: Copy void createOrder(OrderDto dto) { try { Product product = getProductInfo(dto.getProdId()); // do something } catch (RuntimeException ex) { // Don't know exactly where the problem is to take a fallback step } } Product getProductInfo(Long prodId) { if (prodId == null) { throw new RuntimeException("Product Id must not be null."); } WebClient webClient = WebClient.builder().build(); if (webClient == null) { throw new RuntimeException("Missing configuration for WebClient"); } try { return webClient.call("https://api.gpcoder.com/products/" + prodId); } catch (Exception ex) { if (isServer5xxError(ex)) { throw new RuntimeException("External server error", ex); } throw new RuntimeException("Unknown error", ex); } } Instead of using RuntimeException, we can define some of specific exception like IllegalArgumentException, MissingConfigurationException, ExternalServerError, InternalServerError, ... Catch the most specific exception first[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#catch-the-most-specific-exception-first) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This is more of a _compiler_ requirement than a Java exception handling best practice, but a developer should always catch the most specific exception first, and the least specific one last. If this rule is not followed, the JVM will generate a compile time error with a fairly cryptic error message that is difficult to understand. Make your software development life easier, and always catch the most specific exception in your code first. Use modern exception handling techniques[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#use-modern-exception-handling-techniques) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Java has added many features around error and exception handling that simplify development and greatly reduce the verbosity of Java code. Take advantage of the ability to catch multiple exceptions in a single catch block, automatically close resource with the _try-with-resources_ block, and use RuntimeExceptions so other developers aren’t forced to handle the exceptions you throw. Don’t close resources manually[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#dont-close-resources-manually) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Another important Java exception handling best practice is to allow the JVM to call the `close()` method of closeable resources. Don’t close resources yourself. This is easily accomplished if you initialize resources within a _try-with-resources_ block. The following example shows the _try-with-resources_ semantics in action: Copy BufferedReader br = null; try { br = new BufferedReader(new FileReader("D:\\gpcoder.txt")); /* do something */ } catch (IOException e) { /* do something */ } finally { try { if (br != null) { br.close(); } } catch (IOException ex) { /* do something */ } } Copy try (BufferedReader br = new BufferedReader(new FileReader("D:\\gpcoder.txt"));) { /* do something */ } catch (IOException e) { /* do something */ } finally { /* do something */ } /* The JVM closes the resource after the code block */ The JVM closes the resource for you when the _try…catch_ block completes. This eliminates the potential for messy and difficult-to-troubleshoot resource leaks. Throw early and handle exceptions late[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#throw-early-and-handle-exceptions-late) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- As soon as an exception condition happens in your code, throw an Exception. Don’t wait for any additional lines of code to run before you terminate execution of the method you are in. The function to catch exceptions should go toward the end of a method. This puts fewer catch blocks in your methods, and makes your code much easier to read and maintain. Read more: [Fail Fast principle](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle) Don’t log and re-throw[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#dont-log-and-re-throw) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ When an Exception occurs you should either, never do both. * Or log the Exception and carry on with your application. * Or re-throw the Exception and let another method log the details. Copy try { readFile(); } catch (IOExceptoin ex) { log.warning("Error while reading file", ex); throw ex; } Copy try { readFile(); } catch (IOException ex) { log.warning("Error while reading file", ex); } // OR try { readFile(); } catch (IOException ex) { throw new SystemException("System error", ex); } Check for suppressed exceptions[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#check-for-suppressed-exceptions) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The suppressed exception is a relatively new language feature that not all developers are aware of. Basically, the introduction of the try-with-resources function, made it possible to throw two exceptions at the same time. You can easily check this situation simply by querying for the suppressed exception’s existence, as is done in the example below: Copy try (BufferedReader br = new BufferedReader(new FileReader("D:\\gpcoder.txt"));) { /* do something */ } catch (IOException e) { System.out.println("Primary Exception: " + e.getClass()); if (e.getSuppressed().length > 0) { System.out.print("Suppressed Exception: " + e.getSuppressed()[0]); } } finally { /* do something */ } The only way to know if this scenario has occurred is to check if the target Exception also contains a suppressed exception. Follow error handling clean code[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices#follow-error-handling-clean-code) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Refer to [Error Handling](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling) [PreviousError Handling](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling) [NextUnit Tests](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests) Last updated 3 years ago --- # Formatting | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting.md) . Vertical Openness Between Concepts[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#vertical-openness-between-concepts) ----------------------------------------------------------------------------------------------------------------------------------------------------------- Each blank line is a visual cue that identifies a new and separate concept. There are blank lines that separate the package declaration, the import(s), and each of the functions. Copy package com.gpcoder; import java.io.BufferedReader; public class Example { public static final String FILE_NAME = "user.csv"; public static final String CSV_SEPARATOR = ","; public void method1() { } public void method2() { } } Use vertical density for tightly related concepts[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#use-vertical-density-for-tightly-related-concepts) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Lines of code that are tightly related should appear vertically dense. The useless comments break the close association of the two instance variables. Copy /** * The class name of the reporter listener */ private String className; /** * The properties of the reporter listener */ private List properties = new ArrayList<>(); public void addProperty(Property property) { properties.add(property); } Copy private String className; private List properties = new ArrayList<>(); public void addProperty(Property property) { properties.add(property); } Place dependent functions vertically close[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#place-dependent-functions-vertically-close) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- If one function calls another, they should be vertically close, and the caller should be above the callee. Copy public void createUser(UserDto userDto) { validateUser(userDto); userRepository.saveUser(userDto); sendEmailNotification(userDto); } public void deleteUser(Long userId) { if (isUserInUse(userId)) { throw new UserInUseException(); } userRepository.deleteUserById(userId); } private void sendEmailNotification(UserDto userDto) { } private boolean isUserInUse(Long userId) { } private void validateUser(UserDto userDto) { } Copy public void createUser(UserDto userDto) { validateUser(userDto); userRepository.saveUser(userDto); sendEmailNotification(userDto); } private void validateUser(UserDto userDto) { } private void sendEmailNotification(UserDto userDto) { } public void deleteUser(Long userId) { if (isUserInUse(userId)) { throw new UserInUseException(); } userRepository.deleteUserById(userId); } private boolean isUserInUse(Long userId) { } Declare variables vertically close to their usage[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#declare-variables-vertically-close-to-their-usage) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Copy public UserStatisticResponse userStatistics(List users) { UserStatisticResponse response = new UserStatisticResponse(); List admins = new ArrayList<>(); List guests = new ArrayList<>(); for (User user : users) { if (isAdmin(user)) { admins.add(user); } else { guests.add(user); } } response.setAdmins(admins); response.setGuests(guests); return response; } Copy public UserStatisticResponse userStatistics(List users) { List admins = new ArrayList<>(); List guests = new ArrayList<>(); for (User user : users) { if (isAdmin(user)) { admins.add(user); } else { guests.add(user); } } UserStatisticResponse response = new UserStatisticResponse(); response.setAdmins(admins); response.setGuests(guests); return response; } Use horizontal separation and density so that code reads nicely[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#use-horizontal-separation-and-density-so-that-code-reads-nicely) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- We use horizontal white space to associate things that are strongly related and disassociate things that are more weakly related. Copy private void measureLine(String line) { // 1 lineCount++; int lineSize = line.length(); // 2 totalChars += lineSize; lineWidthHistogram.addLine(lineSize, lineCount); // 3 recordWidestLine(lineSize); } * (1) I didn’t put spaces between the function names and the opening parenthesis. This is because the function and its arguments are closely related. Separating them makes them appear disjoined instead of conjoined. * (2) I surrounded the assignment operators with white space to accentuate them. Assignment statements have two distinct and major elements: the left side and the right side * (3) I separate arguments within the function call parenthesis to accentuate the comma and show that the arguments are separate. Horizontal Alignment[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#horizontal-alignment) ------------------------------------------------------------------------------------------------------------------------------- Copy public class FitNesseExpediter implements ResponseSender { private Socket socket; private InputStream input; private OutputStream output; private Request request; private Response response; } Copy public class FitNesseExpediter implements ResponseSender { private Socket socket; private InputStream input; private OutputStream output; private Request request; private Response response; } Breaking Indentation[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#breaking-indentation) ------------------------------------------------------------------------------------------------------------------------------- Copy public class CommentWidget extends TextWidget { public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?"; public CommentWidget(ParentWidget parent, String text){super(parent, text);} public String render() throws Exception {return ""; } } Copy public class CommentWidget extends TextWidget { public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?"; public CommentWidget(ParentWidget parent, String text) { super(parent, text); } public String render() throws Exception { return ""; } } Team Rules[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting#team-rules) ----------------------------------------------------------------------------------------------------------- Every programmer has his/her own favorite formatting rules, but if he/she works in a team, then the team rules. A team of developers should agree upon a single formatting style, and then every member of that team should use that style. We want the software to have a consistent style. We don’t want it to appear to have been written by a bunch of disagreeing individuals. The rules we should follow are coding standards documents: * [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) * [Java Code Conventions by Oracle](https://www.oracle.com/technetwork/java/codeconventions-150003.pdf) Many IDEs support coding style checking, the team can define the coding style template and share it to all team members. Refer to [`Checkstyle`](https://checkstyle.sourceforge.io/) development tool. [PreviousUnit Tests](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests) [NextObjects and Data Structures](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures) Last updated 4 years ago --- # Unit Tests | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests.md) . Keep tests clean[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#keep-tests-clean) ----------------------------------------------------------------------------------------------------------------------- Test code should be maintained to the same standards of quality as their production code. Focus on readability[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#focus-on-readability) ------------------------------------------------------------------------------------------------------------------------------- Readability is even more important in unit tests than it is in production code. What makes tests readable? The same thing that makes all code readable: clarity, simplicity, and density of expression. In a test, you want to say a lot with as few expressions as possible. Copy class UserRepository { public User save(UserDto dto) { } public User update(UserDto dto) { } public boolean delete(Long userId){ } } @Test public void testSaveUser() { try { // Given String userDtoJsonFile = "path/to/file/user-dto.json"; Gson gson = new Gson(); JsonReader reader = new JsonReader(new FileReader(userDtoJsonFile)); UserDto dto = gson.fromJson(reader, UserDto.class); // When User actualUser = userRepository.save(dto); // Then // Expected user String userJsonFile = "path/to/file/user.json"; reader = new JsonReader(new FileReader(userJsonFile)); User expectedUser = gson.fromJson(reader, User.class); // Verify saved user assertNotNull(actualUser); assertNotNull(actualUser.getId()); assertEquals(expectedUser.getEmail(), actualUser.getEmail()); assertEquals(expectedUser.getPassword(), actualUser.getPassword()); } catch(FileNotFoundException ex) { fail("The given user data json file is not found", ex); } } Copy class JsonUtils { public T fromJsonFile(String jsonFile, Class tClass) throws FileNotFoundException { Gson gson = new Gson(); JsonReader reader = new JsonReader(new FileReader(jsonFile)); return gson.fromJson(reader, tClass); } } @Test void givenUser_WhenSave_ShouldSaveSuccessfully() throws FileNotFoundException { // Given UserDto dto = createUserDto(); // When User actualUser = userRepository.save(dto); // Then User expectedUser = createExpectedUser(); verifySavedUser(expectedUser, actualUser); } private UserDto createUserDto() throws FileNotFoundException { String userDtoJsonFile = "path/to/file/user-dto.json"; return JsonUtils.fromJsonFile(userDtoJsonFile, UserDto.class); } private User createExpectedUser() throws FileNotFoundException { String userJsonFile = "path/to/file/user.json"; return JsonUtils.fromJsonFile(userJsonFile, User.class); } private void verifySavedUser(UserDto expectedUser, User actualUser) { assertNotNull(actualUser); assertNotNull(actualUser.getId()); assertEquals(expectedUser.getEmail(), actualUser.getEmail()); assertEquals(expectedUser.getPassword(), actualUser.getPassword()); } One Assert per Test[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#one-assert-per-test) ----------------------------------------------------------------------------------------------------------------------------- Every test function in a JUnit test should have one and only one assert statement. Copy @Test public void testUserCRUD() { // Given UserDto userDto1 = new UserDtoBuilder() .setEmail("cleancode@gpcoder.com") .setPassword("secret") .build(); // When User user1 = userRepository.save(userDto1); // Then assertNotNull(user1); // Do other assert statements ... // Given UserDto updatedUser1 = user1.setPassword("new secret").build(); // When user1 = userRepository.update(user1); // Then assertNotNull(user1); // Given long userId = 1; // When boolean isDeleted = userRepository.delete(1); // Then assertTrue(isDeleted); } Copy @Test public void givenUser_WhenSave_ShouldSaveSuccessfully() { // Given UserDto userDto1 = new UserDtoBuilder() .setEmail("cleancode@gpcoder.com") .setPassword("secret") .build(); // When User user1 = userRepository.save(userDto1); // Then assertNotNull(user1); } @Test public void givenUser_WhenUpdate_ShouldUpdateSuccessfully() { // Given User user1 = new UserBuilder() .id(1) .setEmail("cleancode@gpcoder.com") .setPassword("new secret") .build(); // When User user1 = userRepository.update(user1); // Then assertNotNull(user1); } @Test public void givenUserId_WhenDelete_ShouldDeleteSuccessfully() { // Given long userId = 1; // When boolean isDeleted = userRepository.delete(1); // Then assertTrue(isDeleted); } The names of the functions should use the common given-when-then convention. This makes the tests even easier to read. Use a single concept per test[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#use-a-single-concept-per-test) ------------------------------------------------------------------------------------------------------------------------------------------------- Should minimize the number of asserts per concept and test just one concept per test function. Copy public static final int MIN = 10; public static final int MAX = 100; boolean isInRange(int value) { return MIN <= value && value <= MAX; } @Test public void testInRange() { assertFalse(isInRange(9)); assertTrue(isInRange(10)); assertTrue(isInRange(11)); assertTrue(isInRange(99)); assertTrue(isInRange(100)); assertFalse(isInRange(101)); } You can split it into multiple test cases, e.g. test less than, equal to, greater than MIN/MAX value. However, you can minimize it as follows: Copy @Test public void givenValueInRange_WhenCheckInRange_ShouldReturnTrue() { assertTrue(isInRange(10)); assertTrue(isInRange(11)); assertTrue(isInRange(99)); assertTrue(isInRange(100)); } @Test public void givenValueOutRange_WhenCheckInRange_ShouldReturnFalse() { assertFalse(isInRange(9)); assertFalse(isInRange(101)); } Follow five rules that form the acronym F.I.R.S.T.[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#follow-five-rules-that-form-the-acronym-f.i.r.s.t) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ### **Fast**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#fast) **Tests should be fast.** They should run quickly. When tests run slow, you won’t want to run them frequently. If you don’t run them frequently, you won’t find problems early enough to fix them easily. You won’t feel as free to clean up the code. Eventually the code will begin to rot. ### **Independent**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#independent) **Tests should not depend on each other.** One test should not set up the conditions for the next test. You should be able to run each test independently and run the tests in any order you like. When tests depend on each other, then the first one to fail causes a cascade of downstream failures, making diagnosis difficult and hiding downstream defects. ### **Repeatable**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#repeatable) **Tests should be repeatable in any environment.** You should be able to run the tests in the production environment, in the QA environment, and on your laptop while riding home on the train without a network. If your tests aren’t repeatable in any environment, then you’ll always have an excuse for why they fail. You’ll also find yourself unable to run the tests when the environment isn’t available. ### **Self-Validating**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#self-validating) **The tests should have a boolean output. Either they pass or fail**. You should not have to read through a log file to tell whether the tests pass. You should not have to manually compare two different text files to see whether the tests pass. If the tests aren’t self-validating, then failure can become subjective, and running the tests can require a long manual evaluation. ### **Timely**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/unit-tests#timely) The tests need to be written in a timely fashion. **Unit tests should be written** _**just before**_ **the production code that makes them pass**. If you write tests after the production code, then you may find the production code to be hard to test. You may decide that some production code is too hard to test. You may not design the production code to be testable. [PreviousException handling best practices](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices) [NextFormatting](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting) Last updated 4 years ago --- # Objects and Data Structures | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures.md) . Data Abstraction[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures#data-abstraction) ---------------------------------------------------------------------------------------------------------------------------------------- We do not want to expose the details of our data. Rather we want to express our data in abstract terms. Hiding implementation is not just a matter of putting a layer of functions between the variables. Hiding implementation is about abstractions! A class does not simply push its variables out through getters and setters. Rather it exposes abstract interfaces that allow its users to manipulate the essence of the data, without having to know its implementation. Copy public class Point { public double x; public double y; } Copy public class Point { private double x; private double y; public double getX() { return x; } public double getY() { return y; } public void setCartesian(double x, double y) { this.x = x; this.y = y; } } Data/Object Anti-Symmetry[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures#data-object-anti-symmetry) ---------------------------------------------------------------------------------------------------------------------------------------------------------- Data structures expose data and have no significant behavior. This makes it easy to add new functions to existing data structures but makes it hard to add new data structures to existing functions because all the functions must change. Objects expose behavior and hide data. This makes it easy to add new kinds of objects without changing existing behaviors. It also makes it hard to add new behaviors to existing objects because all the classes must change. In any given system, we will sometimes want the flexibility to add new data types, and so we prefer objects for that part of the system. Other times, we will want the flexibility to add new behaviors, and so in that part of the system, we prefer data types and procedures. **Example of Data structure:** Copy public class Square { private double side; } public class Rectangle { private double height; private double width; } public class App { public void draw(Object shape) throws NoSuchShapeException { if (shape instanceof Square) { log.info("Draw Square with side=" + s.getSide()); } else if (shape instanceof Rectangle) { Rectangle r = (Rectangle) shape; log.info("Draw Rectangle with with=" + r.getWidth() + " and height=" + r.getHeight()); } throw new NoSuchShapeException(); } // Easy to add new functions public void drawV2(Object shape) { if (shape instanceof Square) { log.info("DrawV2 Square with side=" + s.getSide()); } else if (shape instanceof Rectangle) { Rectangle r = (Rectangle) shape; log.info("DrawV2 Rectangle with with=" + r.getWidth() + " and height=" + r.getHeight()); } throw new NoSuchShapeException(); } public void drawV3(Object shape) { log.info("DrawV3 shape=" + shape.getClass().getSimpleName()); } public double area(Object shape) { // ... } } It's hard to add a new data structure like `Circle`, because must change all functions like `draw()` and `drawV2()` to have the `Circle` data structure. **Example of Object:** Copy public interface Shape { void draw(); } public class Square implements Shape { private double side; @Override public void draw() { log.info("Draw Square with side=" + side); } } public class Rectangle implements Shape private double height; private double width; @Override public void draw() { log.info("Draw Rectangle with with=" + width + " and height=" + height); } } // Easy to add new data types public class Circle implements Shape { private double radius; @Override public void draw() { log.info("Draw Circle with radius=" radius); } } It's hard to add new behaviors to existing objects `Shape` like adding functions`drawV2()`, because all the classes must change like `Square`, `Rectangle`, and `Circle`. Avoid Hybrids[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures#avoid-hybrids) ---------------------------------------------------------------------------------------------------------------------------------- Hybrid structures are half object and half data structures. Hybrids make it hard to add new functions but also make it hard to add new data structures. They are the worst of both worlds. Copy public abstract class Shape { public void draw() throws NoSuchShapeException { if (this instanceof Square) { log.info("Draw Square with side=" + s.getSide()); } else if (this instanceof Rectangle) { Rectangle r = (Rectangle) shape; log.info("Draw Rectangle with with=" + r.getWidth() + " and height=" + r.getHeight()); } throw new NoSuchShapeException(); } public void drawV2() { if (this instanceof Square) { log.info("DrawV2 Square with side=" + s.getSide()); } else if (this instanceof Rectangle) { Rectangle r = (Rectangle) shape; log.info("DrawV2 Rectangle with with=" + r.getWidth() + " and height=" + r.getHeight()); } throw new NoSuchShapeException(); } // Hard to add new functions // public abstract double area(); } public class Square extends Shape { private double side; } public class Rectangle extends Shape { private double height; private double width; } // Hard to add new data types // public class Circle extends Shape { } It's hard to add a new data structure like `Circle`, because must change all functions like `draw()` and `drawV2()` to have the `Circle` data structure. It's hard to add new behaviors to existing objects `Shape` like adding functions `area()`, because all the classes must change like `Square`, `Rectangle`. The Law of Demeter[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures#the-law-of-demeter) -------------------------------------------------------------------------------------------------------------------------------------------- Refer to [LoD Principle](https://gpcoder.gitbook.io/clean-code/bonus/lod-principle) Data Transfer Objects[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures#data-transfer-objects) -------------------------------------------------------------------------------------------------------------------------------------------------- The quintessential form of a data structure is a class with public variables and no functions. This is sometimes called a data transfer object, or DTO. DTO is an object that carries data between processes. DTO is a simple object that should not contain any business logic but may contain serialization and deserialization mechanisms for transferring data over the wire. Copy class User { private String firstName; private String lastName; private String email; private LocalDate birthday; private Role role; private LocalDateTime createdAt; private LocalDateTime updatedAt; } public void createUser(String firstName, String lastName, String email, LocalDate birthday, Role role) { User user = new User(); user.setFirstName(firstName); user.setLastName(lastName); // ... user.setCreatedAt(LocalDateTime.now()); userRepository.save(user); } Copy class User { private String firstName; private String lastName; private String email; private LocalDate birthday; private Role role; private LocalDateTime createdAt; private LocalDateTime updatedAt; } class UserDto { private String firstName; private String lastName; private String email; private LocalDate birthday; private Role role; } public void createUser(UserDto userDto) { User user = mapToUser(userDto); user.setCreatedAt(LocalDateTime.now()); userRepository.save(user); } [PreviousFormatting](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/formatting) [NextSimple Design Rules](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules) Last updated 4 years ago --- # Simple Design Rules | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules.md) . Whether you are designing systems or individual modules, never forget to use the **simplest** thing that can possibly work. A design is “simple” if it follows these rules: * Runs all the tests * Contains no duplication * Expresses the intent of the programmer * Minimizes the number of classes and methods Rule 1: Runs All the Tests[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules#rule-1-runs-all-the-tests) --------------------------------------------------------------------------------------------------------------------------------------------------- **A design must produce a system that acts as intended**. A system might have a perfect design on paper, but if there is no simple way to verify that the system actually works as intended, then all the paper effort is questionable. A system that cannot be verified should never be deployed. We need to have tests and run them continuously impacts our system’s adherence to the primary OO goals of **low coupling** and **high cohesion**. Writing tests leads to better designs. * Classes are small and single purpose. It’s easier to test classes that conform to the **SRP**. * Tight coupling makes it difficult to write tests. We use principles like **DIP** and tools like **dependency injection**, **interfaces**, and **abstraction** to minimize coupling. Once we have tests, we are empowered to keep our code and classes clean. We do this by incrementally refactoring the code. During this refactoring step, we can apply anything from the entire body of knowledge about good software design. We can **increase cohesion, decrease coupling, separate concerns, modularize system concerns, shrink our functions and classes, choose better names, and so on**. This is also where we apply the final three rules of simple design: **Eliminate duplication**, **ensure expressiveness**, and **minimize the number of classes and methods**. Rule 2: **No Duplication**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules#ch12lev1sec4) -------------------------------------------------------------------------------------------------------------------------------------- Duplication is the primary enemy of a well-designed system. It represents additional work, additional risk, and additional unnecessary complexity. Duplication manifests itself in many forms**:** * Lines of code that look **exactly the same**. * Lines of code that are **similar to**. * **Duplication of implementation**. To avoid duplication refer to [DRY Principle](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) Rule 3: **Ensure expressiveness**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules#rule-3-ensure-expressiveness) ------------------------------------------------------------------------------------------------------------------------------------------------------------- **Code should clearly express the intent of its author.** The clearer the author can make the code, the less time others will have to spend understanding it. This will reduce defects and shrink the cost of maintenance. Spend a little time with each of your functions and classes express yourself by **choosing better names, splitting large functions into smaller functions, using design pattern, and generally just take care of what you’ve created.** **Well-written unit tests** are also expressive. A primary goal of tests is to act as documentation by example. Someone reading our tests should be able to get a quick understanding of what a class is all about. But the most important way to be expressive is to **try**. All too often we get our code working and then move on to the next problem without giving sufficient thought to making that code easy for the next person to read. Remember, the most likely next person to read the code will be you. **Rule 4: Minimal Classes and Methods**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules#rule-4-minimal-classes-and-methods) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- This rule suggests that **we also keep our function and class counts low.** High class and method counts are sometimes the result of pointless dogmatism. It requires experience, open mind, and reason to apply principles correctly in its true purpose and the proper context of application. Our goal is to keep our overall system small while we are also keeping our functions and classes small. Remember, however, that this rule is the lowest priority of the four rules of Simple Design. So, although it’s important to keep class and function count low, it’s more important to have tests, eliminate duplication, and express yourself. [PreviousObjects and Data Structures](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/objects-and-data-structures) [NextConcurrency](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency) Last updated 4 years ago --- # Concurrency | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency.md) . Concurrent code is difficult to get right. Code that is simple to follow can become hard to understand when multiple threads and shared data get into the mix. If you are faced with writing concurrent code, you need to write clean code with rigor or else face infrequent failures. If you take a clean approach, your chances of getting it right increase drastically. Why do we need Concurrency?[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#e7c3) ----------------------------------------------------------------------------------------------------------------------- It helps in decoupling our code, decoupling what gets done from when it gets done. In a single-threaded application, you can determine the state of the program exactly by looking at the stack trace. We use breakpoints for the job which is quite fair and simple. Writing multithreaded **improves the structural and performance** of your program. Imagine you have a new website that shows news from all the other websites combined. You have a web scrapper that scraps news from different websites one after the other. All this has to be done every hour to keep your content up to date. As the number of news source website will increase, it will eventually take your scrapper more than an hour to scrape data from all the sources. Hence, building a multithreaded web scrapper will improve your performance here. Follow Single Responsibility Principle[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#follow-single-responsibility-principle) -------------------------------------------------------------------------------------------------------------------------------------------------------------------- Keep your concurrency-related code separate from other code. Your thread-aware code should be small and focused. Make sure when you are testing your thread-aware code, you are only testing it and nothing else. Limit the Scope of Data[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#limit-the-scope-of-data) -------------------------------------------------------------------------------------------------------------------------------------- Take data encapsulation to heart; severely limit the access of any data that may be shared. Use the `synchronized` keyword to protect a _critical section_ in the code that uses the shared object. Use Copies of Data[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#use-copies-of-data) ---------------------------------------------------------------------------------------------------------------------------- A good way to avoid shared data is to avoid sharing the data in the first place. In some situations it is possible to copy objects and treat them as read-only. In other cases it might be possible to copy objects, collect results from multiple threads in these copies and then merge the results in a single thread. Threads Should Be as Independent as Possible[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#threads-should-be-as-independent-as-possible) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Consider writing your threaded code such that each thread exists in its own world, sharing no data with any other thread. Each thread processes one client request, with all of its required data coming from an unshared source and stored as local variables. This makes each of those threads behave as if it were the only thread in the world and there were no synchronization requirements. Attempt to partition data into independent subsets than can be operated on by independent threads, possibly in different processors. Know Your Library[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#know-your-library) -------------------------------------------------------------------------------------------------------------------------- Learn your library and know the fundamental algorithms. Understand how some of the features offered by the library support solving problems similar to the fundamental algorithms. Understand some basic definitions: * Bound Process: Resources of fixed size or number used in a concurrent. Examples include database connections and fixed size read/write buffers. * Mutual Exclusion: Only one thread can access shared data or a shared resource at a time. * Starvation: One thread or group of threads is prohibited from proceeding for an excessively long time or forever. For example, always letting fast-running thread through first could starve out longer running threads if there is no end to the fast running threads. * Deadlock: Two or more threads waiting each other to finish. Each thread has a resource that the other thread requires and neither can finish until it get the other resource. * Livelock: Thread in lockstep, each trying to do work but finding another "in the way". Due to resonance, threads continue trying to make progress but are unable to for an excessively long time or forever. Some execution models used in concurrent programming: * Producer-Consumer * Readers-Writers * Dining Philosophers There are several things to consider when writing threaded code in Java: * Use the provided thread-safe collections. * Use the executor framework for executing unrelated tasks. * Use nonblocking solutions when possible. * Several library classes are not thread safe. Beware Dependencies Between Synchronized Methods[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#beware-dependencies-between-synchronized-methods) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Dependencies between synchronized methods cause subtle bugs in concurrent code. Avoid using more than one method on a shared object. Keep Synchronized Sections Small[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#keep-synchronized-sections-small) -------------------------------------------------------------------------------------------------------------------------------------------------------- Learn how to find regions of code that must be locked and lock them. Do not lock regions of code that do not need to be locked. Avoid calling one locked section from another. This requires a deep understanding of whether something is or is not shared. Keep the amount of shared objects and the scope of the sharing as narrow as possible. Change designs of the objects with shared data to accommodate clients rather than forcing clients to manage shared state. Writing Correct Shut-Down Code Is Hard[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#writing-correct-shut-down-code-is-hard) -------------------------------------------------------------------------------------------------------------------------------------------------------------------- Writing a system that is meant to stay live and run forever is different from writing something that works for awhile and then shuts down gracefully. Graceful shutdown can be hard to get correct. Common problems involve deadlock, with threads waiting for a signal to continue that never comes. If you must write concurrent code that involves shutting down gracefully, expect to spend much of your time getting the shutdown to happen correctly. Think about shut-down early and get it working early. It’s going to take longer than you expect, review existing algorithms because this is probably harder than you think. Testing Threaded Code[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency#testing-threaded-code) ---------------------------------------------------------------------------------------------------------------------------------- Proving that code is correct is impractical. Testing does not guarantee correctness. However, good testing can minimize risk. Write tests that have the potential to expose problems and then run them frequently, with different programatic configurations and system configurations and load. If tests ever fail, track down the failure. Don’t ignore a failure just because the tests pass on a subsequent run. Thread typically only happen under load or at seemingly random times. Here are a few more fine-grained recommendations: * Treat spurious failures as candidate threading issues: Do not ignore system failures as one-offs. * Get your nonthreaded code working first: Do not try to chase down nonthreading bugs and threading bugs at the same time. Make sure your code works outside of threads. * Make your threaded code pluggable: Make your thread-based code especially pluggable so that you can run it in various configurations. * Make your threaded code tunable: Allow the number of threads to be easily tuned. Consider allowing it to change while the system is running. Consider allowing self-tuning based on throughput and system utilization. * Run with more threads than processors: The more frequently your tasks swap, the more likely you’ll encounter code that is missing a critical section or causes deadlock. * Run on different platforms: Run your threaded code on all target platforms early, repeatedly and continuously. * Instrument your code to try and force failures: * You will greatly improve your chances of finding erroneous code if you take the time to instrument your code. You can either do so by hand or using some kind of automated technology like an Aspect-Oriented Framework, CGLIB. Invest in this early. You want to be running your thread-based code as long as possible before you put it into production. * You can instrument your code and force it to run in different orderings by adding calls to methods like `Object.wait()`, `Object.sleep()`, `Object.yield()` and `Object.priority()`. [PreviousSimple Design Rules](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/simple-design-rules) [NextCode Smells](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells) Last updated 4 years ago --- # Code Smells | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells.md) . The following list to identify a code smell: * Rigidity: the software is difficult to change. A small change causes a cascade of subsequent changes. * Fragility: the software breaks in many places due to a single change. * Immobility: you cannot reuse parts of the code in other projects because of the involved risks and high effort. * Needless Complexity. * Needless Repetition: the two code fragments look almost identical. * Opacity: the code is hard to understand. **Comments**[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#ch17lev1sec1) ---------------------------------------------------------------------------------------------------------------- Always try to explain yourself in code. Avoid: * Inappropriate information * Obsolete comment * Redundant comment * Poorly Written comment * Commented-out code Functions[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#functions) ---------------------------------------------------------------------------------------------------------- A function should be small and do one thing. Avoid: * Long function: A function contains too many lines of code. Generally, any function longer than ten lines should make you start asking questions. * Too many arguments: More than three or four parameters for a function. * Output arguments: Readers expect arguments to be inputs, not outputs. If your function must change the state of something, have it change the state of the object it is called on. * Flag arguments: Boolean arguments loudly declare that the function does more than one thing. * Selector Arguments: They can be boolean, enums, integers, or any other type of argument that is used to select the behavior of the function. In general, it is better to have many functions than to pass some code into a function to select the behavior. Selector arguments are just a lazy way to avoid splitting a large function into several smaller functions. * Dead function: Methods that are never called should be discarded. * Feature Envy: A method that accesses the data of another object more than its own data. Classes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#classes) ------------------------------------------------------------------------------------------------------ A class should be small and do one thing. Avoid: * Large Class: a class that contains many fields/methods/lines of code. * Alternative classes with different interfaces: two classes perform identical functions but have different method names. The programmer who created one of the classes probably didn’t know that a functionally equivalent class already existed. * Refused Bequest: If a subclass uses only some of the methods and properties inherited from its parents, the hierarchy is off-kilter. The unneeded methods may simply go unused or be redefined and give off exceptions. * Change Preventers: * Having to change many unrelated methods when you make changes to a class. * Making any modifications requires that you make many small changes to many different classes. * Parallel inheritance hierarchies: Whenever you create a subclass for a class, you find yourself needing to create a subclass for another class. * Speculative generality: code is created “just in case” to support anticipated future features that never get implemented. * Dead Code: A variable, parameter, field, method, or class is no longer used (usually because it’s obsolete). * Violate the Law of Delimiter: see a series of calls resembling a->b()->c()->d(). A chain occurs when a client requests another object, that object requests yet another one, and so on. These chains mean that the client is dependent on navigation along the class structure. Any changes in these relationships require modifying the client. * Violate Encapsulation: a class exposes the internal structure. * Inherit Constants: a class extends from a constant class. Should use a static import instead. * Inappropriate use of constants: Enums can have methods and fields. This makes them very powerful tools that allow much more expression and flexibility than constant. General[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#general) ------------------------------------------------------------------------------------------------------ * Multiple Languages in One Source File: a source file should contain one, and only one language. * Obvious Behavior Is Unimplemented: Following “The Principle of Least Surprise”, any function or class should implement the behaviors that another programmer could reasonably expect. * Incorrect Behavior at the Boundaries: Don’t rely on your intuition. Look for every boundary condition and write a test for it. * Duplication: Following "Don’t Repeat Yourself", or "Once, and only once". The duplication can be addressed by using the TEMPLATE METHOD or STRATEGY pattern. * Code at Wrong Level of Abstraction: It is important to create abstractions that separate higher-level general concepts from lower-level detailed concepts. Sometimes we do this by creating abstract classes to hold the higher level concepts and derivatives to hold the lower level concepts. When we do this, we need to make sure that the separation is complete. We want _all_ the lower-level concepts to be in the derivatives and _all_ the higher-level concepts to be in the base class. We don’t want lower and higher-level concepts mixed together. * Base Classes Depending on Their Derivatives: * In general, base classes should know nothing about their derivatives. * Sometimes the number of derivatives is strictly fixed, and the base class has code that selects between the derivatives. In that case, the derivatives and base class are strongly coupled and always deploy together in the same jar file. In the general case, we want to be able to **deploy derivatives and bases in different jar files**. * Deploying derivatives and bases in different jar files and making sure the base jar files know nothing about the contents of the derivative jar files allow us to deploy our systems in discrete and independent components. When such components are modified, they can be redeployed without having to redeploy the base components. This means that the impact of a change is greatly lessened, and maintaining systems in the field is made much simpler. * Too Much Information: Hide your data. Hide your utility functions. Hide your constants and your temporaries. Don’t create classes with lots of methods or lots of instance variables. Don’t create lots of protected variables and functions for your subclasses. Concentrate on keeping interfaces very tight and very small. Help keep coupling low by limiting information. * Dead Code: Dead code is code that isn’t executed. * Vertical Separation: Variables and functions should be defined close to where they are used. * Inconsistency: If you do something a certain way, do all similar things in the same way. * Clutter: Variables that aren’t used, functions that are never called, comments that add no information, and so forth. * Artificial Coupling: an artificial coupling is a coupling between two modules that serve no direct purpose. It is a result of putting a variable, constant, or function in a temporarily convenient, though inappropriate, location. Should figure out where functions, constants, and variables ought to be declared. * Misplaced Responsibility: where to put code. * Inappropriate Static: you should **prefer nonstatic methods to static methods**. When in doubt, make the function nonstatic. If you really want a function to be static, make sure that there is no chance that you’ll want it to behave polymorphically. * Use Explanatory Variables: break the calculations up into intermediate values that are held in variables with meaningful names. * Function Names Should Say What They Do * Understand the Algorithm: Before you consider yourself to be done with a function, make sure you understand how it works. It is not good enough that it passes all the tests. You must know that the solution is correct. * Make Logical Dependencies Physical: If one module depends upon another, that dependency should be physical, not just logical. The dependent module should not make assumptions (in other words, logical dependencies) about the module it depends upon. Rather it should explicitly ask that module for all the information it depends upon. * Prefer Polymorphism to If/Else or Switch/Case * Follow Standard Conventions * Replace Magic Numbers with Named Constants * Be Precise: When you make a decision in your code, make sure you make it precisely. Know why you have made it and how you will deal with any exceptions. Don’t be lazy about the precision of your decisions. * Structure over Convention: Enforce design decisions with structure over convention. Naming conventions are good, but they are inferior to structures that force compliance. For example, switch/cases with nicely named enumerations are inferior to base classes with abstract methods. * Encapsulate Conditionals: Boolean logic is hard enough to understand without having to see it in the context of an if or while statement. Extract functions that explain the intent of the conditional. * Avoid Negative Conditionals * Functions Should Do One Thing * Hidden Temporal Couplings: Temporal couplings are often necessary, but you should not hide the coupling. Structure the arguments of your functions such that the order in which they should be called is obvious. * Encapsulate Boundary Conditions: Boundary conditions are hard to keep track of. Put the processing for them in one place. Don’t let them leak all over the code. * Functions Should Descend Only One Level of Abstraction: The statements within a function should all be written at the same level of abstraction, which should be one level below the operation described by the name of the function. * Keep Configurable Data at High Levels: If you have a constant such as a default or configuration value that is known and expected at a high level of abstraction, do not bury it in a low-level function. Expose it as an argument to that low-level function called from the high-level function. * Avoid Transitive Navigation: we don’t want a single module to know much about its collaborators. This is sometimes called the Law of Demeter. Names[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#names) -------------------------------------------------------------------------------------------------- * Choose Descriptive Names. * Choose Names at the Appropriate Level of Abstraction: Don’t pick names that communicate implementation; choose names that reflect the level of abstraction of the class or function you are working in. * Use Standard Nomenclature Where Possible: Names are easier to understand if they are based on existing conventions or usage. For example, if you are using the DECORATOR pattern, you should use the word Decorator in the names of the decorating classes. * Unambiguous Names: Choose names that make the workings of a function or variable unambiguous. Avoiding the name of the function does not say what the function does. * Use Long Names for Long Scopes: Use Long Names for Long Scopes. * Avoid Encodings * Names Should Describe Side-Effects: Names should describe everything that a function, variable, or class is or does. Don’t hide side effects with a name. Don’t use a simple verb to describe a function that does more than just that simple action. Tests[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells#tests) -------------------------------------------------------------------------------------------------- * Avoid Insufficient Tests: A test suite should test everything that could possibly break. The tests are insufficient so long as there are conditions that have not been explored by the tests or calculations that have not been validated. * Use a Coverage Tool: to find modules, classes, and functions that are insufficiently tested. * Don’t Skip Trivial Tests: They are easy to write and their documentary value is higher than the cost to produce them. * An Ignored Test Is a Question about an Ambiguity: Sometimes we are uncertain about a behavioral detail because the requirements are unclear. We can express our question about the requirements as a test that is commented out, or as a test that is annotated with @Ignore. * Test Boundary Conditions": Take special care to test boundary conditions. We often get the middle of an algorithm right but misjudge the boundaries. * Exhaustively Test Near Bugs: Bugs tend to congregate. When you find a bug in a function, it is wise to do an exhaustive test of that function. You’ll probably find that the bug was not alone. * Patterns of Failure Are Revealing: Sometimes you can diagnose a problem by finding patterns in the way the test cases fail. This is another argument for making the test cases as complete as possible. Complete test cases ordered in a reasonable way, and expose patterns. * Test Coverage Patterns Can Be Revealing: Looking at the code that is or is not executed by the passing tests gives clues to why the failing tests fail. * Tests Should Be Fast [PreviousConcurrency](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/concurrency) [NextWrite Short Units of Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code) Last updated 4 years ago --- # Write Short Units of Code | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code.md) . Units are the smallest groups of code that can be maintained and executed independently. In Java, units are methods or constructors. A unit is always executed as a whole. It is not possible to invoke just a few lines of a unit. Therefore, the smallest piece of code that can be reused and tested is a unit. Motivation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#motivation) ------------------------------------------------------------------------------------------------------------------------ The advantages of short units are that they are easy to test, easy to analyze, and easy to reuse. How to Apply the Guideline[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#how-to-apply-the-guideline) -------------------------------------------------------------------------------------------------------------------------------------------------------- Following this guideline is not difficult when you know the right techniques, but it requires discipline. **When writing a new unit, never let it grow beyond 15 lines of code**. That means that well before you reach 15 lines of code, you need to start thinking about how to add further functionality. Does it _really_ belong in the unit you are writing, or should it go into its own unit? When a unit grows beyond 15 lines of code despite your efforts, you need to shorten it. Example: ### **When Writing a New Unit**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#when-writing-a-new-unit) The most basic version of the start method checks whether the game is already in progress. If so, it silently returns; otherwise, it updates inProgress, a private member to keep track of its state: Copy public void start() { if (inProgress) { return; } inProgress = true; } ### **When Extending a Unit with New Functionality**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#when-extending-a-unit-with-new-functionality) if we add code that tells all observers the level has been lost if the player has died, and that tells all observers that the level is won if any pellets are left: Copy public void start() { if (inProgress) { return; } inProgress = true; // Update observers if player died: if (!isAnyPlayerAlive()) { for (LevelObserver o : observers) { o.levelLost(); } } // Update observers if all pellets eaten: if (remainingPellets() == 0) { for (LevelObserver o : observers) { o.levelWon(); } } } Adding the code to update observers made our unit grow to 16 lines of code (and 18 lines in total, including the 2 lines that contain comments). After testing the behavior of this new code, you are probably already thinking about the next functionality to implement. However, you need to refactor? ### **Using Refactoring Techniques to Apply the Guideline**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#using-refactoring-techniques-to-apply-the-guideline) #### **Refactoring technique: Extract Method**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#refactoring-technique-extract-method) Copy public void start() { if (inProgress) { return; } inProgress = true; updateObservers(); } private void updateObservers() { // Update observers if player died: if (!isAnyPlayerAlive()) { for (LevelObserver o : observers) { o.levelLost(); } } // Update observers if all pellets eaten: if (remainingPellets() == 0) { for (LevelObserver o : observers) { o.levelWon(); } } } As you can see, the unit (the method called `start`) that had grown to 16 lines of code is now back to 7 lines of code, well below the limit of 15 lines. A new unit (method), called `updateObservers`, has been added. It has 12 lines of code, which is also under the limit of 15 lines. The new method still has two responsibilities, as indicated by the comments. We can refactor the code further, applying Extract Method two more times: Copy private void updateObservers() { updateObserversPlayerDied(); updateObserversPelletsEaten(); } private void updateObserversPlayerDied() { if (!isAnyPlayerAlive()) { for (LevelObserver o : observers) { o.levelLost(); } } } private void updateObserversPelletsEaten() { if (remainingPellets() == 0) { for (LevelObserver o : observers) { o.levelWon(); } } } There is no need for the comments anymore: they have been replaced by the names of the new methods. Using short units makes source code self-explanatory, as the names of the methods take over the role of comments. There is a price, however: the total number of code lines has increased, from 16 to 25. Writing maintainable code is always a trade-off between different guidelines. When splitting a unit into multiple units, you might increase the total number of code lines. However, you have decreased the length and complexity of units that need to be tested and understood. Therefore, maintainability has improved. #### **Refactoring technique: Replace Method with Method Object**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#refactoring-technique-replace-method-with-method-object) Sometimes, you want to extract a method that _does_ access local variables. It is always possible to pass local variables as parameters to the extracted method. However, this may lead to long parameter lists. Return values can be even more troublesome, as in Java you can return only a single value from a method. In these cases, you can use a second refactoring technique, called _Replace Method with Method Object_. Example: Copy public Board createBoard(Square[][] grid) { assert grid != null; Board board = new Board(grid); int width = board.getWidth(); int height = board.getHeight(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Square square = grid[x][y]; for (Direction dir : Direction.values()) { int dirX = (width + x + dir.getDeltaX()) % width; int dirY = (height + y + dir.getDeltaY()) % height; Square neighbour = grid[dirX][dirY]; square.link(neighbour, dir); } } } return board; } If you apply the Extract Method technique, you will have to pass seven parameters to the extracted method: Copy public Board createBoard(Square[][] grid) { assert grid != null; Board board = new Board(grid); int width = board.getWidth(); int height = board.getHeight(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Square square = grid[x][y]; for (Direction dir : Direction.values()) { setLink(square, dir, x, y, width, height, grid); } } } return board; } private void setLink(Square square, Direction dir, int x, int y, int width, int height, Square[][] grid) { int dirX = (width + x + dir.getDeltaX()) % width; int dirY = (height + y + dir.getDeltaY()) % height; Square neighbour = grid[dirX][dirY]; square.link(neighbour, dir); } Let us try the Replace Method with Method Object technique instead. Copy public class BoardCreator { private Square[][] grid; private Board board; private int width; private int height; BoardCreator(Square[][] grid) { assert grid != null; this.grid = grid; this.board = new Board(grid); this.width = board.getWidth(); this.height = board.getHeight(); } public Board create() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Square square = grid[x][y]; for (Direction dir : Direction.values()) { setLink(square, dir, x, y); } } } return this.board; } private void setLink(Square square, Direction dir, int x, int y) { int dirX = (width + x + dir.getDeltaX()) % width; int dirY = (height + y + dir.getDeltaY()) % height; Square neighbour = grid[dirX][dirY]; square.link(neighbour, dir); } } Not only have we ended up only with methods shorter than 15 lines of code and avoided creating methods with long parameter lists, but the code is actually easier to read, test, and reuse. Common Objections to Writing Short Units[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#common-objections-to-writing-short-units) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ### Objection: Having More Units Is Bad for Performance[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#objection-having-more-units-is-bad-for-performance) _“Writing short units means having more units, and therefore more method calls. That will never perform.”_ Indeed, theoretically, there is a performance penalty for having more units. There will be more method invocations (compared to having fewer, longer units). For each invocation, a bit of work needs to be done by the Java Virtual Machine (JVM). **In practice, this is almost never a problem. In the worst case, we are talking about microseconds**. Unless a unit is executed hundreds of thousands of times in a loop, the performance penalty of a method invocation is not noticeable. Also, the JVM is _very_ good at optimizing the overhead of method invocations. ### Objection: Code Is Harder to Read When Spread Out[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#objection-code-is-harder-to-read-when-spread-out) _“Code becomes harder to read when spread out over multiple units.”_ Well, psychology says that is not the case. **People have a working memory of about seven items, so someone who is reading a unit that is significantly longer than seven lines of code cannot process all of it**. The exception is probably the original author of a piece of source code while he or she is working on it (but not a week later). ### This Unit Is Impossible to Split Up[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#this-unit-is-impossible-to-split-up) _“My unit really cannot be split up.”_ Sometimes, splitting a method is indeed difficult. Take, for instance, a properly formatted `switch` statement in Java. For each case of the `switch` statement, there is a line for the case itself, at least one line to do anything useful, and a line for the `break` statement. So, anything beyond four cases becomes very hard to fit into 15 lines of code, and a `case` statement cannot be split. However, it is true that sometimes a source code statement simply cannot be split. A typical example in enterprise software is SQL query construction. Copy public static void printDepartmentEmployees(String department) { Query q = new Query(); for (Employee e : q.addColumn("FamilyName") .addColumn("Initials") .addColumn("GivenName") .addColumn("AddressLine1") .addColumn("ZIPcode") .addColumn("City") .addTable("EMPLOYEES") .addWhere("EmployeeDep='" + department + "'") .execute()) { System.out.println("
" + e.getAddressLine1() + "
" + e.getZipCode() + e.getCity() + "
"); } } This example has 16 lines of code. However, there are just three statements. The second statement contains an expression that spans nine lines. Indeed, you cannot extract just this statement; neither the Extract Method nor the Replace Method with Method Object technique is applicable, at least not directly. If you are faced with a unit that seems impossible to refactor, do not ignore it and move on to another programming task, but indeed raise the issue with your team members and team lead. > When a refactoring seems possible but doesn’t make sense, rethink the architecture of your system. ### There Is No Visible Advantage in Splitting Units[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code#there-is-no-visible-advantage-in-splitting-units) _“Putting code in_ `_doSomethingOne_`_,_ `_doSomethingTwo_`_,_ `_doSomethingThree_` _has no benefit over putting the same code all together in one long_ `_doSomething_`_.”_ Actually, it does, provided you choose better names than `doSomethingOne`, `doSomethingTwo`, and so on. Each of the shorter units is, on its own, easier to understand than the long `doSomething`. More importantly, you may not even need to consider all the parts, especially since each of the method names, when chosen carefully, serves as documentation indicating what the unit of code is supposed to do. Moreover, the long `doSomething` typically will combine multiple tasks. **That means that you can only reuse** `**doSomething**` **if you need the exact same combination**. Most likely, **you can reuse each of** `**doSomethingOne**`**,** `**doSomethingTwo**`**, and so on much more easily**. > Put code in short units (at most 15 lines of code) that have carefully chosen names that describe their function. [PreviousCode Smells](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/code-smells) [NextWrite Simple Units of Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-simple-units-of-code) Last updated 3 years ago --- # Keep Unit Interfaces Small | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small.md) . We can agree that a method with zero arguments is a good method, we don’t have to worry too much about it. The perfect world will be if all methods have zero arguments, but we know that’s not possible. Sometimes we’ll end up writing a method containing six or more arguments, like this method: Copy void createUser(String email, String userName, String password, String country, String city, String street, String phone) { // ... } // createUser("cleancode@gpcoder.com", "gpcoder", "str0ng-p4wd", null, null, null, "+84xxxxxxxxx"); In the method above, we have seven arguments in total, and apparently, they don’t have a logical order. We could try to make sense of these arguments, but we can only guess by just looking at the arguments. In the Clean Code book, Uncle Bob (Robert C. Martin) explains that "_an ideal argument’s number for a function is zero (niladic function). Followed by one (monadic function) and closely by two arguments (dyadic function). Functions with three arguments (triadic function) should be avoided if possible. More than three arguments (polyadic function) are only for very specific cases and then shouldn’t be used anyway_". In my opinion, this a great guideline to follow to write better code, but they’re just guidelines, not strict rules that you have to follow no matter what. Motivation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#motivation) ------------------------------------------------------------------------------------------------------------------------- Reducing the number of arguments in methods offers several advantages: * More readable, and easier to understand because probably the methods are smaller and follow the [Single Responsibility Principle](https://gpcoder.gitbook.io/clean-code/bonus/solid-principle/srp-single-responsibility-principle) . * Easier to reuse and modify because they do not depend on too much external input. * Easier to test: by making the method smaller, testing problems individually are pretty simple. We can test the paths in the main function and have a collection of smaller tests for each individual method. How to Apply the Guideline[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#how-to-apply-the-guideline) --------------------------------------------------------------------------------------------------------------------------------------------------------- Having small interfaces is a good idea. How small should an interface be? In practice, an upper bound of **four** seems reasonable: **a method with four parameters is still reasonably clear, but a method with five parameters is already getting difficult to read and has too many responsibilities**. ### **The Replace Method with the Data Transfer Object Refactoring Technique**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#the-replace-method-with-the-data-transfer-object-refactoring-technique) One way to solve this is to use the **Replace Method with the Data Transfer Object** (DTO or parameter objects) refactoring technique. In the next example, I’m going to show how to use the Parameter Object to reduce the arguments’ number using the sample function shown earlier: Copy class User { private String email; private String userName; private String password; private String phone; private Address address; } class Address { private String country; private String city; private String street; } void createUser(User user) { // ... } We’re able to reduce the argument’s number to only one. Common Objections to Keeping Unit Interfaces Small[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#common-objections-to-keeping-unit-interfaces-small) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Objection: Parameter Objects with Large Interfaces[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#objection-parameter-objects-with-large-interfaces) _“The parameter object I introduced now has a constructor with too many parameters.”_ Copy class User { private String email; private String userName; private String password; private String phone; private String country; private String city; private String street; public User(String email, String userName, String password, String phone, String country, String city, String street) { } } If all went well, you have grouped a number of parameters into an object during the refactoring of a method with a large interface. It may be the case that your object now has a lot of parameters because they apparently fit together. Instead of having a constructor with many arguments, we can actually group parameters together inside another object, like the example above, instead of having 7 parameters in a constructor, we can create an Address object to group related fields together (country, address, street). In general, you should not refuse to introduce a parameter object, but rather think about the structure of the object you are introducing and how it relates to the rest of your code. Another way to avoid constructors with too many parameters is to use the **Builder Design Pattern**. ### Refactoring Large Interfaces Does Not Improve My Situation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#refactoring-large-interfaces-does-not-improve-my-situation) _“When I refactor my method, I am still passing a lot of parameters to another method.”_ Getting rid of large interfaces is not always easy. It usually takes more than refactoring one method. Normally, you should continue splitting responsibilities into your methods, so that you access the most primitive parameters only when you need to manipulate them separately. ### Frameworks or Libraries Prescribe Interfaces with Long Parameter Lists[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small#frameworks-or-libraries-prescribe-interfaces-with-long-parameter-lists) _“The interface of a framework we’re using has nine parameters. How can I implement this interface without creating a unit interface violation?”_ Sometimes frameworks/libraries define interfaces or classes with methods that have long parameter lists. Implementing or overriding these methods will inevitably lead to long parameter lists in your own code. These types of violations are impossible to prevent, but their impact can be limited. * To limit the impact of violations caused by third-party frameworks or libraries, it is best to isolate these violations—for instance, by using wrappers or adapters. * Selecting a different framework/library is also a viable alternative, although this can have a large impact on other parts of the codebase. [PreviousWrite Code Once](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once) [NextWrite Clean Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code) Last updated 3 years ago --- # Write Code Once | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once.md) . One well-known principle in software engineering states doesn’t repeat yourself, also known as the [DRY](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) principle. A very obvious violation of DRY is the application of copy/paste to create duplicates of large portions of source code within the same code base. These duplicate pieces of code, are also known as code clones. Copying existing code looks like a quick win, however copied code leads to duplicates, and duplicates are a problem. Motivation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#motivation) -------------------------------------------------------------------------------------------------------------- ### Duplicated Code Is Harder to Analyze[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#duplicated-code-is-harder-to-analyze) The fundamental problem of duplication is not knowing whether there is another copy of the code that you are analyzing, how many copies exist, and where they are located. ### Duplicated Code Is Harder to Modify[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#duplicated-code-is-harder-to-modify) If duplicated code contains a bug, the same bug appears multiple times. Therefore, duplicated code is harder to modify; you may need to repeat bug fixes multiple times. A fix has to be made in a duplicate in the first place! This is why duplication is a typical source of so-called regression bugs: functionality that has worked normally before suddenly stops working (because a duplicate was overlooked). This, in turn, requires knowing that a fix has to be made in a duplicate in the first place! This is why duplication is a typical source of so-called regression bugs: functionality that has worked normally before suddenly stops working (because a duplicate was overlooked). The same problem holds for regular changes. When code is duplicated, changes may need to be made in multiple places, and having many duplicates makes changing a codebase unpredictable. Types of Duplication[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#types-of-duplication) ---------------------------------------------------------------------------------------------------------------------------------- * Type 1: Exact copy, only differences in white space and comments. * Type 2: Same as type 1, but also variable renaming. * Type 3: Same as type 2, but also changing or adding a few statements. * Type 4: Semantically identical, but not necessarily the same syntax. Type 1 clones are easier to detect and recognize (both by humans and computers). Some tools available are somewhere between type 2 and 3, that is allowing more than just identifier differences but not allowing completely arbitrary statement changes. Full type 3 detection is often not desirable, as depending on the number of differences allowed, this would result in many false indications. Type 4 detection requires full parsing. How to Apply the Guideline[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#how-to-apply-the-guideline) ---------------------------------------------------------------------------------------------------------------------------------------------- To avoid the problem of duplicated bugs, **never reuse code by copying and pasting existing code fragments**. Instead, put it in a method if it is not already in one, so that you can call it the second time that you need it. ### Example of code duplicated[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#example-of-code-duplicated) Consider a system that manages bank accounts. In this system, money transfers between accounts are represented by objects of the `Transfer` class (not shown here). The bank offers checking accounts represented by class `CheckingAccount`: Copy public class CheckingAccount { private int transferLimit = 100; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Check withdrawal limit: if (amount.greaterThan(this.transferLimit)) { throw new BusinessException("Limit exceeded!"); } // 2. Assuming result is 9-digit bank account number, validate 11-test: int sum = 0; for (int i = 0; i < counterAccount.length(); i++) { sum = sum + (9-i) * Character.getNumericValue( counterAccount.charAt(i)); } if (sum % 11 == 0) { // 3. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); return result; } else { throw new BusinessException("Invalid account number!"); } } } A class is needed to represent this new account type. Suppose the existing class is simply copied, renamed, and adapted. This would be the result: Copy public class SavingsAccount { CheckingAccount registeredCounterAccount; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Assuming result is 9-digit bank account number, validate 11-test: int sum = 0; // Start of short clone for (int i = 0; i < counterAccount.length(); i++) { sum = sum + (9 - i) * Character.getNumericValue( counterAccount.charAt(i)); } if (sum % 11 == 0) { // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // End of code clone // 3. Check whether withdrawal is to registered counter account: if (result.getCounterAccount().equals(this.registeredCounterAccount)) { return result; } else { throw new BusinessException("Counter-account not registered!"); } } else { throw new BusinessException("Invalid account number!!"); } } } ### **The Extract Method Refactoring Technique**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#the-extract-method-refactoring-technique) Copy public class Account { // Extract method as a utility class public static boolean isValid(String number) { int sum = 0; for (int i = 0; i < number.length(); i++) { sum = sum + (9 - i) * Character.getNumericValue(number.charAt(i)); } return sum % 11 == 0; } } public class CheckingAccount { private int transferLimit = 100; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Check withdrawal limit: if (amount.greaterThan(this.transferLimit)) { throw new BusinessException("Limit exceeded!"); } if (Accounts.isValid(counterAccount)) { // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); return result; } else { throw new BusinessException("Invalid account number!"); } } } public class SavingsAccount { CheckingAccount registeredCounterAccount; public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Assuming result is 9-digit bank account number, // validate with 11-test: if (Accounts.isValid(counterAccount)) { // Start of short clone // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // End of code clone if (result.getCounterAccount().equals(this.registeredCounterAccount)) { return result; } else { throw new BusinessException("Counter-account not registered!"); } } else { throw new BusinessException("Invalid account number!!"); } } } The clone has disappeared, but the following issues remain: * Even though according to the definition, the clone has disappeared, there is still logically repeated in the two classes. * The extracted fragment had to be put in a third class, just because in Java every method needs to be in a class. The class to which the extracted method was added runs the risk of becoming a mixture of unrelated methods. This leads to a _large class smell_ and _tight coupling_. Having a large class is a smell because it signals that there are multiple unrelated functionalities within the class. This tends to lead to tight coupling when methods need to know implementation details in order to interact with such a large class. ### **The Extract Superclass Refactoring Technique**[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#the-extract-superclass-refactoring-technique) The Extract Superclass refactoring technique uses this feature by extracting a fragment of code lines not just to a method, but to a new class that is the superclass of the original class. So, to apply this technique, you create a new `Account` class like so: Copy public class Account { public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { // 1. Assuming result is 9-digit bank account number, validate 11-test: int sum = 0; // Start of extracted clone for (int i = 0; i < counterAccount.length(); i++) { sum = sum + (9 - i) * Character. getNumericValue(counterAccount.charAt(i)); } if (sum % 11 == 0) { // 2. Look up counter account and make transfer object: CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); Transfer result = new Transfer(this, acct, amount); // End of extracted clone return result; } else { throw new BusinessException("Invalid account number!"); } } } public class CheckingAccount extends Account { private int transferLimit = 100; @Override public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { if (amount.greaterThan(this.transferLimit)) { throw new BusinessException("Limit exceeded!"); } return super.makeTransfer(counterAccount, amount); } } public class SavingsAccount extends Account { CheckingAccount registeredCounterAccount; @Override public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { Transfer result = super.makeTransfer(counterAccount, amount); if (result.getCounterAccount().equals(this.registeredCounterAccount)) { return result; } else { throw new BusinessException("Counter-account not registered!"); } } } All functionality is now exactly where it belongs. The part of making a transfer that is the same for all accounts is in the `Account` class, while the parts that are specific to certain types of accounts are in their respective classes. All duplication has been removed. As the comments indicate, the `makeTransfer` method in the `Account` superclass has two responsibilities. Let makes the new Account class even more maintainable: Copy public class Account { public Transfer makeTransfer(String counterAccount, Money amount) throws BusinessException { if (isValid(counterAccount)) { CheckingAccount acct = Accounts.findAcctByNumber(counterAccount); return new Transfer(this, acct, amount); } else { throw new BusinessException("Invalid account number!"); } } public static boolean isValid(String number) { int sum = 0; for (int i = 0; i < number.length(); i++) { sum = sum + (9 - i) * Character.getNumericValue(number.charAt(i)); } return sum % 11 == 0; } } Common Objections to Avoiding Code Duplication[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#common-objections-to-avoiding-code-duplication) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Copying from Another Codebase Should Be Allowed[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#copying-from-another-codebase-should-be-allowed) _“Copying and pasting code from another codebase is not a problem because it will not create a duplicate in the codebase of the current system.”_ Technically, that is correct: it does not create a duplicate in the codebase of the current system. Copying code from another system may seem beneficial if the code solves the exact same problem in the exact same context. However, in any of the following situations you will run into problems: * **The other (original) codebase is still maintained**: Your copy will not benefit from the improvements made in the original codebase. Therefore, do not copy, but rather import the functionality needed (that is, add the other codebase to your classpath). * **The other codebase is no longer maintained and you are working on rebuilding this codebase**: In this case, you definitely should not copy the code. Often, rebuilds are caused by maintainability problems or technology renewals. In the case of maintainability issues, you would be defeating the purpose by copying code. You are introducing code that is determined to be (on average) hard to maintain. In the case of technology renewals, you would be introducing limitations of the old technology into the new codebase, such as an inability to use abstractions that are needed for reusing functionality efficiently. ### Slight Variations, and Hence Duplication, Are Unavoidable[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#slight-variations-and-hence-duplication-are-unavoidable) _“Duplication is unavoidable in our case because we need slight variations of common functionality.”_ Indeed, systems often contain slight variations of common functionality. For instance, some functionality is slightly different for different operating systems, for other versions (for reasons of backward compatibility), or for different customer groups. However, this does not imply that duplication is unavoidable. **You need to find those parts of the code that are shared by all variants and move them to a common superclass**. You should strive to model variations in the code in such a way that they are explicit, isolated, and testable. ### This Code Will Never Change[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#this-code-will-never-change) _“This code will never, ever change, so there is no harm in duplicating it.”_ If it is absolutely, completely certain that code will never, ever change, duplication (and every other aspect of maintainability) is not an issue. For a start, you have to be absolutely, completely certain that the code in question also does not contain any bugs that need fixing. Apart from that, the reality is that systems change for many reasons, each of which may eventually lead to changes in parts deemed to never, ever change: * **The** _**functional requirements**_ **of the system may change** because of changing users, changing behavior, or a change in the way the organization does business. * **The** _**organization**_ **may change** in terms of ownership, responsibilities, development approach, development process, or legislative requirements. * _**Technology**_ **may change**, typically in the system’s environment, such as the operating system, libraries, frameworks, or interfaces to other applications. * _**The code**_ **itself may change**, because of bugs, refactoring efforts, or even cosmetic improvements. That is why we argue that most of the time the expectation that code never changes is unfounded. So accepting duplication is really nothing more than accepting the risk that someone else will have to deal with it later if it happens. ### Duplicates of Entire Files Should Be Allowed as Backups[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#duplicates-of-entire-files-should-be-allowed-as-backups) _“We are keeping copies of entire files in our codebase as backups. Every backup is an unavoidable duplicate of all other versions.”_ We recommend keeping backups, but not in the way implied by this objection (inside the codebase). **Version control systems** such as SVN and Git provide a much better backup mechanism. If those are not available, move backup files to a directory next to the root of the codebase, not inside it. Why? Because sooner or later you will lose track of which variant of a file is the right one. ### Unit Tests Are Covering Me[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#unit-tests-are-covering-me) _“Unit tests will sort out whether something goes wrong with a duplicate.”_ This is true only if the duplicates are in the same method, and the unit test of the method covers both. If the duplicates are in other methods, it can be true only if a code analyzer alerts you if duplicates are changing. Otherwise, unit tests would not necessarily signal that something is wrong if only one duplicate has changed. Hence, **you cannot rely only on the tests (identifying symptoms) instead of addressing the root cause of the problem** (using duplicate code). You should not assume that eventual problems will be fixed later in the development process when you could avoid them altogether right now. ### Duplication in String Literals Is Unavoidable and Harmless[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-code-once#duplication-in-string-literals-is-unavoidable-and-harmless) _“I need long string literals with a lot of duplication in them. Duplication is unavoidable and does not hurt because it is just in literals.”_ This is a variant of one of the objections discussed in [Write Short Unit of Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-short-units-of-code) (“This unit is impossible to split”). We often see code that contains long SQL queries or XML or HTML documents appearing as string literals in Java code. Sometimes such literals are complete clones, but more often parts of them are repeated. For instance, we have seen SQL queries of more than a hundred lines of code that differed only in the sorting order (`order by asc` versus `order by desc`). This type of duplication is not harmless even though technically they are not in the Java logic itself. It is also not unavoidable; in fact this type of duplication can be avoided in a straightforward fashion: * **Extract to a method** that uses string concatenation and parameters to deal with variants. * **Use a templating engine** to generate HTML output from smaller, nonduplicated fragments that are kept in separate files. [PreviousWrite Simple Units of Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-simple-units-of-code) [NextKeep Unit Interfaces Small](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small) Last updated 3 years ago --- # Error Handling | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling.md) . Use Exceptions Rather Than Return Codes[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#use-exceptions-rather-than-return-codes) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Returning error codes leads to deeply nested structures. Refer to this [example](https://gpcoder.gitbook.io/clean-code/the-key-principles/functions#prefer-exceptions-to-returning-error-codes) . Put all code inside the try block[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#put-all-code-inside-the-try-block) ------------------------------------------------------------------------------------------------------------------------------------------------------------- If the keyword try exists in a function, it should be the very first word in the function and there should be nothing after the catch/finally blocks. Copy public void performLogin(UserDto userDto) { try { login(userDto); } catch(Exception ex) { log.error(ex.getMessage(), ex); throw new BadCredentialExceptoin(); } redirect(); // Should move to try block } Copy public void performLogin(UserDto userDto) { try { login(userDto); redirect(); } catch(Exception ex) { log.error(ex.getMessage(), ex); throw new BadCredentialExceptoin(); } } Use Unchecked Exceptions[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#use-unchecked-exceptions) ------------------------------------------------------------------------------------------------------------------------------------------- The checked exception is an Open/Closed Principle violation. If you throw a checked exception from a method in your code and the `catch` is three levels above, _you must declare that exception in the signature of each method between you and the_ `_catch_`. This means that a change at a low level of the software can force signature changes on many higher levels. The changed modules must be rebuilt and redeployed, even though nothing they care about changed. Encapsulation is broken because all functions in the path of a throw must know about the details of that low-level exception. Checked exceptions can sometimes be useful if you are writing a critical library: You must catch them. But in general application development, the dependency costs outweigh the benefits. Copy class UserNotFoundException extends Exception { // Checked exception public UserNotFoundException(String message) { super(message); } } class AuthException extends Exception { // Checked exception public AuthException(String message) { super(message); } } public class AuthController { private AuthService authService; public void login(AuthDto dto) { try { authService.auth(dto); } catch(UserNotFoundException ex) { } catch(AuthException ex) { } } } public class AuthService { private AuthService authService; // Must rethrow or catch a checked exception public void login(AuthDto dto) throws UserNotFoundException, AuthException { User user = getUserByEmail(dto.getEmail()); if(notMatch(user.getPasword(), dto.getPassword()) { throw new AuthException("User does not exist"); } // Login success } } public class UserService throws UserNotFoundException { private UserRepository userRepository; public User getUserByEmail(String email) throws UserNotFoundException { User user = userRepository.getUserByEmail(email); if (user == null) { throw new UserNotFoundException("User does not exist"); } return user; } } Copy class UserNotFoundException extends RuntimeException { // Unchecked exception public UserNotFoundException(String message) { super(message); } } class AuthException extends RuntimeException { // Unchecked exception public AuthException(String message) { super(message); } } public class AuthController { private AuthService authService; public void login(AuthDto dto) { try { authService.auth(dto); } catch(UserNotFoundException ex) { } catch(AuthException ex) { } } } public class AuthService { private AuthService authService; public void login(AuthDto dto) { User user = getUserByEmail(dto.getEmail()); if(notMatch(user.getPasword(), dto.getPassword()) { throw new AuthException("User does not exist"); } // Login success } } public class UserService throws UserNotFoundException { private UserRepository userRepository; public User getUserByEmail(String email) { User user = userRepository.getUserByEmail(email); if (user == null) { throw new UserNotFoundException("User does not exist"); } return user; } } Provide Context with Exceptions[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#provide-context-with-exceptions) --------------------------------------------------------------------------------------------------------------------------------------------------------- Each exception that you throw should provide enough context to determine the source and location of an error. Copy class UserNotFoundException extends RuntimeException { // Unchecked exception public UserNotFoundException(String message) { super(message); } } class AuthException extends RuntimeException { // Unchecked exception public AuthException(String message) { super(message); } } public class AuthController { private AuthService authService; public void login(AuthDto dto) { try { authService.auth(dto); } catch(AuthException ex) { log.error("Auth failed", ex); } } } public class AuthService { private AuthService authService; public void login(AuthDto dto) { try { User user = getUserByEmail(dto.getEmail()); if(notMatch(user.getPasword(), dto.getPassword()) { throw new AuthException("User does not exist"); } // Login success } catch (UserNotFoundException ex) { throw new AuthException("Can not get user"); // Missing stack trace from root exception } } } public class UserService throws UserNotFoundException { private UserRepository userRepository; public User getUserByEmail(String email) { User user = userRepository.getUserByEmail(email); if (user == null) { throw new UserNotFoundException("User does not exist"); } return user; } } Copy class AuthException extends RuntimeException { // Unchecked exception public AuthException(String message, Throwable cause) { super(message, cause); // Accept stack trace from root exception } } public class AuthService { private AuthService authService; public void login(AuthDto dto) { try { User user = getUserByEmail(dto.getEmail()); if(notMatch(user.getPasword(), dto.getPassword()) { throw new AuthException("User does not exist"); } // Login success } catch (UserNotFoundException ex) { throw new AuthException("Can not get user", ex); // Provide the cause of exception } } } Define Exception Classes in Terms of a Caller’s Needs[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#define-exception-classes-in-terms-of-a-callers-needs) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- We should simplify our code considerably by wrapping the API that we are calling and making sure that it returns a common exception type. Copy public void run() { try { LocalPort port = new LocalPort(); port.open(); } catch (DeviceResponseException e) { reportPortError(e); logger.log("Device response exception", e); } catch (ATM1212UnlockedException e) { reportPortError(e); logger.log("Unlock exception", e); } catch (GMXError e) { reportPortError(e); logger.log("Device response exception"); } finally { // … } } public class LocalPort { public void open() throws DeviceResponseException, ATM1212UnlockedException, GMXError { // Do something } } Copy public void run() { try { LocalPort port = new LocalPort(); port.open(); } catch (PortDeviceFailure e) { reportError(e); logger.log(e.getMessage(), e); } finally { // … } } public class PortDeviceFailure extends RuntimeException { // exception wrapper public PortDeviceFailure(String message, Throwable cause) { super(message, cause); } } public class LocalPort { public void open() { try { // Do something } catch (DeviceResponseException e) { throw new PortDeviceFailure("Device response exception", e); } catch (ATM1212UnlockedException e) { throw new PortDeviceFailure("Unlock exception", e); } catch (GMXError e) { throw new PortDeviceFailure("Device response exception", e); } } } Wrapping third-party APIs is a best practice. When you wrap a third-party API, you minimize your dependencies upon it: * You can choose to move to a different library in the future without much penalty. * Wrapping also makes it easier to mock out third-party calls when you are testing your own code. Don’t Return Null[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#dont-return-null) ---------------------------------------------------------------------------------------------------------------------------- Returning null maybe leads to deeply nested structures. Copy public void registerItem(Item item) { if (item != null) { ItemRegistry registry = peristentStore.getItemRegistry(); if (registry != null) { Item existing = registry.getItem(item.getID()); if (existing.getBillingPeriod().hasRetailOwner()) { existing.register(item); } } } } It’s easy to say that the problem with the code above is that it is missing a `null` check, but in actuality, the problem is that it has _too many_. If you are tempted to return `null` from a method, consider throwing an exception or returning a SPECIAL CASE object instead. Copy List employees = getEmployees(); if (employees != null) { for (Employee e : employees) { totalPay += e.getPay(); } } public List getEmployees() { return null; } Copy List employees = getEmployees(); for (Employee e : employees) { totalPay += e.getPay(); } public List getEmployees() { return Collections.emptyList(); } Consider returning an `empty` list instead of a `null` value Don’t Pass Null[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#dont-pass-null) ------------------------------------------------------------------------------------------------------------------------ Returning null from methods is bad, but passing null into methods is worse. Unless you are working with an API which expects you to pass null, you should avoid passing null in your code whenever possible. Copy public double xProjection(Point p1, Point p2) { return (p2.x – p1.x) * 1.5; } We’ll get a NullPointerException if a caller passes a null parameter. How can we fix it? We could create a new exception type and throw it: Copy public double xProjection(Point p1, Point p2) { if (p1 == null || p2 == null) { throw InvalidArgumentException("Invalid argument for MetricsCalculator.xProjection"); } return (p2.x –p1.x) *1.5; } // alternative public double xProjection(Point p1, Point p2) { assert p1 != null : "p1 should not be null"; // throws AssertionException assert p2 != null : "p2 should not be null"; // throws AssertionException return (p2.x –p1.x) *1.5; } It’s good documentation, but it doesn’t solve the problem. If someone passes `null`, we’ll still have a runtime error. In most programming languages there is no good way to deal with a null that is passed by a caller accidentally. Because this is the case, the rational approach is to **forbid passing null by default.** When you do, you can code with the knowledge that a null in an argument list is an indication of a problem, and end up with far fewer careless mistakes. Fail fast[](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling#fail-fast) ------------------------------------------------------------------------------------------------------------- Refer to [Fail Fast principle](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle) [PreviousComments](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/comments) [NextException handling best practices](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/error-handling/exception-handling-best-practices) Last updated 4 years ago --- # Write Clean Code | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code.md) . Code smells are coding patterns that hint that a problem is present. Introducing or not removing such patterns is bad practice, as they decrease the maintainability of code. Boy Scouts have a rule that says, “Always leave the code better than you found it”. Applying the Boy Scout rule to software development means that once you are writing or modifying a piece of code, you have the opportunity to make small improvements as well. The result is that you leave the code cleaner and more maintainable than you found it. If you are adjusting a piece of code now, apparently there is a need for maintaining it. That increases the chance that you will revisit that same code later. When you revisit that code again, you will benefit from the refactoring you are doing now. How to Apply the Guideline[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code#how-to-apply-the-guideline) ----------------------------------------------------------------------------------------------------------------------------------------------- 1. Leave no unit-level code smells behind. 2. Leave no bad comments behind. 3. Leave no code in comments behind. 4. Leave no dead code behind. 5. Leave no long identifier names behind. 6. Leave no magic constants behind. 7. Leave no badly handled exceptions behind. See details in the sections: [The key principles of clean code.](https://gpcoder.gitbook.io/clean-code/the-key-principles-of-clean-code/meaningful-names) Common Objections to Writing Clean Code[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code#common-objections-to-writing-clean-code) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Objection: Comments Are Our Documentation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code#objection-comments-are-our-documentation) _“We use comments to document the workings of the code.”_ Comments that tell the truth can be a valuable aid to less experienced developers who want to understand how a piece of code works. In practice, however, most comments in code lie—not on purpose, of course, but comments often tell an outdated version of the truth. Outdated comments become more and more common as the system gets older. Keeping comments in sync with code is a task that requires precision and a lot of times is overlooked during maintenance. Code that “tells the story” itself does not require lengthy comments to document its workings. By keeping units small and simple, and by using descriptive names for identifiers, using comments for documentation is seldom necessary. ### Objection: Exception Handling Causes Code Additions[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code#objection-exception-handling-causes-code-additions) _“Implementing exception classes forces me to add a lot of extra code without visible benefits.”_ Exception handling is an important part of _defensive programming_: coding to prevent unstable situations and unpredictable system behavior. Anticipating unstable situations means trying to foresee what can go wrong. This does indeed add to the burden of analysis and coding. However, this is an investment. The benefits of exception handling may not be visible now, but they definitely will prove valuable in preventing and absorbing unstable situations in the future. By defining exceptions, you are documenting and safeguarding your assumptions. They can later be adjusted when circumstances change. ### Objection: Why Only These Coding Guidelines?[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code#objection-why-only-these-coding-guidelines) _“We use a much longer list of coding conventions and quality checks in our team. This list of seven seems like an arbitrary selection with many important omissions.”_ Having more guidelines and checks than the seven in this chapter is of course not a problem. These seven rules are the ones we consider the most important for writing maintainable code and the ones that should be adhered to by every member on the development team. A risk of having many guidelines and checks is that developers can be overwhelmed by them and focus their efforts on the less critical issues. However, teams are obviously allowed to extend this list with items that they find indispensable for building a maintainable system. [PreviousKeep Unit Interfaces Small](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/keep-unit-interfaces-small) [NextAutomate Tests](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests) Last updated 3 years ago --- # Automate Tests | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests.md) . Automated unit tests are tests of code units themselves described in code that runs autonomously. The same holds for other types of testing, such as regression tests and user acceptance tests: automate as much as possible, using a standard _test framework_. For unit tests, a common framework is [jUnit](http://junit.org/) . Motivation[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#motivation) ------------------------------------------------------------------------------------------------------------- This section describes the advantages of _automating_ your tests as much as possible. ### Automated Testing Makes Testing Repeatable[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#automated-testing-makes-testing-repeatable) Just like other programs and scripts, automated tests are executed in exactly the same way every time they are run. This makes testing repeatable: if a certain test executes at two different points in time yet gives different answers, it cannot be that the test execution itself was faulty. One can conclude that something has changed in the system that has caused the different outcome. With manual tests, there is always the possibility that tests are not performed consistently or that human errors are made. ### Automated Testing Makes Development Efficient[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#automated-testing-makes-development-efficient) Automated tests can be executed with much less effort than manual tests. The effort they require is negligible and can be repeated as often as you see fit. They are also faster than manual code reviews. You should also test as early in the development process as possible, to limit the effort it takes to fix problems. **Important:** Postponing testing to a late stage in the development pipeline risks late identification of problems. That costs more effort to fix, because code needs to go back through the development pipeline and be merged, and tests must be rerun. ### Automated Testing Makes Code Predictable[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#automated-testing-makes-code-predictable) Technical tests can be automated to a high degree. Take unit tests and integration tests: they test the technical inner workings of code and the cohesion/integration of that code. Without being sure of the inner workings of your system, you might get the right results by accident. A common advantage of automated testing is identifying when regression is occurring. Without a batch of automated unit tests, development quickly turns into a game of whack-a-mole: you implement a change in one piece of code, and while you are working on the next change in another piece of code, you realize you have introduced a bug with your previous change. Automated tests allow you to double-check your entire codebase effortlessly before turning to the next change. And since the automated unit tests follow predefined paths, you can be sure that if you have fixed a bug, it does not pop up on a second run. Thus, running automated tests provides certainty about how the code works. Therefore, the predictability of automated tests also makes the quality of developed code more predictable. ### Tests Document the Code That Is Tested[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#tests-document-the-code-that-is-tested) The script or program code of a test contains assertions about the expected behavior of the system under test. The assert statement plays a double role: as the actual test, and as documentation of the expected behavior. In other words, _tests are examples of what the system does_. ### Writing Tests Make You Write Better Code[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#writing-tests-make-you-write-better-code) Writing tests helps you to write testable code. As a side effect, this leads to code consisting of units that are shorter, simpler, have fewer parameters, and are more loosely coupled (as the guidelines in the previous chapters advise). For example, _a method is more difficult to test when it performs multiple functions instead of only one. To make it easier to test, you move responsibilities to different methods, improving the maintainability of the whole_. That is why some development approaches advocate writing a unit test before writing the code that conforms to the test. Such approaches are called _test-driven development_ (TDD) approaches. You will see that designing a method becomes easier when you think about how you are going to test it: what are the valid arguments of the method, and what should the method return as a result? How to Apply the Guideline[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#how-to-apply-the-guideline) --------------------------------------------------------------------------------------------------------------------------------------------- How you automate tests differs by the types of tests you want to automate. Test types differ in what is tested, by whom, and why. They are ordered from top to bottom based on the scope of the tests. For example, a unit test has the unit as scope, while an end-to-end test, a regression test, and an acceptance test are on the system level. Type What it tests Why Who Unit test Functionality of one unit in isolation Verify that unit behaves as expected Developer (preferably of the unit) Integration test Functionality, performance, or other quality characteristic of at least two classes Verify that parts of the system work together Developer End-to-end test System interaction (with a user or another system) Verify that system behaves as expected Developer Regression test Previously erroneous behavior of a unit, class, or system interaction Ensure that bugs do not re-appear. Verify that all unchanged parts of a system still function correctly after the implementation of a change. Developer Progression test Test of new or adapted parts of a system. Verify that new or parts of the system behaves as expected Developer Acceptance test System interaction (with a user or another system) Confirm the system behaves as required End-user representative (never the developer) Different types of testing call for different automation frameworks. * For unit testing, several well-known Java frameworks are available, such as [jUnit](http://junit.org/) . * For automated end-to-end testing, you need a framework that can mimic user input and capture output. A well-known framework that does just that for web development is [Selenium](http://www.seleniumhq.org/) . * For integration testing, it all depends on the environment in which you are working and the quality characteristics you are testing. [SoapUI](http://www.soapui.org/) is a framework for integration tests that focuses on web services and messaging middleware. * [Apache jMeter](http://jmeter.apache.org/) and [Gatling](https://gatling.io/) are frameworks for testing the performance of Java applications under heavy workloads. Choosing a test framework needs to be done at the team level. Writing integration tests is a specialized skill—but _unit testing is for each and every individual developer_. Java developers are writing unit tests using the most well-known framework _jUnit_. General Principles for Writing Good Unit Tests[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#general-principles-for-writing-good-unit-tests) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- When writing tests, it is important to keep in mind the following general principles: ### Test both normal and special cases[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#test-both-normal-and-special-cases) Test two kinds of cases: * Write tests that confirm that a unit indeed behaves as expected on normal input (called _happy flow_ or _sunny-side_ testing). * Also, write tests that confirm that a unit behaves sensibly on non-normal input and circumstances (called _unhappy flow_ or _rainy-side_ testing). For instance, in jUnit, it is possible to write tests to confirm that a method under test indeed throws a certain exception. ### Maintain tests just like nontest (production) code[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#maintain-tests-just-like-nontest-production-code) When you adjust the code in the system, the changes should be reflected in the unit tests as well. This is most relevant for unit tests, though it applies to all tests. In particular, when adding new methods or enhancing the behavior of existing methods, be sure to add new test cases that cover that new code. ### Write tests that are isolated: their outcomes should reflect only the behavior of the subject being tested[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#write-tests-that-are-isolated-their-outcomes-should-reflect-only-the-behavior-of-the-subject-being-t) That is, each test should act independently of all other tests. For unit testing, this means that each test case should test only one functionality. No unit test should depend on state, such as files written by other tests. That is why a unit test that, say, causes the class under test to access the filesystem or a database server is not a good unit test. ### Measure Coverage to Determine Whether There Are Enough Tests[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#measure-coverage-to-determine-whether-there-are-enough-tests) How many unit tests are needed? One way to assess whether you have written enough unit tests is to measure _coverage_ of your unit tests. Coverage, or more precisely, line coverage, is the percentage of lines of code in your codebase that actually get executed when all unit tests are executed. As a rule of thumb, you should aim for _at least 80% line coverage with a sufficient number of tests—that is, as many lines of test code as production code._ Why 80% coverage (and not 100%)? Any codebase contains fragments of trivial code that technically can be tested, but are so trivial that testing them makes little sense. Take the following typical Java getter method: Copy public String getName() { return this.name; } A minimum of 80% coverage alone is not enough to ensure high-quality unit tests. It is possible to get high coverage by testing just a few high-level methods and _not_ mocking out lower-level methods. That is why we advise a 1-to-1 ratio of production code versus test code. You can measure coverage using a code coverage tool. Well-known examples are the Maven/Gradle plugin [Jacoco](https://www.jacoco.org/) , and the Eclipse plugin [EclEmma](http://www.eclemma.org/) . Examples: ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252FFn8DflT4iSaZ1CwKQF3h%252Fimage.png%3Falt%3Dmedia%26token%3D9c4243fb-c254-4f67-8eec-052a4d357015&width=768&dpr=3&quality=100&sign=9b83b59c6e3c89a9761123f66b1300ba&sv=3) EclEmma coverage report ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252F85Wcdk7G6S9MSDmB2paE%252Fimage.png%3Falt%3Dmedia%26token%3D524e312f-85e0-4917-b32c-c24f4f1c1f21&width=768&dpr=3&quality=100&sign=de41a58e605267df872d72cadb3b433c&sv=3) Line/Branch covarage Common Objections to Automating Tests[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#common-objections-to-automating-tests) ------------------------------------------------------------------------------------------------------------------------------------------------------------------- This section discusses typical objections and limitations regarding automation. They deal with the reasons and considerations to invest in test automation. ### Objection: We Still Need Manual Testing[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#objection-we-still-need-manual-testing) _“Why should we invest in automated tests at all if we still need manual testing?”_ The answer to this question is simply because test automation frees up time to manually test those things that cannot be automated. Consider the downsides of the alternative to automated tests. Manual testing has clear limitations. It is slow, expensive, and hard to repeat in a consistent manner. In fact, technical verification of the system _needs_ to take place anyway, since you cannot manually test code that does not work. Because manual tests are not easily repeatable, even with small code changes a full retest may be needed to be sure that the system works as intended. ### Objection: I Am Not Allowed to Write Unit Tests[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#objection-i-am-not-allowed-to-write-unit-tests) _“I am not allowed to write unit tests because they lower productivity according to my manager.”_ Writing unit tests during development actually improves productivity. It improves system code by shifting the focus from “what code should do” toward “what it should not do.” If you never take into account how the code may fail, you cannot be sure whether your code is resilient to unexpected situations. The disadvantages of not having unit tests are mainly in uncertainty and rework. Every time a piece of code is changed, it requires painstaking review to verify whether the code does what it is supposed to do. ### Objection: Why Should We Invest in Unit Tests When the Current Coverage Is Low?[](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/automate-tests#objection-why-should-we-invest-in-unit-tests-when-the-current-coverage-is-low) _“The current unit test coverage of my system is very low. Why should I invest time now in writing unit tests?”_ We have elaborated on the reasons why unit tests are useful and help you develop code that works predictably. However, when a very large system has little to no unit test code, this may be a burden. After all, it would be a significant investment to start writing unit tests from scratch for an existing system because you would need to analyze all units again. Therefore, you should make a significant investment in unit tests only if the added certainty is worth the effort. This especially applies to critical, central functionality and when there is reason to believe that units are behaving in an unintended manner. Otherwise, add unit tests incrementally each time you change existing code or add new code. [PreviousWrite Clean Code](https://gpcoder.gitbook.io/clean-code/building-maintainable-software/write-clean-code) [NextSOLID Principle](https://gpcoder.gitbook.io/clean-code/bonus/solid-principle) Last updated 3 years ago --- # YAGNI Principle | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/bonus/yagni-principle.md) . A design principle from Extreme Programming (XP) states that **a programmer shouldn't add any functionality until it's actually necessary.** Ron Jeffries, one of the founders of XP wrote that programmers should "**always implement things when you actually need them, never when you foresee that you need them**" and "do the simplest possible thing that will work". **Why is it useful?** * This can help you iterate really quickly. * It helps prevent design fatigue or fear of a large all-encompassing up-front design. **But!** YAGNI is meant to be combined with **continuous refactoring**, automated unit testing, and continuous integration. Failure to refactor code early could require huge amounts of **technical debt** and **rework**. Therefore, in order to do YAGNI well, developers first need to know how to: * write code that's testable * run automated tests [PreviousLoD Principle](https://gpcoder.gitbook.io/clean-code/bonus/lod-principle) [NextDRY Principle](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) Last updated 3 years ago --- # Fail Fast principle | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle.md) . Whenever an error occurs in a running software application there are typically three possible error-handling approaches: * The _**Ignore!**_ approach: the error is ignored and the application continues execution. * The _**Fail fast!**_ approach: the application stops immediately and reports an error. * The _**Fail safe!**_ approach: the application acknowledges the error and continues execution in the best possible way. Which approach is the best one? Which one should you apply in your application? There are some general rules: * We should never “Ignore!” an error — unless there is a really good reason to do so. * During development we should apply the "Fail fast!" approach. * In critical applications the "Fail safe!" approach must be implemented in order to minimize damages. Fail fast![](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle#fail-fast) ---------------------------------------------------------------------------------------- The fail fast principle stands for stopping the current operation as soon as any unexpected error occurs. **When a problem occurs, it fails immediately and visibly.** The _Fail fast!_ approach helps in debugging. * As soon as something goes wrong, the application stops and the error message helps to detect, diagnose and correct the error. * Therefore the _Fail fast!_ approach leads to more reliable software, reduces development and maintenance costs and prevents frustrations and catastrophes that would otherwise risk to appear in production mode. * Even if a bug doesn’t lead to a severe failure, it is always best to detect it as soon as possible, because the costs to fix a bug raise exponentially with the time passed in the development cycle (compile-, test-, production-time). The consequences of bugs appearing during development mode are generally not harmful. The customer doesn’t complain, money doesn’t go to the wrong account, and rockets don’t explode. > _Failing immediately and visibly’ sounds like it would make your software more fragile, but it actually makes it more robust. Bugs are easier to find and fix, so fewer go into production.”_ > > \-- Jim Shore / Martin Fowler — [Fail Fast](http://martinfowler.com/ieeeSoftware/failFast.pdf) ### Immediate and visible failure[](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle#immediate-and-visible-failure) The opposite to fail-fast is fail-silently. Copy try { doSomething(); } catch (Exception ex) { log.error(ex); } A common justification for wrapping everything in a generic try-catch block is that it makes a software feel more stable by not letting end users know about errors in it. This generally is a bad practice. The problem with such approach is that instead of revealing issues in the software, we mask them and thus extend the feedback loop. If something goes wrong with the application, it wouldn’t be obvious. The incorrect behavior is now hidden from the eyes of developers and end users and might stay unnoticed for a long time. Moreover, the application’s persistence state may get corrupted if the code continues executing after an error took place. The fix here is simple, we just need to add a "throw" statement to the catch block: Copy try { doSomething(); } catch (Exception ex) { log.error(ex); throw ex; } Consider a method that reads a property from a configuration file. What should happen when the property isn’t present? A common approach is to return null or a default value: Copy public int maxConnections() { String maxConnections = getProperty("maxConnections"); if (property == null) { return 10; } else { return maxConnections.toInt(); } } For the code that returns a default value, everything will seem fine. But when customers start using the software, they’ll encounter mysterious slowdowns. The outcome is much different when we write the software to fail fast. Then the software stops functioning, and developer slaps his or her forehead and spends a little bit time fixing the problem. A program that fails fast will throw an exception: Copy public int maxConnections() { String maxConnections = getProperty("maxConnections"); if (property == null) { throw new NullReferenceException("maxConnections property not found in " + this.configFilePath); } else { return maxConnections.toInt(); } } ### Fail-fast fundamentals[](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle#fail-fast-fundamentals) Assertions are the key to failing fast. An assertion is a tiny piece of code that checks a condition and then fails if the condition isn’t met. So, when something starts to go wrong, an assertion detects the problem and makes it visible. When writing an assertion, think about what kind of information you’ll need to fix the problem if the assertion fails. Include that information in the assertion message. Don’t just repeat the assertion’s condition; the stack trace will lead to that. Instead, put the error in context. You can create a global exception handler to gracefully handle unexpected exceptions, such as assertions, and bring them to the developers’ attention. If you use a global exception handler, avoid catch-all exception handlers in the rest of your application. They’ll prevent exceptions from reaching your global handler. Fail safe![](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle#fail-safe) ---------------------------------------------------------------------------------------- In development mode we should always apply the _Fail fast!_ approach. In production mode: * We should generally favor the _Fail fast!_ approach by default. * Critical applications that risk leading to high damages in case of a malfunction need customized, context-specific and damage-eliminating (or at least damage-reducing) behavior. * _Fail safe and react appropriately!_ approaches must be applied in fault-tolerant systems. * Repair what you can — but when you must fail, fail noisily and as soon as possible. * Errors should preferably be automatically detected at compile-time, or else as early as possible at run-time. [PreviousDRY Principle](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle) [NextHollywood Principle](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle) Last updated 4 years ago --- # Hollywood Principle | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle.md) . This little sentence opens up a new viewpoint in software. This is one of the important principles every developer should know. In this article, we will try to discuss it. What's Hollywood principle?[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#whats-hollywood-principle) ------------------------------------------------------------------------------------------------------------------------- The Hollywood Principle states, "Don't Call Us, We'll Call You." It's closely related to the [Dependency Inversion Principle](https://deviq.com/principles/dependency-inversion-principle) , and illustrates a different way of writing software from the more traditional form of programming in which one's own code dictates the flow of control. When following the Hollywood Principle, code is written to respond to external events, such as from an existing framework. To explain "you" and "they" in technical terms, first we need to understand how software design works. When we design a software, we try to implement two things. * API * Framework #### API[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#api) An API is used to publish some methods/functions, so the caller/user of the API calls this method to get some useful information. So, the caller does not have any action points to take — only call methods and outputs. #### Framework[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#framework) The framework is a little bit more critical than the API. The framework is maintaining an algorithm, but it expects the value to be produced by the caller of the framework. To put it simply, the framework takes the strategy or business implementation from the caller and calls it when required. With the Hollywood Principle, we can feed our strategy or business implementation, denoting the framework engine/implementation, which calls the fed strategy when required. Real time Example[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#real-time-example) ------------------------------------------------------------------------------------------------------- **Spring DI**: Think about Spring where we declare beans in XML, and Spring container call these beans create Spring beans, inject other beans into it and returns fully configured bean. So by the help of XML, we feed the strategy and Spring container calls them when required. We often called it Dependency Injection so Hollywood Principle’s another name is IOC(Inversion of Control). **Observer pattern/Listener in Swing**: Think about Swing’s actionListener we subscribe to an event like button click, on Blur etc and when this event occurs Swing call our code written in the actionPerformed method. We call those methods as Callback methods because Framework call this method we don’t have to call them but we may provide the implementations of those methods if we want to push some strategies in Framework. Use Case[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#use-case) ------------------------------------------------------------------------------------- Say Cognizant has a resume upload portal where job seekers upload their resumes. When the company does some on-campus recruiting, Cognizant will call them by sending an email to their inbox. We can implement the same thing via the Hollywood principle. Job seekers upload their resumes in the job portal, and Cognizant sends mail to them when an on-campus event occurs. **Cognizant says: Don’t call me, I will call you.** ![](https://gpcoder.gitbook.io/clean-code/~gitbook/image?url=https%3A%2F%2F2690823695-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FfnxBXXXtPb2q20LXB7uL%252Fuploads%252Fupdgv9wJiIbFd3jRTlWc%252Fimage.png%3Falt%3Dmedia%26token%3D240e99fc-0fb9-4eb4-8145-fb456e3b9242&width=768&dpr=3&quality=100&sign=d421a083fe275afb389c18974ea21bc8&sv=3) Let see the implementation. #### Assumption[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#assumption) Here, I have not introduced any interface for the sake of simplicity, and I've not added any complex scenario like a priority, reset, GroupWise mail sending, etc., as I just wanted to show how the Hollywood Principle works. Copy public class Resume { private String email; private String name; private String content; /* getters and setters */ @Override public String toString() { return "Resume [email=" + email + ", name=" + name + ", content=" + content + "]"; } } public class CognizantJobPortal { private static CognizantJobPortal portal = new CognizantJobPortal(); private List resumeList = new ArrayList(); public static CognizantJobPortal get(){ return portal; } private CognizantJobPortal() {} public void uploadContent(String mail ,String name,String content) { Resume resume = new Resume(); resume.setName(name); resume.setEmail(mail); resume.setContent(content); resumeList.add(resume); } public void triggerCampusing(){ for(Resume resume : resumeList){ System.out.println("Sending mail to " + resume.getName() + " at " + resume.getEmail()); } } } public class HollywoodTest { public static void main(String[] args) { CognizantJobPortal.get().uploadContent("shamik@xyz.com", "Shamik Mitra", "A java developer"); CognizantJobPortal.get().uploadContent("Ajanta@vvv.com", "Ajanta Mitra", "A PHP developer"); CognizantJobPortal.get().uploadContent("Swastika@vvv.com", "Swastika Mitra", "A Microservice developer"); CognizantJobPortal.get().uploadContent("Mayukh@vvv.com", "Mayukh Mitra", "A Network engineer"); CognizantJobPortal.get().uploadContent("Samir@123.com", "Samir Mitra", "A java Architect"); // Now trigger campusing CognizantJobPortal.get().triggerCampusing(); } } #### Output[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#output) Copy Sending mail to Shamik Mitra at shamik@xyz.com Sending mail to Ajanta Mitra at Ajanta@vvv.com Sending mail to Swastika Mitra at Swastika@vvv.com Sending mail to Mayukh Mitra at Mayukh@vvv.com Sending mail to Samir Mitra at Samir@123.com Please note that in the CognizantJobPortal class, I maintain a list where uploaded resumes are added. When Cognizant triggers a campusing, the job portal/framework sends the mail to all job seekers who uploaded a CV to Cognizant. Read more: [Library vs Framework](https://gpcoder.gitbook.io/clean-code/bonus/library-vs-framework) References[](https://gpcoder.gitbook.io/clean-code/bonus/hollywood-principle#references) ----------------------------------------------------------------------------------------- * [https://dzone.com/articles/the-hollywood-principle](https://dzone.com/articles/the-hollywood-principle) [PreviousFail Fast principle](https://gpcoder.gitbook.io/clean-code/bonus/fail-fast-principle) [NextLibrary vs Framework](https://gpcoder.gitbook.io/clean-code/bonus/library-vs-framework) Last updated 3 years ago --- # DRY Principle | Clean code For the complete documentation index, see [llms.txt](https://gpcoder.gitbook.io/clean-code/llms.txt) . This page is also available as [Markdown](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle.md) . DRY stand for "Don't Repeat Yourself," a basic principle of software development aimed at reducing the repetition of information. The DRY principle is stated as, "Every piece of knowledge or logic must have a single, unambiguous representation within a system." Structured programming, Aspect Oriented Programming, Component Oriented Programming, and Design Patterns are all, in part, strategies for eliminating duplication. Duplication manifests itself in many forms**:** * Lines of code that look **exactly the same**. * Lines of code that are **similar to**. * **Duplication of implementation**. Example of "exactly the same"[](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle#example-of-exactly-the-same) ----------------------------------------------------------------------------------------------------------------------- Copy class UserService { public void createUser(String email, String password) { if (isEmailValid(email)) { // create user } } private boolean isEmailValid(String email) { String pattern = "email pattern"; Pattern pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(email); return matcher.matches(); } } class SubscriptionService { public void subscribe(String topic, String email) { if (isEmailValid(email)) { // subscribe } } // By copying and pasting an existing class, // we have introduced some duplicated code in the codebase. private boolean isEmailValid(String email) { String pattern = "email pattern"; Pattern pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(email); return matcher.matches(); } } Copy class EmailValidator { public boolean isValid(String email) { String pattern = "email pattern"; Pattern pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(email); return matcher.matches(); } } class UserService { public void createUser(String email, String password) { if (EmailValidator.isValid(email)) { // create user ... } } } class SubscriptionService { public void subscribe(String topic, String email) { if (EmailValidator.isValid(email)) { // subscribe ... } } } Example of "similar to"[](https://gpcoder.gitbook.io/clean-code/bonus/dry-principle#example-of-similar-to) ----------------------------------------------------------------------------------------------------------- The **Template Method Pattern** is a common technique for removing higher-level duplication. Copy interface PageRenderer { void renderPage(); } class HomePage implements PageRenderer{ private void showHeader() { System.out.println("
"); } private void showNavigation() { System.out.println("