Thursday

Clean Code (Robert Cecil Martin) - Chapter5 Formatting- My summary

I have tried to make a short summary for chapter 5 of the Clean Code(Robert Cecil Martin) book. All codes  and some sentences that i liked too much in the summary are quoted from the book. I hope the summary will also be useful for you.

Vertical Formatting

1. Significant systems can be created with classes up to 200 lines long (maximum 500 lines).
(You can reach average values for some global projects in the book.)

2."Variable Declarations"
Local variables should appear a the top of each function.

private static void readPreferences() {
       InputStream is= null;
       try {
              is= new FileInputStream(getPreferencesFile());
              setPreferences(new Properties(getPreferences()));
              getPreferences().load(is);
       } catch (IOException e) {
              try {
              if (is != null)
                                   is.close();
              } catch (IOException e1) {
              }
       }
}

3."Instance variables"
"The common convention in Java, however, is to put them all at the top of the class."
"The important thing is for the instance variables to be declared in one well-known place. Everybody should know where to go to see the declarations."

In the below example, you see two instance variables declared in the middle of the class. It is hard to realize where the declarations are.
public class public class TestSuite implements Test {
       static public Test createTest(Class<? extends TestCase> theClass, String name) {
       ...
       }
      
       public static Constructor<? extends TestCase> getTestConstructor(Class<? extends TestCase> theClass)
       throws NoSuchMethodException {
              ...
       }
      
       public static Test warning(final String message) {
              ...
       }
      
       private static String exceptionToString(Throwable t) {
              ...
       }
      
       private String fName;
       private Vector<Test> fTests= new Vector<Test>(10);
      
       public TestSuite() {
       }
      
       public TestSuite(final Class<? extends TestCase> theClass) {
              ...
       }
      
       public TestSuite(Class<? extends TestCase> theClass, String name) {
              ...
       }
      
       ... ... ... ... ...
}

4."Dependent Functions."
"If one function calls another, they should be vertically close, and the caller should be above the callee, if at all possible.This gives the program a natural flow."
public class WikiPageResponder implements SecureResponder {
       protected WikiPage page;
       protected PageData pageData;
       protected String pageTitle;
       protected Request request;
       protected PageCrawler crawler;
      
       public Response makeResponse(FitNesseContext context, Request request)
              throws Exception {
              String pageName = getPageNameOrDefault(request, "FrontPage");
              loadPage(pageName, context);
              if (page == null)
                     return notFoundResponse(context, request);
              else
                     return makePageResponse(context);
       }
      
       private String getPageNameOrDefault(Request request, String defaultPageName)
       {
              String pageName = request.getResource();
              if (StringUtil.isBlank(pageName))
                           pageName = defaultPageName;
             
              return pageName;
       }
      
       protected void loadPage(String resource, FitNesseContext context)
                     throws Exception {
              WikiPagePath path = PathParser.parse(resource);
              crawler = context.root.getPageCrawler();
              crawler.setDeadEndStrategy(new VirtualEnabledPageCrawler());
              page = crawler.getPage(context.root, path);
              if (page != null)
                           pageData = page.getData();
       }
      
       private Response notFoundResponse(FitNesseContext context, Request request)
                     throws Exception {
              return new NotFoundResponder().makeResponse(context, request);
       }
      
       private SimpleResponse makePageResponse(FitNesseContext context)
              throws Exception {
              pageTitle = PathParser.render(crawler.getFullPath(page));
              String html = makeHtml(context);
             
              SimpleResponse response = new SimpleResponse();
              response.setMaxAge(0);
              response.setContent(html);
              return response;
       }
}

5."Conceptual Affinity."
"The stronger that affinity, the less vertical distance there should be between them."
The following functions call each other, so the closer to the vertical is better.
public class Assert {
       static public void assertTrue(String message, boolean condition) {
              if (!condition)
                     fail(message);
       }
      
       static public void assertTrue(boolean condition) {
              assertTrue(null, condition);
       }
      
       static public void assertFalse(String message, boolean condition) {
              assertTrue(message, !condition);
       }
      
       static public void assertFalse(boolean condition) {
              assertFalse(null, condition);
       }
}

Horizontal Formatting

6. A good character limit on a line is 100-120. 
"I used to follow the rule that you should never have to scroll to the right."

7."Horizontal Openness and Density"
Surround the assignment operators with white space.
Don't put spaces between the function and the parenthesis.
private void measureLine(String line) {
       lineCount++;
       int lineSize = line.length();
       totalChars += lineSize;
       lineWidthHistogram.addLine(lineSize, lineCount);
       recordWidestLine(lineSize);
}

public static double root2(int a, int b, int c) {

8. "Horizontal Alignment"
The below kind of alignment is not useful.
public class FitNesseExpediter implements ResponseSender
{
       private       Socket               socket;
       private       InputStream          input;
       private       OutputStream        output;
       private       Request              request;
       private       Response             response;
       private       FitNesseContext     context;
       protected     long                 requestParsingTimeLimit;
       private       long                 requestProgress;
       private       long                 requestParsingDeadline;
       private       boolean              hasError;
      
       public        FitNesseExpediter(Socket s,
                                      FitNesseContext context) throws Exception
       {
              this.context = context;
              socket = s;
              input = s.getInputStream();
              output = s.getOutputStream();
              requestParsingTimeLimit = 10000;


9."Breaking Indentation."
USE:
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 "";
       }
}

INSTEAD OF:

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 ""; }
}


References:
Robert C Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Wednesday

Clean Code (Robert Cecil Martin) - Chapter4 Comments - My summary

I have tried to make a short summary for chapter 4 of the Clean Code(Robert Cecil Martin) book. All codes  and some sentences that i liked too much in the summary are quoted from the book. I hope the summary will also be useful for you.


GOOD COMMENTS:
1. Instead of adding comments to the code you can write understandable code without writing comments by making variables, functions, classes, and package names properly.
"Truth can only be found in one place: the code."
"Clear and expressive code with few comments is far superior to cluttered and complex code with lots of comments."

2. "Explain yourself in code"
/* USE the first one instead of the second code snippet containing comments
(The below code explains itself in the code which is more better)  */    
if (employee.isEligibleForFullBenefits())

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

3."Informative comments"
/* USE the first one instead of the second code snippet */

protected abstract Responder responderBeingTested();
   
// Returns an instance of the Responder being tested.
protected abstract Responder responderInstance();
The following example shows which regex mathes, a more meaningful comment.
// format matched kk:mm:ss EEE, MMM dd, yyyy
Pattern timeMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");

4."Warning of Consequences"
/* USE the first one instead of the second code snippet */

/*first code snippet*/
import org.junit.Ignore;

@Ignore("Takes too long to run")
public void _testWithReallyBigFile() {            
}

/*second code snippet*/
// Don't run unless you
//have some time to kill.
public void _testWithReallyBigFile() {     
}
This comment is reasonable:
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;
}

5."If you are writing a public API, then you should certainly write good javadocs for it. But keep in mind the rest of the advice in this chapter. Javadocs can be just as misleading, nonlocal and dishonest as any other kind of comment."
You can generate Javadocs in eclipse as below:
/**<NEWLINE>


BAD COMMENTS:
6. "Mumbling"
The purpose of this comment is why nothing is done in the catch block. 
The comment that forces you to look at another module is not worth writing.(Who loads all the defaults? )
public void loadProperties() {
       try {
              String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE;
              FileInputStream propertiesStream = new FileInputStream(propertiesPath);
              loadedProperties.load(propertiesStream);

       } catch(IOException e) {
              // No properties files means all defaults are loaded
       }
}

7. "Redundant Comments"
The comment takes more time to read the code.
// 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");
       }
}

8. "Mandated Comments"
"It is just plain silly to have a rule that says that every function must have a javadoc."
The below javadocs serves nothing.
/**
*
* @param title The title of the CD
* @param author The author of the CD
* @pram tracks The number of tracks on the CD
* @param durationInMinutes The duration of the CD in minutes
*/
public void addCD(String title, String author,  int tracks, int durationInMinutes) {
       CD cd = new CD();
       cd.title = title;
       cd.author = author;
       cd.tracks = tracks;
       cd.duration = duration;
       cdList.
}

9."Don’t Use a Comment When You Can Use a Function or a Variable"
/* USE the first one instead of the second code snippet */

/* first code snippet */
ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))

/* second code snippet */
// does the module from the global list <mod> depend on the
// subsystem we are part of?
if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))

10."Closing Brace Comments"
"Sometimes programmers will put special comments on closing braces...""...if you find
yourself wanting to mark your closing braces, try to shorten your functions instead."
public static void main(String[] args) {
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      String line;
      int lineCount = 0;
      int charCount = 0;
      int wordCount = 0;
      try {
            while ((line = in.readLine()) != null) {
                  lineCount++;
                  charCount += line.length();
                  String words[] = line.split("\\W");
                  wordCount += words.length;
            } //while
            System.out.println("wordCount = " + wordCount);
            System.out.println("lineCount = " + lineCount);
            System.out.println("charCount = " + charCount);
      } // try
      catch (IOException e) {
            System.err.println("Error:" + e.getMessage());
      } //catch
}

11."Attributions and Bylines"
"Source code control systems are very good at remembering who added what, when. There is no need to pollute the code with little bylines."
/* Added by Rick */

12."Commented-Out Code"
One of the most common situations i think:
"Few practices are as odious as commenting-out code. Don’t do this! 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."
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()));

References:
Robert C Martin - Clean Code: A Handbook of Agile Software Craftsmanship