On Github nkhalasi / code_smell_heuristics
Summarized from "Clean Code" by Robert Martin
Technically correct
Does function as expected
BUT
You get a sense of deeper problem
Indications of violation of fundamental design principles
Your development has slowed down
Or there is increased risk of bugs and failures
Hold information in the right system
Old, irrelevant and incorrect
Floating islands of irrelevance and misdirection in the code
Either update or remove obselete comments
Comments should say what the code cannot say for itself
Don'ti++; //increment ior
/** * @param sellRequest * @return * @throws ManagedComponentException */ public SellResponse beginSellItem(SellRequest sellRequest) throws ManagedComponentException
A comment worth writing is worth writing well
Make sure it is the best comment
Use proper grammar and punctuation
Don't state the obvious
Rots and becomes less and less irrelevant with each day
Delete it. Source control system has it for reference.
Calls functions and uses variables that are no longer valid.
Trivialize building a project
Automate multi-steps and simplify
Explore new age build tools - SBT, Gradle, etc.
Does your build tool allow easy extensions?
Make testing less painful
Running tests should be quick, easy and obvious
No Arguments is best
Three is the limit
Time to refactor your design and abstractions when you need more arguments
They are counterintuitive
Arguments are for inputs
Update state of the object being actioned
public void appendFooter(StringBuffer report)vs
report.appendFooter();
Strong smell and avoid them
Clear indication that your function does more than one thing
Go back and revise your understanding of SRP
def chosen_ident(choice_flag, item, match): assert choice_flag in (action.ASIS, action.APPLY) if choice_flag is action.ASIS: return (item.artist, item.title) elif choice_flag is action.APPLY: return (match.info.artist, match.info.title)
class _IdentChooser: pass class AsisIdent(_IdentChooser): def __call__(self, ident): return (ident.artist, ident.title) class ApplyIdent(_IdentChooser): def __call__(self, ident): assert ident.hasattr('info') is True return (ident.info.artist, ident.info.title) class NullChooser(_Chooser): def __call__(self, ident=None): return () choosers = {action.ASIS: AsisChooser, action.APPLY: ApplyChooser, None: NullChooser, '': NullChooser} def chosen_ident(choice_flag, item): return choosers[choice_flag](item)
it just rots and misguides
Just discard
Follow "The Principle of Least Surprise"
Not implementing the obvious results into
Don't rely on your intuition
Write tests for every boundary condition
represents a missed opportunity for abstraction
Always follow DRY principle
Abstraction increases vocabulary of your design
Improves reusability, increases coding speed and reduces error
Replace switch/case or if/else with polymorphism
Similar looking code? Does TEMPLATE METHOD or STRATEGY Pattern apply?
Seperate concepts at different levels and place them in different containers
Seperation should be complete. Don't mix lower and higher level concepts.
public interface Stack { Object pop() throws EmptyException; void push(Object o) throws FullException; double percentFull(); class EmptyException extends Exception {} class FullException extends Exception {} }percentFull() is applicable to BoundedStack but may not be applicable to some other implementation of Stack