common sense methods - miklos csere

70
AUTHOR TO DATE Methods in comprehensible code Writing clean common sense method 25.08.2016 Miklós Csere software engineer @Netcentric

Upload: miklos-csere

Post on 12-Apr-2017

89 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Common sense methods - Miklos Csere

AUTHOR

TO

DATE

Methodsin comprehensible code

Writing clean common sense method

25.08.2016Miklós Csere

software engineer @Netcentric

Page 2: Common sense methods - Miklos Csere

AgendaContext

To OOP || !OOP

Imperative vs Declarative

Temporal coupling

NULL == EVIL; STATIC == EVIL;

Defensive Programming

Mutable / Immutable

Size matters

Adobe Experience Manager Perspective

00

01

02

03

04

05

06

07

Page 3: Common sense methods - Miklos Csere

Think before you code You can either start coding right away or you can sit down, relax, and start thinking.

Page 4: Common sense methods - Miklos Csere

0Context Q: Should I apply (something)? A: It depends.

Page 5: Common sense methods - Miklos Csere

Before applying a programming paradigm / patternwe have to think about what we want to achieve:

❖ AEM Component (Java Bean)❖ DTO (POJO)

❖ OSGI Service

❖ HTTP Request Handlers❖ Event Handlers

❖ Helpers (Factories, Builders, Transformers, Static ...)

Context

Page 6: Common sense methods - Miklos Csere

Then we have to think of what should be solved in the current context:

❖ AEM Component, DTO → data transfer

❖ OSGI Service → business logic

❖ HTTP / Event Handlers → call the services above

❖ Helpers (factories, builders, proxies, static ..etc) ➢ → business logic independent, tested and

immutable

Context

Page 7: Common sense methods - Miklos Csere

What is actually going on?

Context

Page 8: Common sense methods - Miklos Csere

Context

AEM Component- Has logic- Cannot be extended

Page 9: Common sense methods - Miklos Csere

Context

OSGI Service- Hard to test- Many

responsibilities

Page 10: Common sense methods - Miklos Csere

What we could have instead?

❖ Extendable components❖ Testable business logic ❖ Comprehensible objects & methods❖ Separation of concerns❖ SOLID OOP❖ TDD, DDD, BDD

What we could give up on? ❖ Procedural programming → but this will take a while❖ Tight coupling and low cohesion❖ Headaches!

Context

Page 11: Common sense methods - Miklos Csere

AEM Component

Context

We have a teaser component that can be reused under different circumstances.

Page 12: Common sense methods - Miklos Csere

Context

Sling Model with no logic

Page 13: Common sense methods - Miklos Csere

HTTP Servlet - no logic- reads the input, calls a service, writes the answer

Page 14: Common sense methods - Miklos Csere

Context

3rd party requests and message translation are the responsibility of dependencies Easy to use fake for testing

OSGI Service

This class takes care only of business logic

Page 15: Common sense methods - Miklos Csere

1OOP || !OOP

Are we actually doing OOP?

Page 16: Common sense methods - Miklos Csere

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things. Where is the OOP?

Component {void init(){

this.callPrivateMethod();this.osgiService.callPublicMethod();callStaticMethod();

if/else/switch statements

this.osgiService.callPublicMethod();this.callPrivateMethod();

} }

OOP || !OOP

Page 17: Common sense methods - Miklos Csere

OOP || !OOP

Not really OOP?

Page 18: Common sense methods - Miklos Csere

Great encapsulation, huh?

Context

Page 19: Common sense methods - Miklos Csere

Anemic Domain Model:

objects, many named after the nouns in the domain space, and these objects are connected with rich relationships.

there is hardly any behavior on these objects, making them little more than bags of getters and setters.

these models come with design rules that say that you are not to put any domain logic in the the domain objects.

service objects capture all the domain logic. These services live on top of the domain model and use the domain model for data.

Martin Fowler

OOP || !OOP

Page 20: Common sense methods - Miklos Csere

One source of confusion in all this is that many OO

experts do recommend putting a layer of procedural

services on top of a domain model, to form a Service Layer.

But this isn't an argument to make the domain model void

of behavior, indeed service layer advocates use a service

layer in conjunction with a behaviorally rich domain

model. Martin Fowler

OOP || !OOP

Page 21: Common sense methods - Miklos Csere

OOP || !OOP

OOP

Page 22: Common sense methods - Miklos Csere

In AEM the following case is also valid:

POJO as a Sling Model we just represent data and no logic is involved.

OOP || !OOP

Page 23: Common sense methods - Miklos Csere

2Imperative vs Declarative

vs

Page 24: Common sense methods - Miklos Csere

An imperative code specifies step-by-step how a problem is solved using a series of statements which change a program’s state.

A declarative code expresses what you want without specifying how. It separates the process of stating a problem from the process of solving it.

Imperative vs Declarative

Page 25: Common sense methods - Miklos Csere

“I’m by Ikea. How do I get to your house from here?”

An imperative response: Go out of the north exit of the parking lot and

take a left. Get on B-10 south until you get to the Maritim Highway exit. Take

a right off the exit like you’re going to Ikea. Go straight and take a right at

the first light. Continue through the next light then take your next left. My

house is #123.

A declarative response: My address is 123 Immutable Alley, Barcelona

80003

Imperative vs Declarative

Page 26: Common sense methods - Miklos Csere

Imperative vs Declarative

/*** Return the double value of all even numbers in an array;* A hashtag has to be added at each number;*/

Imperative solution

Page 27: Common sense methods - Miklos Csere

Imperative vs Declarative

Declarative Solution

Page 28: Common sense methods - Miklos Csere

Declarative programming is not necessarily "lean and mean". It's not something you probably want to do for a quick and dirty app.

In the long term, the combination of an abstraction layer driven by declarative code backed by application specific imperative code makes for very maintainable and extensible applications.

But most important: test your business logic!

Imperative vs Declarative

Page 29: Common sense methods - Miklos Csere

Declarative programming:

❖ Minimizes mutability ❖ Reduces state side-effect❖ It leads to more understandable code❖ It is more scalable (easier to maintain)

So that next time we're about to implement some functionality, we

could ask ourselves whether it can be written in a declarative manner.

Imperative vs Declarative

Page 30: Common sense methods - Miklos Csere

3Temporal coupling

Page 31: Common sense methods - Miklos Csere

Temporal coupling happens between sequential

method calls when they must stay in a particular order.

This is inevitable in imperative programming, but we

can reduce the negative effect of it just by turning those

procedures into methods.

Temporal coupling

Page 32: Common sense methods - Miklos Csere

Imperative code

What happens if I add the “#” before doing the math?

Temporal coupling

Page 33: Common sense methods - Miklos Csere

Declarative code

The magic happens only at the end. We first declare, then we execute.

Temporal coupling

Page 34: Common sense methods - Miklos Csere

4NULL == EVIL; STATIC == EVIL;

Page 35: Common sense methods - Miklos Csere

What will this generate?

NULL == EVIL

Page 36: Common sense methods - Miklos Csere

❖ Unexpected NullPointerException❖ Multiple (random) error handling

❖ Ambiguous variable initialization ➢ Is NULL an Employee ?

NULL == EVIL

Page 37: Common sense methods - Miklos Csere

❖ Slow failing ➢ Instead of interrupting the execution of the thread

we continue doing processes which might not be necesarry

❖ Mutable and incomplete objects➢ Add a caching layer and you will end up with

inconsistent objects stored

NULL == EVIL

Page 38: Common sense methods - Miklos Csere

Alternatives❖ Null Object Pattern

❖ Throw an Exception (Fail fast)

NULL == EVIL

Page 39: Common sense methods - Miklos Csere

❖ Let’s get inspiration from jQuery

Never return null arrays or lists Instead just return an empty collection

NULL == EVIL

Page 40: Common sense methods - Miklos Csere

Static methods and variables are global. They are an extra hard-coded dependency to your code.

“Unit-testing assumes that I can instantiate a piece of my application in isolation. During the instantiation I wire the dependencies with mocks/friendlies which replace the real dependencies. With procedural programing there is nothing to “wire” since there are no objects, the code and data are separate.”

Miško Hevery,2008

STATIC == EVIL

Page 41: Common sense methods - Miklos Csere

A static method does more than it is supposed to: Example: class NodeHelper

STATIC == EVIL

Page 42: Common sense methods - Miklos Csere

Since we are working with JCR, we will find ourselves required to use either recursive or while loops

STATIC == EVIL

But where does it stop?

Page 43: Common sense methods - Miklos Csere

Hard to reason about when you don’t have a context.

Testing this method is a nightmare

Page 44: Common sense methods - Miklos Csere

Declarative Solution: ❖ Boundaries❖ Search conditions ❖ Recursion

STATIC == EVIL

Page 45: Common sense methods - Miklos Csere

5Defensive programming

Page 46: Common sense methods - Miklos Csere

Classical defensive programming:Ex: if (something != null) → then doSomething();

if (isNumber(input)) → then doSomething();

Defensive programming

Page 47: Common sense methods - Miklos Csere

Adds unnecessary code to our methods:

❖ Not related to what our method should do❖ Clutters methods with exceptional cases❖ Makes it hard to test all cases (combinations)

Defensive programming

Page 48: Common sense methods - Miklos Csere

Solution: Decorator Pattern

Smaller objects always mean higher maintainability. Our class will always remain small, no matter how many validations we may invent in the future.

The more things we need to validate, the more validating decorators we will create. All of them will be small and cohesive all together in different variations.

Defensive programming

Page 49: Common sense methods - Miklos Csere

Defensive programmingDecoratorInterface

Usage

Actual implementation

Page 50: Common sense methods - Miklos Csere

Alternative: Fail fastIf an invalid call has been made, tell the developer

that something went wrong → You deserve a NPE!No validations. Don’t forget to treat the exception.

Defensive programming

Page 51: Common sense methods - Miklos Csere

6Mutable / Immutable

Page 52: Common sense methods - Miklos Csere

Immutable Object → the internal fields (or at least, all the internal fields that affect its external behaviour) cannot be changed.

Mutable / Immutable

Page 53: Common sense methods - Miklos Csere

Advantages of having immutable classes:

❖ immutable objects are simpler to construct, test, and use

❖ immutable objects are always thread-safe

❖ they help to avoid temporal coupling

❖ their usage is side-effect free (no defensive copies)

❖ identity mutability problem is avoided

❖ they always have failure atomicity

❖ they are much easier to cache

❖ they prevent NULL references, which are bad

Mutable / Immutable

Page 54: Common sense methods - Miklos Csere

Programmers are often reluctant to employ immutable objects,

because they worry about the cost of creating a new object as

opposed to updating an object in place.

The impact of object creation is often overestimated, and can be

offset by some of the efficiencies associated with immutable objects.

These include decreased overhead due to garbage collection,

and the elimination of code needed to protect mutable objects from

corruption.

https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

Mutable / Immutable

Page 55: Common sense methods - Miklos Csere

Advice:

Always try to minimize mutability of a class

Few exceptions: Classes that are not part of your domain (Builders, Factories)

Mutable / Immutable

Page 56: Common sense methods - Miklos Csere

7Size matters

Fact:

In World of Warcraft the C++ file containing the code related to the Lich King has 3210 lines. All cohesive and low coupled.

Page 57: Common sense methods - Miklos Csere

Constructors Must Be Code-Free

Only declarations are allowed.

Doing operations is not their responsibility

Have only one primary constructor

A primary constructor is the one that constructs an object and encapsulates other objects inside it.

Secondary constructors just call the primary one using this (..)

Size matters - methods

Page 58: Common sense methods - Miklos Csere

Methods must be smallHow small?

“The first rule of [methods] is that they should be small. The second rule of [methods] is that they should be smaller than that”

(Robert C Martin - Clean Code)

“[Methods] should not be 100 lines long.[Methods] should hardly ever be 20 lines long.”

Size matters - methods

Page 59: Common sense methods - Miklos Csere

Block and indentingMethods should not be large enough to hold nested structures.

The indent level of a function should not be greater than two.

Do One Thing

“Methods should do one thing. They should do it well. They should do it only.”

(Robert C. Martin - Clean Code)

Have no side effectsRemember the session.save() example above?

Size matters - methods

Page 60: Common sense methods - Miklos Csere

Redundant variables are bad

“The more variable names I have to remember, the longer it takes to digest the code”

(Yegor Bugayenko - Elegant Objects)

Size matters - methods

Composite names smell like bad code

Eg: netcentricEmployeeSomeProjectGPN;

Page 61: Common sense methods - Miklos Csere

Reading code from Top to Bottom

“We want every function to be followed by those at the next level of abstraction so that we can read the program, descending one level of abstraction at a time as we read down the list of functions.” (Clean Code)

Switch Statements

Should only be used either in a factory or together with a factory.

Size matters - methods

Page 62: Common sense methods - Miklos Csere

Method arguments

“The ideal number of arguments for a [method] is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway.” (Robert C Martin - Clean Code)

Size matters - methods

Page 63: Common sense methods - Miklos Csere

Output argumentsBest argument to return is: thisPrefer to throw exceptions over returning error codes.Only return a different

object if you have no Input arguments

Check fluent interfaces →

Size matters - methods

Page 64: Common sense methods - Miklos Csere

Q: How many methods should a class have?A: As less as possible.

A number between 5 - 8 public methods is mentioned in several places.

Every public method must implement an interface!

Q: How many lines of code should a class have?A: As less as possible.

A number between 100-200 is mentioned as a limit in several places.

Size matters - interface & classes

Page 65: Common sense methods - Miklos Csere

Q: How many private methods should a class have?A: Put everything in a class that belongs to its responsibilities.

I dislike having many private methods, I think they should be refactored either into decorators or external dependencies of the class.

Size matters - interface & classes

Page 66: Common sense methods - Miklos Csere

Favor Composition over Inheritance

Size matters - interface & classes

Page 67: Common sense methods - Miklos Csere

Evolve interfaces & create traits using default methods.

Con: Today we are unable to declare a protected default method

Size matters - interface & classes

Page 68: Common sense methods - Miklos Csere

❖ Consider your context when writing code ❖ Consider if your class might be extensible (Component)❖ Favor OOP over Procedural Programming

➢ Even if you are not using Domain Driven Design➢ Even if you have an AnemicDomainModel

❖ Try to write declarative code➢ We spend more time reading code than writing it

❖ Take care of temporal coupling❖ Don’t return NULL❖ Don’t use Static Methods❖ Defensive Programming can be done with decorators❖ Minimize mutability

Summary

Page 69: Common sense methods - Miklos Csere

❖ Think about your code as a final product that you will unveil to the world.

❖ Don’t just write code! Design it!

❖ Think about the UX of the developers using your code. That might be you in 2 years!

DRY → don’t repeat yourselfKISS → keep it simple (stupid)YAGNI → you ain’t gonna need it

Summary

Page 70: Common sense methods - Miklos Csere

Write beautiful code