The art of Software Craftmanship part - 2

Clean code can save a significant amount of time and money in the long run by reducing the need for debugging, rewriting code, and maintenance.

Meaningful Names

Class Name :
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 Name :
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.

Don't Be Cute :
If names are too clever, they will be memorable only to people who share the author’s sense of humor, and only as long as these people remember the joke. Will they know what the function named HolyHandGrenade is supposed to do? Sure, it’s cute, but maybe in this case DeleteItems might be a better name. Choose clarity over entertainment value.
Say what you mean. Mean what you say.

Final Words :
The hardest thing about choosing good names is that it requires good descriptive skills and shared cultural background. This is a teaching issue rather than a technical, business, or management issue. As a result, many people in this field don’t learn to do it very well.

Functions

Exercise-1 :
Read the below code snippet and honestly talk to yourself if you understood the working of the code.

              public static String renderPageWithSetupsAndTeardowns(
                    PageData pageData, boolean isSuite
            ) throws Exception {
                boolean isTestPage = pageData.hasAttribute("Test");
                if (isTestPage) {
                    WikiPage testPage = pageData.getWikiPage();
                    StringBuffer newPageContent = new StringBuffer();
                    includeSetupPages(testPage, newPageContent, isSuite);
                    newPageContent.append(pageData.getContent());
                    includeTeardownPages(testPage, newPageContent, isSuite);
                    pageData.setContent(newPageContent.toString());
                }
                return pageData.getHtml();
            }
            Listing 1.1
            

The above code is refactored code, priorly it was like depicted below, now read that too and take an honest opinion of yourself if you understanding it or not.

              public static String testableHtml(
                    PageData pageData,
                    boolean includeSuiteSetup
            ) throws Exception {
                WikiPage wikiPage = pageData.getWikiPage();
                StringBuffer buffer = new StringBuffer();
                if (pageData.hasAttribute("Test")) {
                    if (includeSuiteSetup) {
                        WikiPage suiteSetup =
                                PageCrawlerImpl.getInheritedPage(
                                        SuiteResponder.SUITE_SETUP_NAME, wikiPage
                                );
                        if (suiteSetup != null) {
                            WikiPagePath pagePath =
                                    suiteSetup.getPageCrawler().getFullPath(suiteSetup);
                            String pagePathName = PathParser.render(pagePath);
                            buffer.append("!include -setup .")
                                    .append(pagePathName)
                                    .append("\n");
                        }
                    }
                    WikiPage setup =
                            PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);
                    if (setup != null) {
                        WikiPagePath setupPath =
                                wikiPage.getPageCrawler().getFullPath(setup);
                        String setupPathName = PathParser.render(setupPath);
                        buffer.append("!include -setup .")
                                .append(setupPathName)
                                .append("\n");
                    }
                }
                buffer.append(pageData.getContent());
                if (pageData.hasAttribute("Test")) {
                    WikiPage teardown =
                            PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);
                    if (teardown != null) {
                        WikiPagePath tearDownPath =
                                wikiPage.getPageCrawler().getFullPath(teardown);
                        String tearDownPathName = PathParser.render(tearDownPath);
                        buffer.append("\n")
                                .append("!include -teardown .")
                                .append(tearDownPathName)
                                .append("\n");
                    }
                    if (includeSuiteSetup) {
                        WikiPage suiteTeardown =
                                PageCrawlerImpl.getInheritedPage(
                                        SuiteResponder.SUITE_TEARDOWN_NAME,
                                        wikiPage
                                );
                        if (suiteTeardown != null) {
                            WikiPagePath pagePath =
                                    suiteTeardown.getPageCrawler().getFullPath (suiteTeardown);
                            String pagePathName = PathParser.render(pagePath);
                            buffer.append("!include -teardown .")
                                    .append(pagePathName)
                                    .append("\n");
                        }
                    }
                }
                pageData.setContent(buffer.toString());
                return pageData.getHtml();
            }
            Listing 1.2
            

The point I want to convey here is that this is the power of 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. This is not an assertion that we can justify. The author has nearly 40 years of experience in programming, who has written functions that are 3000 lines long and functions that are 20 to 30 lines long, Author says that from long trial and error I came to one conclusion that functions should be very small. How short should your functions be? They should usually be shorter than Listing 1.1 Indeed, Listing 1.1 should be shortened to Listing 1.3

              public static String renderPageWithSetupsAndTeardowns(
                    PageData pageData, boolean isSuite) throws Exception {
                if (isTestPage(pageData))
                    includeSetupAndTeardownPages(pageData, isSuite);
                return pageData.getHtml();
            }
            Listing 1.3
            

Do One Thing :
It should be very clear that Listing 1.2 is doing lots more than one thing. It’s creating buffers, fetching pages, searching for inherited pages, rendering paths, appending arcane strings, and generating HTML, among other things. Listing 1.2 is very busy doing lots of different things. On the other hand, Listing 1.3 is doing one simple thing. It’s including setups and teardowns into test pages. The following advice has appeared in one form or another for 30 years or more. FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.

Use Descriptive Names :
In Listing 1.1 I changed the name of our example function from testableHtml to SetupTeardownIncluder.render. This is a far better name because it better describes what the function does. I also gave each of the private methods an equally descriptive name such as isTestable or includeSetupAndTeardownPages. It is hard to overestimate the value of good names. Remember Ward’s principle: “You know you are working on clean code when each routine turns out to be pretty much what you expected.” Half the battle to achieving that principle is choosing good names for small functions that do one thing. The smaller and more focused a function is, the easier it is to choose a descriptive name.

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. Use a naming convention that allows multiple words to be easily read in the function names, and then make use of those multiple words to give the function a name that says what it does.

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) require very special justification—and then shouldn’t be used anyway.

Argument Objects :
When a function seems to need more than two or three arguments, some of those arguments likely ought to be wrapped into a class of their own. Consider, for example, the difference between the two following declarations:

              Circle makeCircle(double x, double y, double radius);
              Circle makeCircle(Point center, double radius);
            
Reducing the number of arguments by creating objects out of them may seem like cheating, but it’s not. When groups of variables are passed together, the way x and y are in the example above, they are likely part of a concept that deserves a name of its own.

Have No Side Effects :
Side effects are lies. Your function promises to do one thing, but it also does other hidden things. Sometimes it will make unexpected changes to the variables of its class. Sometimes it will take them to the parameters passed into the function or to system globals. In either case, they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.
Consider, for example, the seemingly innocuous function in Listing 2.1. This function uses a standard algorithm to match a userName to a password. It returns true if they match and false if anything goes wrong. But it also has side effects. Can you spot it?

              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;
                }
              }
              Listing 2.1
            

The side effect is the call to Session.initialize(), of course. The checkPassword function, by its name, says that it checks the password. The name does not imply that it initializes the session. So a caller who believes what the name of the function says runs the risk of erasing the existing session data when he or she decides to check the validity of the user.

This side effect creates a temporal coupling. That is, checkPassword can only be called at certain times (in other words, when it is safe to initialize the session). If it is called out of order, session data may be inadvertently lost. Temporal couplings are confusing, especially when hidden as a side effect. If you must have a temporal coupling, you should make it clear in the name of the function. In this case, we might rename the function checkPasswordAndInitializeSession, though that certainly violates “Do one thing.”

How do we write functions that people love? :
Writing software is like any other kind of writing. When you write a paper or an article, you get your thoughts down first, then you massage it until it reads well. The first draft might be clumsy and disorganized, so you wordsmith it and restructure it and refine it until it reads the way you want it to read.

When I write functions, they come out long and complicated. They have lots of indenting and nested loops. They have long argument lists. The names are arbitrary, and there is duplicated code. But I also have a suite of unit tests that cover every one of those clumsy lines of code.

So then we should massage and refine that code, splitting out functions, changing names, eliminating duplication. We should shrink the methods and reorder them. Sometimes we break out whole classes, all the while keeping the tests passing. In the end, we wind up with functions that follow the rules I’ve laid down in this chapter. We don’t write them that way to start. We don’t think anyone could.


Source : Clean Code : A Handbook of Agile Software by Martin Fowler

Get in touch

Let’s work together

Reach out if you have a concept for a website or mobile app or require guidance with product design. contact me.
  info@whywhytechnova.com
  +(91) 88661 28862