Clear Code
  • Introduction
    • About This Book
    • Timeline
    • Software Killers
    • Billion Dollar Mistakes
    • Clear Code Overview
    • Clear Code Rules
  • Data Processing
    • Separate Data Collection And Processing
    • Create Data Models
    • Separate Use Cases
    • Data Should Be Immutable
  • Examples
    • Separate Use Cases With Data Model
  • Maintenance Cost
    • Consider the Maintenance Cost
    • The Software Exists In Time
    • Don't Feed the Monsters
  • OOP
    • Separate Data And Procedures
    • Do Not Use Inheritance
    • When To Avoid Inheritance?
    • What Is The Problem With Abstract Frameworks?
  • VARIOUS
    • The Real Single Responsibility Principle
    • The problem with Clean Code's name
    • How To Handle Warnings
    • Do Not Create Constant Collection Classes
  • Externals
    • Links
    • Quotes
    • Funny
  • Technology
    • Git Tutorials
  • Clean Code
    • Clean Code Introduction
      • Origin & Overview
      • Advanced
      • Typical Issues
    • Clean Code Outline
      • Why Clean Code?
      • Clean Code
      • Clean Code Approaches
      • Specification & Design
      • Duplication
      • Refinement & Refactoring
      • Conventions
      • Names
      • Types
      • Methods
      • Nulls and Validity Checks
      • Comments
      • Dead Code
      • Error Handling
      • Classes
      • Code Formatting
      • Unit Tests
      • Special Cases
      • Object Oriented Programming
      • General Code Smells
    • Clean Code Links
    • Clean Code TOC
    • Effective Java TOC
Powered by GitBook
On this page
  • Cases of duplication
  • Avoid inline implementation
  • DRY Principle

Was this helpful?

  1. Clean Code
  2. Clean Code Outline

Duplication

Last updated 5 years ago

Was this helpful?

One of the "enemies" of clean code.

Cases of duplication

  • Copy-pasted parts

  • Duplicated logic - something implemented more times on different ways

  • Duplicated values or information - literals or constants

Avoid inline implementation

This is also a misplaced responsibility!

  • Not reusable - Leads to duplication

  • Different implementations

  • Not testable

  • Refactor it

DRY Principle

  • Don't repeat yourself (Kent Beck)

Example: Refactor inline implementation

Example: Bad: Duplication causes incorrect intention

// It suggests that it is a branching, but it is only a duplicate
// It differs only in the input value, which is implemented inline

public boolean isMultipleOriginAllowedForCountry(SearchFlightsForm form) {
    if (GstUserType.INTERNAL == userHelper.getCurrentUserUserType()) {
        return isCountryInTheListOfAllowedMultipleOrigins(form.getPos().getCode());
    } else {
        return isCountryInTheListOfAllowedMultipleOrigins(userHelper.getCurrentUserPos());
    }
}

Example: Good: No duplicates, correct intention

public boolean isMultipleOriginAllowedForCountry(SearchFlightsForm form) {
    return isCountryInTheListOfAllowedMultipleOrigins(getPosOfUser(form));
}

// Extracted funtionality can be tested too
private String getPosOfUser(SearchFlightsForm form) {
    return GstUserType.INTERNAL == userHelper.getCurrentUserUserType() ? 
            form.getPos().getCode() : userHelper.getCurrentUserPos();
}

Example: Bad: Duplicated implementation with differences

// Cause: laziness of the developer
// Cannot be found by a code checker
// Blocks the development and the refactoring too

public final void parse(final String[] configs, final String configPath, final boolean flushAfterParse) {
    final FileLocator locator = new FileLocator();
    try {
        if (getInputSource() != null) {
            final EdifactParser parser = new EdifactParser(getInputSource(), getHandler());
            final String extendedConfigPath = StringUtils.isEmpty(configPath) ? "" : configPath + CharacterConstant.SLASH;
            for (final String config : configs) {
                final File grammarFile = locator.locate(extendedConfigPath + config + ".xml");
                parser.addConfig(new Config(config, grammarFile));
            }
            parser.convert();
            if (flushAfterParse) {
                getHandler().flush(true);
            }
        }
    } catch (final IOException e) {
        throw new ExtendedRuntimeException(e);
    } catch (final ExtendedException e) {
        throw new ExtendedRuntimeException(e);
    } finally {
        locator.releaseAll();
    }
}

public final void parse(final Config[] configs, final boolean flushAfterParse) {
    final FileLocator locator = new FileLocator();
    try {
        if (getInputSource() != null) {
            final EdifactParser parser = new EdifactParser(getInputSource(), getHandler());
            for (final Config config : configs) {
                parser.addConfig(config);
            }
            parser.convert();
            if (flushAfterParse) {
                getHandler().flush(true);
            }
        }
    } catch (final IOException e) {
        throw new ExtendedRuntimeException(e);
    } catch (final ExtendedException e) {
        throw new ExtendedRuntimeException(e);
    } finally {
        locator.releaseAll();
    }
}

// Other clean code issues in this example:
// - Methods are doing more than one thing
// - Inner dependency
// - Not expressive validity check

Example: Bad: Duplicates differ only in values

// Bad intention: similar methods with very different names - how can be that?
// Methods do what they tell but you CANNOT SEE it
// It contains another duplication which can be expensive (e.g. database access)

private void fillOutCountriesForMultipleOrigin() {
    getSegments().get(0).setOrigin(countryAutoCompleteHelper.getCountryItemForAiportCode(getPosForMultipleOrigin()));
    if (JourneyType.OPEN_JAW.equals(getJourneyType())) {
        getSegments().get(1).setDestination(countryAutoCompleteHelper.getCountryItemForAiportCode(getPosForMultipleOrigin()));
    }
}

private void removeCountriesForNormalFlights() {
    getSegments().get(0).setOrigin(null);
    if (JourneyType.OPEN_JAW.equals(getJourneyType())) {
        getSegments().get(1).setDestination(null);
    }
}

Example: Good: Refactor value differences to input parameters

// Methods do what they tell and you CAN SEE it

private void fillOutCountriesForMultipleOrigin() {
    setCountryForSegments(countryAutoCompleteHelper.getCountryItemForAiportCode(getPosForMultipleOrigin()));
}

private void removeCountriesForNormalFlights() {
    setCountryForSegments(null);
}

private void setCountryForSegments(AirportCityCodeItem country) {
    getSegments().get(0).setOrigin(country);
    if (JourneyType.OPEN_JAW.equals(getJourneyType())) {
        getSegments().get(1).setDestination(country);
    }
}

// It is not yet clean: magic numbers
// It is not yet clean: why only two segments?