All Projects → tum-esi → common-coding-conventions

tum-esi / common-coding-conventions

Licence: other
A concise and universal guide to clear software design.

Projects that are alternatives of or similar to common-coding-conventions

Evergreen Skills Developers
List of evergreen skills, based on software development best practices & cross-framework principles, that should serve as a fair assessment of skilled software engineers / developers
Stars: ✭ 818 (+167.32%)
Mutual labels:  best-practices, clean-code
Android Modular Architecture
📚 Sample Android Components Architecture on a modular word focused on the scalability, testability and maintainability written in Kotlin, following best practices using Jetpack.
Stars: ✭ 2,048 (+569.28%)
Mutual labels:  best-practices, clean-code
Clean Code Ruby
🛁 Clean Code concepts adapted for Ruby
Stars: ✭ 1,235 (+303.59%)
Mutual labels:  best-practices, clean-code
Best-Coding-practices-in-android
This repo is to add best practices that developers can apply to write clean, short and testable code in android.
Stars: ✭ 86 (-71.9%)
Mutual labels:  best-practices, clean-code
Run Aspnetcore
A starter kit for your next ASP.NET Core web application. Boilerplate for ASP.NET Core reference application, demonstrating a layered application architecture with applying Clean Architecture and DDD best practices. Download 100+ page eBook PDF from here ->
Stars: ✭ 227 (-25.82%)
Mutual labels:  best-practices, clean-code
Clean Code Dotnet
🛁 Clean Code concepts and tools adapted for .NET
Stars: ✭ 4,425 (+1346.08%)
Mutual labels:  best-practices, clean-code
Php Programming Best Practices
Referencia para los desarrolladores de Tiendanube y para la comunidad de PHP.
Stars: ✭ 138 (-54.9%)
Mutual labels:  best-practices, clean-code
Clean Code Javascript
🛁 Clean Code concepts adapted for JavaScript
Stars: ✭ 62,912 (+20459.48%)
Mutual labels:  best-practices, clean-code
Bookmarks
🔖 +4.3K awesome resources for geeks and software crafters 🍺
Stars: ✭ 210 (-31.37%)
Mutual labels:  best-practices, clean-code
Architecture
.NET 6, ASP.NET Core 6, Entity Framework Core 6, C# 10, Angular 13, Clean Code, SOLID, DDD.
Stars: ✭ 2,285 (+646.73%)
Mutual labels:  best-practices, clean-code
php-best-practices
What I consider the best practices for web and software development.
Stars: ✭ 60 (-80.39%)
Mutual labels:  best-practices, clean-code
Movies Kotlin Kata
Katas for practice Kotlin( Coroutines, dataclasses, delegate properties...) Clean Architecture and best practices in Android(DI, Dagger, MVP, Espresso) implemented by Jorge Sánchez (Xurxodev)
Stars: ✭ 240 (-21.57%)
Mutual labels:  best-practices, clean-code
angular-clean-code
My personal best practices when I'm working with Angular.
Stars: ✭ 39 (-87.25%)
Mutual labels:  best-practices, clean-code
Clean Code Typescript
Clean Code concepts adapted for TypeScript
Stars: ✭ 5,075 (+1558.5%)
Mutual labels:  best-practices, clean-code
clean-code-javascript
🛁 Clean Code-Konzepte adaptiert für JavaScript.
Stars: ✭ 37 (-87.91%)
Mutual labels:  best-practices, clean-code
Clean Code Java
Clean Code concepts adapted for Java. Based on @ryanmcdermott repository.
Stars: ✭ 155 (-49.35%)
Mutual labels:  best-practices, clean-code
Clean Code Javascript Tr
JavaScript için Uyarlanmış Temiz Kod Kavramları
Stars: ✭ 232 (-24.18%)
Mutual labels:  best-practices, clean-code
Write Readable Javascript Code
📖 All about writing maintainable JavaScript
Stars: ✭ 244 (-20.26%)
Mutual labels:  best-practices, clean-code
playwright-lighthouse
🎭: Playwright Lighthouse Audit
Stars: ✭ 120 (-60.78%)
Mutual labels:  best-practices
birthtalk
Meet who have birth common with you
Stars: ✭ 36 (-88.24%)
Mutual labels:  clean-code

 

C³: Common Coding Conventions

Keep it simple and solid, let the toolchain be smart,
code correctness is the duty, readability the art.

The goal of these conventions is to be concise, universal, and remarkable. It targets emerging code enthusiasts under time pressure and covers 7 topics:

  1. General Clarifications   (Keep ConsistencyBreak rulesImprove CodeTerms)
  2. Architecture   (Low CouplingCoherent Abstraction)
  3. Implementation   (DRYSmall ScopesExpress IdeasSort ArgsCompose)
  4. Naming   (Pick OneBoolsSubprogramsTypesVariablesWord Pairs)
  5. Code Layout
  6. Documentation   (CommentsTODOsReadmesLoggingFile HeadersDocstrings)
  7. Languages   (PythonCJavaScript)

To follow this guide, you should already have heard about Object Oriented Programming and know basic programming rules, such as writing loops and meaningful functions instead of copy pasting instructions.

 

General Clarifications

Be consistent with the existent.

“Consistency with this guide is important. Consistency within a project is more important. Consistency within one module or function is the most important” [PEP8].

Break rules if it enhances clarity.

Do not blindly follow this guide but think for yourself. The goal of software development is keeping the code complexity low. Period. None of the rules and fancy patterns matters if the code becomes impossible to maintain.

Leave code cleaner than you found it.

We all have seen bad code, we all have written bad code. Code tends to get messy over time. Therefore, do not only complain about bad code but improve it if you know how. If you don't care to do it, why should anyone else?

Terminology

To be universal, we group several concepts under these broad identifiers:

  • Scope = {Module, File, Namespace, Subprogram}
  • Subprogram = {Procedure, Function, Method}
  • Type = {Primitive, Collection, Struct, Class, ...}
  • Collection = {Array, List, Tuple, Dict, Map, ...}

 

Architecture

To manage complexity, divide your software into smaller parts (scopes) such as modules, classes, and subprograms. Where to separate and where to connect scopes is the art of good architecture.

Two common mistakes in architecture design are the creation of a monster class that has too many responsibilities and letting each class communicate with too many other classes:

Bad Architecture.

Instead, limit the amount and direction of information exchange between classes and create larger architectures from the following building blocks:

Better Architecture.

Aim for low coupling between classes.

You may have many classes but each class should communicate with as few others as possible. If any two classes communicate at all, they should exchange as little information as possible.

Aim for coherent abstraction levels.

Each scope should reflect a single coherent level of abstraction that corresponds to its hierarchy level [ClCd]. In your UML, abstraction should decrease from top to bottom. In your code, the deeper you are in a call tree, the more specific your instructions can be. Avoid state variables at high abstraction levels.

Bad Better Better
engine.start()
nStartUps += 1
if fuelTank.isEmpty():
  fuelGaugeUI.setRedLED()
engine.start()
engine.runTest()
warnings = engine.warnings()
dashboard.show( warnings )
sys.test():
 engine.test():
  sparkPlug.test():
   testIgnition()

Caution: Mixing abstraction levels creates confusion and introduces unnecessary dependencies.

Read more ...

 

Implementation

Once you have an initial plan for the architecture, you can start writing the code for classes and subprograms.

Don't Repeat Yourself (DRY).

Any piece of data or logic should have a single source. Duplicated code is difficult to maintain and represents a missed opportunity for abstraction. As a rule of thumb: If you repeat more than 2 statements more than 2 times, write a new subprogram. At best, any atomic change in program logic should only affect a single line of code.

There are two code smells that should remind you of this rule:

  • Copy & Paste: Every time you take your mouse and mark lines with the intention to copy them, you are going to violate this rule. Instead of slightly adjusting copied lines, think about the common pattern between those lines and create a new function.

  • Repeated if-else and switch-case statements: If you are testing the same conditions at different locations (e.g. state variables), you can abstract these differences with Polymorphism and the Strategy Pattern.

Keep all scopes (file/class/function) small and sorted.

Define subprograms and variables in the smallest scope possible and limit their exposure to external code. Put declarations at the beginning of each scope and initialize variables directly at the declaration. Do not reuse variables in nested scopes or for different purposes.

Express ideas in code: use domain-specific names.

Avoid magic numbers (literal numbers with unclear origin/purpose) but always create constants with meaningful names. Create new types or derive subtypes from primitives to create more specific names, especially for physical quantities.

Bad

double limit = 13.89;        // unit not clear
from_to(int x,  int y,
        int x2, int y2);     // vague argument names 

if (speed > limit && 
   t.h > 22 && t.h < 6){ ... }  // 22 and 6 are magic numbers

Better

MeterPerSecond limit = SPEED_LIMIT_NIGHT;
drive(Point origin, Point destination);

isNight    = (T_NIGHT_MIN < t.h && t.h < T_NIGHT_MAX);
isSpeeding = (limit < speed);
if (isSpeeding && isNight){ ... }

Sort arguments and limit them to 0 – 4 per call.

If the argument list of a subprogram grows too long, try to combine related arguments in a new data structure. For example, instead of passing x, y, z coordinates individually, use a single vector.

Bad Better
makeCircle(double r, double x, double y)
makeCircle(Point center, double radius)

Do not change the same variable in steps but compose once from parts.

Within a subprogram, do not modify the same variable in several steps, e.g. by summing up an amount using total += ... multiple times. Instead, call functions that return some part of the final value and then compose the final value of these parts in one instruction at the end. E.g. total = partA + partB.

Bad Better
totalIncome = 0 
// ... long code to get contract
totalIncome += contract.salary  
// ... long code to access taxoffice
totalIncome -= taxoffice[id].tax
Int totalIncome(employee){      
    salary = getSalary(employee)
    tax    = getTax(employee)   
    return (salary - tax)       
}

Read more ...

 

Naming

Code should communicate behavior to other humans with lower complexity than the behavior it inherits. Since code mostly consists of custom names, your ability to abstract concepts with meaningful names is most important for readability.

Pick one word for one concept.

Each concept should be described by a single word. Do not use send(), write(), and transmit() as synonyms for the same process, such as sending a message over a bus. Same holds true for handleRequest(), processQuery(), or manageIncomingPacket().

Each word should only describe a single concept. Do not use activate() for setting a boolean variable and sending an activation packet to another system component. The first procedure is safe and instant, the second could fail, block execution, or run asynchronously. Better call it sendActivationMsg().

Boolean Variables/Functions should have a is/has/can prefix.

Clean code reads like prose and these prefixes achieve clear and concise naming. There is no difference between the naming of variables, e.g. hasElements, and functions, e.g. hasElements(), except that functions can also answer true/false questions regarding arguments, such as isFile(path) or user.hasAccessTo(file).

  • consider the slightly uncommon prefixes can to express abilities/possibilities, e.g. canWalk.
  • boolean names regarding Collections should use Each/Any before the prefix, e.g. isEachLightOn / isAnyLightOn
  • prefer positive forms. Use isActive not isInactive to avoid confusing negations (!isInactive). Same for hasElements (not isEmpty) and isEnabled (not isDisabled).
  • Avoid further uncommon prefixes, such as does, are, was, will, should.
Rule Bad Better
Consider can isAllowedToWalk, hasWalkAbility, isWalkable canWalk
Avoid not isNotEmpty, !isEmpty hasElements
Avoid are: areAllLightsOn, isAllLightsOn , allLightsOn isEachLightOn
Avoid was/had wasSend, hasBeenSent, hadArrived isSent
Avoid does doesUseIO, mightUseIO isUsingIO, canUseIO

Fun fact: The old jQuery 1.7 had a boolean called doesNotAddBorder. Now they use isBorderBox.

Naming Subprograms (=Procedure/Function)

Procedures may return values, functions always return a value. Methods are subprograms of a class.

  • procedure names should start with a verb. e.g. syncViews(), list.addItem(x).
  • function names should describe the result and, if suitable, its type. e.g. time_ms(), sin(x), isFile(path)
  • class methods should not repeat or include the name of the class. Define Line.length(), not Line.getLineLength()

Caution: Single noun subprograms should be pure functions! Never let e.g. x.length() change a state.

Naming Types (=Class/Struct/Subtypes)

  • type names should be capitalized nouns. E.g. Integer, Date, Line2D
  • enums/structs are types and should be named as types without a special prefix/suffix.
    E.g. enum Color = {RED, GREEN, BLUE}
  • interface names can start with a capital I and can also be adjectives. E.g. IObservable

Naming Variables

  • variables with a large scope should have long names, variables with a small scope may have short names [CdCm].
  • collections (set, array, dict) should have a plural name. E.g. cars, indices
  • the prefix n or num should be used for names representing the total number of objects in a collection. E.g. numCars
  • write constant names in capitals. E.g CFG_TEMPERATURE_MAX = 80.0
  • prefix global variables with g_
Bad Better
score_list = [0] * scores 
for idx, val in score_list:
  score_list = val + 1
scores = [0] * numScores 
for idx, score in scores:
  scores[idx] = score + 1

Use word pairs (opposites, antonyms).

If you start something, you should stop it and not end it [CdCm]. While most opposites can be created by using un- or de- prefixes (lock/unlock), some are more distinct and allow code alignment:

Verb pairs with same length:

set send query insert attach show split enter accept
get recv reply delete detach hide merge leave reject
👆 List of further word pairs

Verb pairs that differ by one character are more visually distinct but still easy to align with one extra space:

open read load push start create grant hit prepend empty
close write store pop stop destroy deny miss append full

Noun and adjective pairs with same/similar length:

max next head new row ack front source client primary leader
min prev tail old col nak rear target server replica follower
 

Avoid inappropriate terms: Many organizations discourage the use of master/slave due to their negative association in different cultures. See 1 and 2.
Avoid useless noise-terms: E.g. data, info, process. What would be the difference between Product, ProductData, and ProductInfo?

Read more ...

 

Code Layout

A clear and consistent visual appearance of your code improves readability and readability helps to understand the code.

  • Existing Project: Stick to the existing recommendations and tools.
  • New Project: Use an automatic code formatter. Examples:
Language Tool
Python black
C uncrustify
C++ clang-format
JavaScript prettier.io
👆 Read more ...

Here are some example recommendations that would be ensured by most formatters:

  • aim for one statement and less than 80 characters per line
  • indent with spaces not tabs because editors do not agree on tab width
  • surround top-level function and class definitions with two or three blank lines.
  • surround binary operators (=, ==, +) with a single space, except when nested inline
  • break lines before operators and align operators vertically

 

Documentation

English is the language of programming, so documentation should also be in English.

Write few brief comments of high quality.

Choose your words carefully and comment only what the code cannot say, that is why you did it, maybe what you did, but never how. Change comments when code changes because “comments that contradict the code are worse than no comments” [PEP8].

Bad Better
if t.h > NIGHT_H:  # Check if night
  if ifr.sense():  # detect person 
    turnLightOn()  # set Pin 13
    lockLight(TIMEOUT) # TIMEOUT=5s
if (isNightTime() and isPersonPresent()):
  turnLightOn()
  lockLight(TIMEOUT) # avoid flickering

Further Don'ts:

  • Don't commit commented-out code. Just remove.
  • Don't create headings with S E P A R A T E D letters because you cannot search for them.
  • Don't assume insider knowledge but write simple comments for anybody on the planet.
  • Don't make jokes or use cute language.
  • Don't comment closing braces. They just indicate that your blocks are too long.

Use TODO and FIXME tags.

Comment unfinished work with TODO: or FIXME:, which allows to search & find these lines later. Some IDEs will automatically highlight these tags via extensions. A TODO is more urgent and needs to be done, a FIXME would be nice to have but is not required.

Write Readme files.

There are two different interest groups for your code, so please make sure that your Readme addresses both.

  • Users: How to install and run your code with examples. Supported OS. Release versions and change logs.
  • Developers: How to compile. Module structure, dependencies, contribution rules, where to contact developers.

Avoid print. Use a library with log levels.

Level Use-case Example
Fatal: the system cannot continue operation segfault
Error: some function is (currently) not working no connection
Warn: unexpected event but retry/alternative works dropped packet
Notice: notable events that do not happen often new device
Info: usual business events relevant to the user user connected
Debug: technological info relevant for developers protocol stages
Trace: step-by-step implementation details loop index
  • Each log entry should at least output log level and file/module name (or topic label). Timestamps and line numbers are optional.
  • Log with context and avoid messages like “Operation Failed” or “Write Complete”.
  • Separate message ("User connected") from parameters ("ip=%s", ip)

Bad

print("User %s connected from %s", uid, ip)

Better

log.info("P2P: User connected. [id=%s, ip=%s]", uid, ip)

Write file headers for header files.

Each code file with interfaces (e.g. .h files in C) should start with a block comment that briefly explains what this module/class/lib does. However, do not provide author name or changelogs as this info belongs into the Version Control System.

Use Docstrings for public APIs

Docstrings are specially formatted comments that can be converted into a code documentation. This is useful as soon as other people start to depend on your interfaces.

👆 Docstring Example
/**
 * Solves equations of the form a * x = b
 * @example
 * // returns 2
 * globalNS.method(5, 10);
 * @example
 * // returns 3
 * globalNS.method(5, 15);
 * @returns {Number} Returns the value of x for the equation.
 */
globalNS.method = function (a, b) {
    return b / a;
};

 

Languages

Each programming language has special mechanisms and some rules are only applicable to a certain language. We also try to give an overview of language-specific rules, but the following list is unfinished and work in progress.

 

References

This guide is partly based on the principles that are explained in the following books and documents and we can recommend them as further reading material.

General Design Principles

Students from TUM and other universities can read these books for free. Simply click the links below and login with your university credentials.

Language Specific Coding Conventions

Videos

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].