Clean Code in OpenEMS

Clean Code

Clean Code

  • What is Clean Code for us?
    • The Boy Scout Rule
  • Meaningful Names
    • Clean Code: Naming – Key Points
  • Comments
  • Functions
    • Command Query Separation (CQS)
  • Objects and Data Structure
      1. Using Objects and Data Structure

What is Clean Code for us?

Looking back at the notes from our last session, several recurring ideas emerge:

1. Code should explain itself as much as possible

Several points point in this direction: self-explanatory variable names, understandable code, code that explains itself, and comments only where they are truly necessary.

2. Clean Code should be maintainable and extensible

It was mentioned several times that code should be easy to extend, but not overengineered. Future development should also be kept in mind, without introducing unnecessary complexity.

3. Clean Code should be stable and testable

Good code isn’t just pleasant to read — it should also be well testable and behave in a stable way.

4. Reusability and avoiding boilerplate matter

Code reuse and reducing boilerplate were also mentioned. This ties in with topics like DRY, KISS, and clean abstractions.

5. Refactoring is part of it

Clean Code doesn’t only come from writing new code, but also from making small improvements to existing code. This fits well with the Boy Scout Rule.

The Boy Scout Rule

(image omitted)

Always leave the code a little cleaner than you found it.

This refers to small, pragmatic improvements in everyday work — not large-scale rewrites.


Meaningful Names

:paperclip: naming.pdf (222.9 KB)

Core idea: Good names reduce the need for explanation. Code should be named in a way that its intent is clear, without having to read additional comments.

Clean Code: Naming – Key Points

1. Avoid unnecessary abbreviations

Names should be directly understandable and pronounceable.

Example: movieRelationScore instead of relScore, generationTimestamp instead of genymdhms.

2. Make meaningful distinctions

Names like accountData, accountInfo, or moneyAmount are often too vague when they don’t express a real difference.

Better: choose names that make clear what is actually meant.

3. State units in the name if the type doesn’t express them

This is especially important for energy, power, time, percentage values, etc.

Example: gridBuyEnergyWh instead of gridBuyEnergy, socPercentage instead of just soc.

4. Names should express domain meaning, not technical details

Prefixes like I, Base, or Abstract often say more about the implementation than about the meaning.

Better: Movable instead of IMovable or AbstractMovable.

5. Be careful with “Utils” classes

When a class is called Utils, it often lacks clear responsibility. It’s usually better to move methods into the appropriate domain objects.

Example: movie.relationScore(otherMovie) instead of Utils.relationScore(movie1, movie2).


Comments

:paperclip: Clean Code Comments.pdf (313.2 KB)

1. Comments are often a sign that the code isn’t clear enough

Before writing a comment, check whether the intent can be expressed better in the code itself.

Example:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) {
...
}

Better:

if (employee.isEligibleForFullBenefits()) {
...
}

The comment becomes unnecessary because the method name directly expresses the intent.

2. Comments can become outdated or incorrect

Code changes, but comments often don’t. Over time, comments can end up lying — even unintentionally.

3. Good names and small methods reduce the need for comments

Many explanatory comments can be avoided if variables, methods, and classes are well named.

Example: durationInMinutes instead of duration with a comment // Duration in minutes.

4. Good comments explain “why”, not “what”

Comments are useful when they explain technical constraints, business/domain reasons, or unusual behavior.

Example:

// Battery sends 0x00 byte at the beginning of F42 responses – skip it

5. Use JavaDoc deliberately for real public APIs

JavaDoc is especially useful for APIs used by other modules/bundles.

Trivial getters/setters or self-explanatory methods usually don’t need JavaDoc.


Functions

:paperclip: TechExchangeFunctions.pdf (963.2 KB)

1. Keep them small

Functions should be as short as possible. Ideally, fewer than 20 lines of code.

2. Do one thing (SRP)

A function should have exactly one responsibility.

It should do that one thing well — and only that.

3. One level of abstraction

Mixing abstraction levels makes code hard to understand.

Within a function, only one level of abstraction should be used at a time.

4. Function arguments

Term Count Recommendation
Niladic 0 Ideal. Easiest to read and test.
Monadic 1 Very good for transformations. A boolean should never be the only argument.
Dyadic 2 Makes sense for logically related values (e.g. x and y).
Triadic 3 Avoid where possible. Increases mental complexity.
Polyadic 4+ Use an object or a class instead.

5. Side effects & CQS

Functions should do exactly what their name promises.

For example, a function like checkPassword() shouldn’t also initialize a session. Hidden side effects often lead to hard-to-trace bugs.

Command Query Separation (CQS)

A function should either:

  • perform an action (Command)
  • or return a value (Query)

but never both at the same time.


Objects and Data Structure

1. Using Objects and Data Structure

Objects should be used:

  • when data should be hidden and behavior exposed
  • when it’s likely that new types will be implemented in the future

Data Structures should be used:

  • when data should simply be provided
  • when it’s likely that new operations will be implemented in the future

2. Hybrids

Hybrids are a mix of objects and data structures. These should be avoided as much as possible.

3. The Law of Demeter

Objects should only communicate with their immediate surroundings.

Methods should only call methods of:

  • their own class
  • an object created within the method
  • an object passed as a parameter
  • an instance variable of their own class

4. Train Wrecks

(image omitted)

Train wrecks are chains of instance methods where an object is returned. These should be avoided as much as possible.

Example:

a.getB()
 .getC()
 .getD();


1 Like