Clean Code - sivakrsna/DesignPatterns GitHub Wiki

simple code:

  • 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 has minimal dependencies, which are explicitly defined, and provides a clear and minimal API.
  • Contains no duplication;
  • Expresses all the design ideas that are in the system;
  • Minimizes the number of entities such as classes, methods, functions, and the like
  • The code has to be kept clean over time
  • making it easy to read actually makes it easier to write.

Meaningful Names

  • Choosing good names takes time but saves more than it takes. So take care with your names and change them when you find better ones.
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
  • Choosing names that reveal intent can make it much easier to understand and change code. 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.

👍 the zeroth subscript is the location of a status value and that a status value of 4 means “flagged.” Just by giving these concepts names we can improve the code considerably

if (x[0] == 4)
list1.add(x);

if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
  • Programmers must avoid leaving false clues that obscure the meaning of code. We should avoid words whose entrenched meanings vary from our intended meaning. For example, hp, aix, and sco would be poor variable names because they are the names of Unix platforms or variants.

Make Meaningful Distinctions

  • Distinguish names in such a way that the reader knows what the differences offer.

Use Pronounceable Names

class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
/* ... */
};
to
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;;
private final String recordId = "102";
/* ... */
};

Use Searchable Names

  • the name e is a poor choice for any variable for which a programmer might need to search
  • single-letter names can ONLY be used as local variables inside short methods
  • The length of a name should correspond to the size of its scope
for (int j=0; j<34; j++) {
   s += (t[j]*4)/5;
}
to
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) {
   int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
   int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
   sum += realTaskWeeks;
}

Member Prefixes You also don’t need to prefix member variables with m_ anymore. Your classes and functions should be small enough that you don’t need them. And you should be using an editing environment that highlights or colorizes members to make them distinct.

public class Part {
  private String m_dsc; // The textual description
   void setName(String name) {
     m_dsc = name;
   }
}
_________________________________________________
public class Part {
  String description;
  void setDescription(String description) {
    this.description = description;
  }
}

Interfaces and Implementations Calling it ShapeFactoryImp, or even the hideous CShapeFactory, is preferable to encoding the interface.

Class Names

Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.

Method Names

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 javabean standard.

string name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted())...

When constructors are overloaded, use static factory methods with names that describe the arguments. For example, Complex fulcrumPoint = Complex.FromRealNumber(23.0); is generally better than Complex fulcrumPoint = new Complex(23.0); Consider enforcing their use by making the corresponding constructors private.

Choosing technical names for those things is usually the most appropriate course.

Don’t Add Gratuitous Context In an imaginary application called “Gas Station Deluxe,” it is a bad idea to prefix every class with GSD. Frankly, you are working against your tools. You type G and press the completion key and are rewarded with a mile-long list of every class in the system. Is that wise? Why make it hard for the IDE to help you? Likewise, say you invented a MailingAddress class in GSD’s accounting module, and you named it GSDAccountAddress. Later, you need a mailing address for your customer contact application. Do you use GSDAccountAddress? Does it sound like the right name? Ten of 17 characters are redundant or irrelevant.

Functions

  • The first rule of functions is that they should be small. Functions should not be 100 lines long. Functions should hardly ever be 20 lines long.

Blocks and Indenting This implies that the blocks within if statements, else statements, while statements, and so on should be one line long. Probably that line should be a function call.

FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL.THEY SHOULD DO IT ONLY.

  • If a function does only those steps that are one level below the stated name of the function, then the function is doing one thing. After all, the reason we write functions is to decompose a larger concept (in other words, the name of the function) into a set of steps at the next level of abstraction.

Function 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.

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.

Verbs and Keywords Choosing good names for a function can go a long way toward explaining the intent of the function and the order and intent of the arguments. For example, write(name) is very evocative. Whatever this “name” thing is, it is being “written.” An even better name might be writeField(name), which tells us that the “name” thing is a “field.” This last is an example of the keyword form of a function name. Using this form we encode the names of the arguments into the function name. For example, assertEquals might be better written as assertExpectedEqualsActual(expected, actual). This strongly mitigates the problem of having to remember the ordering of the arguments.

public class UserValidator {
	private Cryptographer cryptographer;
	public boolean checkPassword(String userName, String password) {
		User user = UserGateway.findByName(userName);
		if (user != User.NULL) {
			String codedPhrase = user.getPhraseEncodedByPassword();
			String phrase = cryptographer.decrypt(codedPhrase, password);
			if ("Valid Password".equals(phrase)) {
				Session.initialize();
				return true;
			}
		}
		return false;
	}
}
	

we might also can rename the function checkPasswordAndInitializeSession,

Extract Try/Catch Blocks

	public void delete(Page page) {
		try {
			deletePageAndAllReferences(page);
		}
		catch (Exception e) {
			logError(e);
		}
	}
	private void deletePageAndAllReferences(Page page) throws Exception {
		deletePage(page);
		registry.deleteReference(page.name);
		configKeys.deleteKey(page.name.makeKey());
	}
	private void logError(Exception e) {
		logger.log(e.getMessage());
	}
  • Prefer Exceptions to Returning Error Codes

Duplication may be the root of all evil in software. Many principles and practices have been created for the purpose of controlling or eliminating it.Consider also how object-oriented programming serves to concentrate code into base classes that would otherwise be redundant. Structured programming, Aspect Oriented Programming, Component Oriented Programming, are all, in part, strategies for eliminating duplication. It would appear that since the invention of the subroutine, innovations in software development have been an ongoing attempt to eliminate duplication from our source code.

Every system is built from a domain-specific language designed by the programmers to describe that system. Functions are the verbs of that language, and classes are the nouns.The art of programming is, and has always been, the art of language design.If you follow the rules herein, your functions will be short, well named, and nicely organized.

Comments

  • Clear and expressive code with few comments is far superior to cluttered and complex code with lots of comments.
  • Explain Yourself in Code
// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
                     (employee.age > 65))
Or this?
if (employee.isEligibleForFullBenefits())

Good Comments

  1. Legal Comments For example, copyright and authorship statements are necessary and reasonable things to put into a comment at the start of each source file. // 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.
  2. Informative Comments It is sometimes useful to provide basic information with a comment. For example, consider this comment that explains the return value of an abstract method: // Returns an instance of the Responder being tested. protected abstract Responder responderInstance(); // format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher = Pattern.compile("\d*:\d*:\d* \w*, \w* \d*, \d*");
  3. Explanation of Intent Sometimes a comment goes beyond just useful information about the implementation and provides the intent behind a decision. return 1; // we are greater because we are the right type. //This is our best attempt to get a race condition //by creating large number of threads. for (int i = 0; i < 25000; i++) { ... }
  4. Clarification
  5. TODO Comments //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; }
  6. Amplification A comment may be used to amplify the importance of something that may otherwise seem inconsequential. String listItemContent = match.group(3).trim(); // the trim is real important. It removes the starting // spaces that could cause the item to be recognized // as another list. new ListItemWidget(this, listItemContent, this.level

Commented-Out Code Few practices are as odious as commenting-out code. Don’t do this! 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())); Others who see that commented-out code won’t have the courage to delete it. They’ll think it is there for a reason and is too important to delete. So commented-out code gathers like dregs at the bottom of a bad bottle of wine.

Formatting

  • Analogy- we want to be impressed with the neatness, consistency, and attention to detail that they perceive.

Code formatting is also important. It is too important to ignore and it is too important to treat religiously. Code formatting is about communication, and communication is the professional developer’s first order of business.

You should take care that your code is nicely formatted. You should choose a set of simple rules that govern the format of your code, and then you should consistently apply those rules. If you are working on a team, then the team should agree to a single set of formatting rules and all members should comply. It helps to have an automated tool that can apply those formatting rules for you.

👍 Instance variables, on the other hand, should be declared at the top of the class. 👍 Variable Declarations. Variables should be declared as close to their usage as possible.

  • we should strive to keep our lines short. The old Hollerith limit of 80 is a bit arbitrary, and I’m not opposed to lines edging out to 100 or even 120. I used to follow the rule that you should never have to scroll to the right. But monitors are too wide for that nowadays, and younger programmers can shrink the font so small that they can get 200 characters across the screen. Don’t do that. I personally set my limit at 120.

  • Indentation - A source file is a hierarchy rather like an outline. To make classes, methods, block - hierarchy of scopes visible, we indent the lines of source code in proportion to their position in the hiearchy.