Clean Code - A&BP CC

Preview:

Citation preview

Always leave the campgroundcleaner than you found it.

Service?

Processor?

Handler?Manager?

ClassesDriver?

 

1.    public static String testableHtml(PageData pageData, boolean includeSuiteSetup) throws Exception {2.           WikiPage wikiPage = pageData.getWikiPage();3.           StringBuffer buffer = new StringBuffer();4.           if (pageData.hasAttribute("Test")) {5.                   if (includeSuiteSetup) {6.                           WikiPage suiteSetup = PageCrawlerImpl.getInheritedPage(SuiteResponder.SUITE_SETUP_NAME, wikiPage);7.                           if (suiteSetup != null) {8.                               WikiPagePath pagePath = suiteSetup.getPageCrawler().getFullPath(suiteSetup);9.                               String pagePathName = PathParser.render(pagePath);10.                                  buffer.append("!include -setup .").append(pagePathName).append("\n");11.                        }12.                   }13.                   WikiPage setup = PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);14.                   if (setup != null) {15.                           WikiPagePath setupPath = wikiPage.getPageCrawler().getFullPath(setup);16.                           String setupPathName = PathParser.render(setupPath);17.                           buffer.append("!include -setup .").append(setupPathName).append("\n");18.                   }19.           }20.           buffer.append(pageData.getContent());21.           if (pageData.hasAttribute("Test")) {22.                   WikiPage teardown = PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);23.                   if (teardown != null) {24.                           WikiPagePath tearDownPath = wikiPage.getPageCrawler().getFullPath(teardown);25.                           String tearDownPathName = PathParser.render(tearDownPath);26.                           buffer.append("\n").append("!include -teardown .").append(tearDownPathName).append("\n");27.                   }28.                   if (includeSuiteSetup) {29.                           WikiPage suiteTeardown = PageCrawlerImpl.getInheritedPage(SuiteResponder.SUITE_TEARDOWN_NAME, wikiPage);30.                           if (suiteTeardown != null) {31.                               WikiPagePath pagePath = suiteTeardown.getPageCrawler().getFullPath(suiteTeardown);32.                               String pagePathName = PathParser.render(pagePath);33.                    buffer.append("!include -teardown .").append(pagePathName).append("\n");34.                }35.            }36.        }37.        pageData.setContent(buffer.toString());38.        return pageData.getHtml();39.    }

1.    public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception {2.         boolean isTestPage = pageData.hasAttribute("Test");3.         if (isTestPage) {4.          WikiPage testPage = pageData.getWikiPage();5.          StringBuffer newPageContent = new StringBuffer();6.          includeSetupPages(testPage, newPageContent, isSuite);7.          newPageContent.append(pageData.getContent());8.          includeTeardownPages(testPage, newPageContent, isSuite);9.          pageData.setContent(newPageContent.toString());10.        }11.        return pageData.getHtml();12.    }

1.    public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception {2.         if (isTestPage(pageData))3.                 includeSetupAndTeardownPages(pageData, isSuite);4.         return pageData.getHtml();5.    }

Small: Never more than 20 lines

Do one thing and one thing only

Only 1 or 2 levels deep

Descriptive names

Avoid 3 parameters

Have no side effects

private String readQwPinCode(String fyon, String item) throws TranslationException { try { FetchQwItemOnCar fetchQwItemOnCar = new FetchQwItemOnCar(); QwOnCarBuf qwOnCarBuf = fetchQwItemOnCar.fetchQwItemOnCar(fyon, item); if(fetchQwItemOnCar.getStatusCode() == FetchQwItemOnCarStatusCode.ATACQ$_SUCCESS && qwOnCarBuf != null) return qwOnCarBuf.getSerieNumber().trim(); else if(fetchQwItemOnCar.getStatusCode() == FetchQwItemOnCarStatusCode.ATACQ$_RNF) return "??????????????????????????????"; else throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION)); } catch (VcomException e) { logger.error(e.getMessage(), e); throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION_VCOM)); } catch (BufferException e) { logger.error(e.getMessage(), e); throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION_VCOM)); }}

Avoid output arguments

Avoid output arguments

appendFooter(s);

public void appendFooter(StringBuffer report)

report.appendFooter();

“Principle of least astonishment”

Avoid output arguments

Throw unchecked exceptions

private String readQwPinCode(String fyon, String item) throws TranslationException { try { FetchQwItemOnCar fetchQwItemOnCar = new FetchQwItemOnCar(); QwOnCarBuf qwOnCarBuf = fetchQwItemOnCar.fetchQwItemOnCar(fyon, item); if(fetchQwItemOnCar.getStatusCode() == FetchQwItemOnCarStatusCode.ATACQ$_SUCCESS && qwOnCarBuf != null) return qwOnCarBuf.getSerieNumber().trim(); else if(fetchQwItemOnCar.getStatusCode() == FetchQwItemOnCarStatusCode.ATACQ$_RNF) return "??????????????????????????????"; else throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION)); } catch (VcomException e) { logger.error(e.getMessage(), e); throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION_VCOM)); } catch (BufferException e) { logger.error(e.getMessage(), e); throw new TranslationException("TranslateBuildingInfoItem",

String.valueOf(BuildingInfoConfigConstants.TRANSLATION_EXCEPTION_VCOM)); }}

Comments

Comments

Don’t write comments

Comments

Unless…– Javadocs in public APIs– “why” comments

public interface Vehicle {double getFuelTankCapacityInGallons();double getGallonsOfGasoline();

}

public interface Vehicle {double getPercentFuelRemaining();

}

final String outputDir =ctxt.getOptions().getScratchDir().getAbsolutePath();

Alternatives:• ctxt.getAbsolutePathOfScratchDirectoryOption();• ctx.getScratchDirectoryOption().getAbsolutePath();

Careful! Don’t cause an explosion of methods

How used?

String outFile = outputDir + "/" +

className.replace('.', '/') + ".class";

FileOutputStream fout = new FileOutputStream(outFile);

BufferedOutputStream bos = new BufferedOutputStream(fout);

How about this then?

BufferedOutputStream bos =

ctxt.createScratchFileStream(classFileName);

Error Handling

• Return codes are bad

• Unchecked exception are not!

• TDD: write your exception handling first• Nullpointers: Do not return or pass null.

Boundaries

Unit Tests

! Write clean test code !

1. Write failing unit test before production code

2. Only write enough test code to fail

3. Only write enough production code to pass the test

4. Repeat

AAA / GivenWhenThen• Arrange• Act• Assert

• Given• When• Then

or vs

F.I.R.S.T.

• Fast

• Independent

• Repeatable

• Self validation

• Timely

Classes should be small

• Avoid too many public methods (God class)

• Hint: class name should concisely describe the class

Single Responsibility Principle

Gather together the things that change for the same reasons

Separate those things that change for different reasonsThe reason we don't put SQL in JSPsThe reason we don't generate HTML in modules which compute resultsThe reason business rules shouldn't know about the database schema

Cohesion

Classes should have a small number of instance variables

Aim for high cohesion A class in which each variable is used by each method is maximally cohesive

When subset of methods depend on subset of instance variables → good sign for an extra class

Results in many small classes

Recommended