3 Code Smells

0.0(0)
studied byStudied by 0 people
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
Card Sorting

1/41

encourage image

There's no tags or description

Looks like no tags are added yet.

Study Analytics
Name
Mastery
Learn
Test
Matching
Spaced

No study sessions yet.

42 Terms

1
New cards

"A code smell

is a surface indication that usually corresponds to a deeper problem in the system." -- Martin Fowler

Providing names to different types of ugly code enables more effective discussions on design improvement.

2
New cards

Duplicate Behavior ("Duplicate Code")

Then you need to make even more changes... and your code base grows. Oh, and you did copy-paste for a hundred other routines.

  • You find yourself in a never-ending cycle of updating little spots of code all over the codebase.

  • The routines get complex and difficult to understand.

  • You can't be reassigned to a new project since you're the only one who understands the code.


3
New cards

Don’t Repeat Yourself (DRY)

  • Composition or Inheritance

  • parameters or polymorphism

Solution to Duplicate Code:

Write code in a method just once, then call it where you need it.

  • Use — to reduce duplication

  • Use — to handle variations.

When you need to update your logic, you only need to update and test one spot.

Code is easier to read since it is broken up into descriptive methods.

4
New cards

Long Methods & Large Classes

Class has a lot of fields.

Difficult to understand, maintain, reuse.

OOP is about small, specialized components.

5
New cards

multiple smaller methods.

Long Methods & Large Classes

Each method should only do one, simple thing.

  • No side-effects.

  • Method name should be descriptive of that one thing.

  • If a method is hard to name, it's probably doing to much.

A class should be a specialized, cohesive unit.

  • Just a few fields.

  • If the class is difficult to name, or has a generic name, it might be doing too much (or not enough).

Solutions:

Break up a long method into

Break up a large class into two or more classes.

6
New cards

Primitive Obsession:

Sticking with built-in types of the language instead of creating one's own classes.

Primitive Obsession: Sticking with built-in types of the language instead of creating one's own classes.

   int customerId1;

   String customerFirstName1;

   String customerLastName1;

   int[] orderIdsOfCustomer1;

   int customerId2;

   String customerFirstName2;

   String customerLastName2;

   int[] orderIdsOfCustomer2;

7
New cards

Data Clump:

Data that's often found together.

   int customerId;

   String customerFirstName;

   String customerLastName;

   String customerEmailAddress;

   int[] orderIdsOfCustomer;

   Date[] orderDates;

8
New cards

Long Parameter Lists

void method(int customerId, int customerId, String customerFirstName,

           String customerLastName, String customerEmailAddress,

           int[] orderIdsOfCustomer, Date[] orderDates) {

9
New cards
  • form fields, etc.

What happens as the data clump changes?

  • Additional and removal of —

Maintenance nightmare!

10
New cards

Cohesion

Solution to Primitive Obsession, Data Clumps & Long Parameter Lists


Encapsulate a data clump into a meaningful class.

class Customer {

   private final int id;

   private String firstName;

   private String lastName;

   private String emailAddress;

   private Set<Order> orders;

   ...

}

No more data clumps.

Customer customer1;

Customer customer2;

Customer customer3;


No more long parameter lists.

void method(Customer customer) {

11
New cards

Long parameter lists

can also be a sign that the method is in the wrong class.

  • It always requires data from somewhere else.

OOP is about combining data structures with the operations that act on them.

Solution: Move the method to the class where most or all of the data it uses is found.

12
New cards

Divergent Change

principle of Separation of Concerns.

The same class is changed for different reasons.

"Well, I will have to change these three methods every time I get a new database and I have to change these four methods every time there is a new financial instrument..

This class is handling both business and persistence concerns.

A class is suffering from it if it breaks the —

13
New cards

one concern.

Solution to Divergent Change

Similar to large classes, you should break up the class so that it only does —

  • Examples of concerns: business logic, persistence, presentation, transactions, security...

14
New cards

Shotgun Surgery

When multiple classes need to be modified to do one change.

  • Opposite of Divergent Change.

  • Caused by a lack of Cohesiveness - the many separate bits should be in one class.

15
New cards

Cohesion

Solution to Shotgun Surgery:

— Encapsulate the things that change together into one class.

"Things that change together should be together."

Also applies to packages - Classes that change together should be in the same package.

16
New cards

Feature Envy

Move the method

A method keeps accessing data from another class.

Solution: to the class where the data it uses resides.

  • Again - OOP is combining data with the methods that act on that data


17
New cards

Conditional Complexity

Large and growing If-Else and Switch logic become difficult to maintain.

18
New cards

polymorphism

Solution to Conditional Complexity

Use .

  • Separate the common logic from the special case logic.

  • Create a supertype (abstract class or interface) as placeholder for special case logic.

  • Create subtypes to hold logic for each special case.


19
New cards

Parallel Inheritance Hierarchy

Every time you add a class to one package, you have to add a class to another package

  • Customer → CustomerService

  • Order → OrderService

  • Product → ProductService

Solution: Move code from one hierarchy to the other, and then collapse what's left into fewer classes.

20
New cards

Lazy Class

Middle Man

Dead Code:

Doesn't do much to justify its existence.
Delegates to another class but doesn't add its own value.

— Code no longer used.


21
New cards

Inline

Combine

Delete

Any code that exists takes maintenance cost. Eliminate code that doesn't justify its existence.

Lazy Class: its behavior into other classes.

Middle Man: the Middle Man with the class to which it delegates.

Dead Code: it.

22
New cards

Alternative Classes with Different Interfaces

Classes that are similar but are not substitutable, since they do not share the same supertype.

Choices have to be hard-coded, or messy conditionals need to be used.

What if we have to support other forms of data access (web services?) later on?

<p><span>Classes that are similar but are not substitutable, since they do not share the same supertype.</span></p><p><span>Choices have to be hard-coded, or messy conditionals need to be used.</span></p><p><span>What if we have to support other forms of data access (web services?) later on?</span></p>
23
New cards

Polymorphism

Solution to Alternative Classes with Different Interfaces


Solution: —- Have the classes share a common supertype.

<p><em>Solution to </em><span><em>Alternative Classes with Different Interfaces</em></span></p><p><em><br></em><span>Solution: —- Have the classes share a common supertype.</span></p>
24
New cards

Data Class or Anemic Domain Model

Class that only contains data and not behavior.


public class BankAccount {

   private int acctNo;

   private BigDecimal balance;


   public void setAcctNo(int acctNo) {

       this.acctNo = acctNo;

   }


   public int getAcctNo() {

       return acctNo;

   }


   public void setBalance(BigDecimal balance) {

       this.balance = balance;

   }


   public BigDecimal getBalance() {

       return balance;




25
New cards

outside the object

invalid state

Data Class or Anemic Domain Model

  • Balance should not be negative.

  • ATM withdrawals should not exceed 20,000.

  • All transactions must be logged with a transaction ID.

In an Anemic Domain Model, all this behavior needs to be done — Error-prone.

Object may be in an — (ex. negative balance). Constant validation must be done.

Fields can be changed by any code. Encapsulation is broken.

26
New cards

Rich Domain Model and Information Expert.

Solution to Data Class or Anemic Domain Model

Solution: Implement — Place methods in the class with the data they operate on.

  • Remove unneeded getters and setters, to preserve encapsulation.

public class BankAccount {

   private final int acctNo;

   private BigDecimal balance;


   public BankAccount(int acctNo) {...}


   public Transaction deposit(BigDecimal amt) {

       if (amt.signum() < 0) {

           throw new IllegalArgumentException("cannot be negative");

       }

   ...

   }

...

27
New cards

Refused Bequest

Replace inheritance with composition.

When a class inherits members that it doesn't need.

  • Ok if the unneeded members are encapsulated.

  • Dangerous if the unneeded members are part of the interface.

Solution: —

28
New cards

Speculative Generality

When code is written to be more flexible than the present requirements need it to be.

Usually in anticipation of future requirements.

29
New cards
  • any data type

  • Overloaded

Speculative Generality

  • Methods that try to accommodate —

  • ex. String or int instead of enum, LocalDate, BigDecimal or custom class

  • — methods/constructors that are not or rarely used.

  • Methods that don't do much, and don't add to clarity.

  • Parameters that aren't used.

  • Supertypes that only have one subtype.

  • Middle Man, Lazy Class, Dead Code

Code is hard to understand and maintain.

30
New cards

YAGNI - You Ain't Gonna Need It

DTSTTCPW - Do the Simplest Thing That Could Possibly Work

Solution to Speculative Generality


Code just enough to satisfy the requirements of the current Sprint.


Requirements change. Even if the written requirements state that something is required, that might change later, and any effort you do to fulfilling those requirements will be wasted.

Focus on the more certain requirements - those in the current Sprint.

  • Code is simpler, more readable, less likely to be buggy, gets done on-time.

Collapse unneeded hierarchies, inline methods and classes, remove unused parameters, etc.

31
New cards

God Class / God Method

Much of the code is concentrated in one class or method, or many other classes or methods depend on that one class or method.

32
New cards
  • Single Responsibility Principle

  • Information Expert

  • Law of Demeter

Solution to God Class / God Method: (3)

33
New cards

Temporary Field

Class or instance fields that are temporarily set for method operations. They don't describe the state of the object.


private int x;

void method() {

   x = 0;

... // do stuff with x

}


Dangerous in multithreaded environment! Multiple threads may be modifying the field in the middle of method executions.

Confusing for other teammates (or your future self) since it's hard to figure out what the field is for.

34
New cards
  • local variable/s.

Solution to Temporary Field

  • Make the field/s —

void method() {

   int x = 0;

... // do stuff with x

}

  • If there are several of them and they end up getting passed around together as parameters, encapsulate them in a new class.

35
New cards

Message Chains or Train Wrecks

Reaching into an object's attributes to call the attributes' methods.

currSection.getSchedule().equals(newSection.getSchedule())

Causes tight coupling. The calling class becomes tightly coupled to the internal structure of the object. The object cannot change without breaking the caller.

36
New cards

Message Chains or Train Wrecks

Not to mention being difficult to read.

urrSection.getSchedule().getDays().equals(

newSection.getSchedule().getDays()) &&

(currSection.getSchedule().getStartTime().compareTo(

newSection.getSchedule().getEndTime()) >= 0 ||

currSection.getSchedule().getEndTime().compareTo(

newSection.getSchedule().getStartTime()) <=0)


Prone to error

Difficult to maintain.

37
New cards

Information Expert / Law of Demeter

Solution to Message Chains or Train Wrecks


Apply

  • Don't get the fields. Create a method that does the work and just get the results.

currSection.hasConflict(newSection)

No tight coupling. Internal structure of Section can change without breaking callers.

Easier to read & maintain.

38
New cards

different objects.

Do not confuse Message Chain with Method Chain / Fluent Interface

Method Chains / Fluent Interfaces return the same instance, except possibly for the last call. Message Chains return —

39
New cards

"How" Comments

If you need a comment to understand how some code works, then the code is not readable:

// start of fund transfer process

// end of fund transfer process

// check if section schedule has conflict with existing section


40
New cards

"Why" comments

readable

— are good:

// This method uses encryption library Xxx to comply with US regulations on...

// This field is immutable in order to make it threadsafe.

// This private no-arg constructor is to allow JPA to set the final fields.

Javadoc comments that state the contract that overridden methods need to keep are also good.

See equals method Javadoc.

"How" Comments

Solution: Make the code itself —.

41
New cards

Flag Arguments

Having a method do different operations based on a Boolean parameter.

public void login (

   Credentials creds, bool isAdmin

) {

   if (isAdmin) {...}

   else {...}

}

Doing this makes programmers try to remember what the Boolean parameters was for.

42
New cards

Boolean more obvious.

Solution to Flag Arguments

Solution: Make the meaning of the —

<p><em>Solution to </em><span><em>Flag Arguments</em></span></p><p><span>Solution: Make the meaning of the —</span></p>