Skip to content

mfacecchia/code-styleguide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 

Repository files navigation

Feis Code Styleguide

1. Introduction

This document serves as the complete definition of all the fashion rules to follow when working with projects developed by mfacecchia.

1.1. Guide Notes

Considering that this document defines my personal styling preferences when writing code, the rules specified later on does not represent the only way of actually writing code, and therefore any other styling preference can be considered valid. The rules in this document apply for any programming language (even though there might be few slight differences between some, which will be specified on the appropriate section of this document). Anyways, for a more detailed breakdown of all styling rules per programming language, it's advised to refer to the related programming language's documentations. Some links to the official programming languages' style guides I generally work with can be easily consulted by following the below hyperlinks.

2. Code Formatting

2.1. Naming

The naming for source files, variables, constants, methods and functions, and any other programming language-related concept should follow the rules defined by the programming language, therefore, it's strongly advised to adhere to such rules to keep the source code consistent with most of the other programs you will work with.

2.2. File Encoding and Line Breaks

All source files should be encoded using UTF-8, and all lines should terminate with a \n character (ASCII code 0x10).

On most of my projects, there will probably be an .editorconfig file or similar configuration file to easily follow some of the basic rules on spacing, variables casing, and more.

2.3. Code Formatting

2.3.1 Braces

Delimiting if, else, elif, for, do, while statements, and function definitions with curly braces is strongly advised, even if its body contains only one statement. Moreover, to keep the code as readable as possible, it's advised to place the actual body on a new line if it contains only one statement. About else, and elseif (or elif depending on your preferences), it's fine to place them on the same line of the if statement closing bracket. Opening brackets MUST be placed on the same the statement declaration line. This applies to all other programming-language specific statements that expect curly braces as styling preference. This does not apply to Python statements since, in such specific case, it's expected to use colons (:) instead, and the same applies to all other programming languages which expect similar styling rule.

Examples:

// Correct
fn sum(n1: i32, n2: i32) -> i32 {
    n1 + n2
}

// Correct
fn even_numbers_sum(vec: &Vec<i32>) -> i32 {
    let mut result: i32 = 0;

    // More lines, but more readable
    for n in vec.iter() {
        if (*n % 2 == 0) {
          result += *n;
        }
    }

    // Syntactically correct, but less readable
    for n in vec.iter() {
        if (*n % 2 == 0) { result += *n; }
    }


    // Again, syntactically correct, but not-so-much readable
    for n in vec.iter()
    {
        if (*n % 2 == 0)
        {
          result += *n;
        }
    }

    result
}
2.3.1.1. Empty Blocks

An empty code block can either be closed immediately on the same line, or closed on a new line.

Examples:

// Acceptable
fn empty_function() -> () {}

// Equally acceptable
fn empty_function() -> () {
}

2.3.2. Indentation

Indentation should follow programming language-specific directives, to ensure consistency between all other codebases. For example, Java source files should use four spaces, TypeScript source files should have two spaces, etc... It's advised to use the space character (ASCII code 0x20) rather than the horizontal tab sign (ASCII code 0x09) to ensure consistency on all kinds of text editors. Indentation rules also include continuation lines indent rules(which may differ per language).

2.3.3. Grouping Parentheses

The use of grouping parentheses is advised to make the code more readable, and helps keeping the general code syntax more consistent. This rule does not apply for situations in which it's syntactically impossible to use grouping parentheses by programming language design (such as in a Python for loop).

2.3.4. Spacing

A smart usage of spacing can significantly improve code quality and readability. The following rules of thumb help making the code more consistent and easily understandable by all developers working on the project. If the programming language you're working with enforces some specific spacing rules, then it's advised to follow those rules.

2.3.4.1. Blank Lines

  • Use one blank line to separate methods and functions, and to logically separate the sections within a scope.
  • Use one blank line to separate attributes declarations and methods within a class.
  • Use one blank line to logically separate imports from different packages.
  • Even though this is not mandatory, it's advised to place a single blank line at the end of each source file
  • No trailing spaces

Examples:

// Correct usage of spacing rules
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import com.feis.sampleproject.features.dataLoader.repository.DataRepository;

public class DataLoader {
    private DataRepository repository;
    private static final Logger logger = LogManager.getLogger(DataLoader.class);

    public DataLoader(DataRepository repository) {
        this.repository = repository;
    }

    private void loadData() {
        String authId = SecurityUtils.getAuthenticatedUser().getId();

        List<Data> data = repository.findByUserId(authId);

        return data;
    }
}
// Incorrect, difficult to read
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.feis.sampleproject.features.dataLoader.repository.DataRepository;

public class DataLoader {
    private DataRepository repository;
    private static final Logger logger = LogManager.getLogger(DataLoader.class);
    public DataLoader(DataRepository repository) {
        this.repository = repository;
    }
    private void loadData() {
        String authId = SecurityUtils.getAuthenticatedUser().getId();
        List<Data> data = repository.findByUserId(authId);
        return data;
    }
}

 2.3.4.2. Operators

Always include one space (ASCII code 0x20) before and after all assignment operators, comparison operators, and arithmetic operators.

Examples:

// Correct usage of spacing rules
public User findUserById(int id) {
    Optional<User> optionalUser = userRepository.findById(id);

    if (optionalUser.isEmpty()) {
        throw new NotFoundException("User with ID " + id + " not found.");
    }

    return optionalUser.get();
}
// Incorrect, not readable enough
public User findUserById(int id){
    Optional<User> optionalUser=userRepository.findById(id);

    if (optionalUser.isEmpty()) {
        // Uneven spacing on the "plus" operator, incorrect
        throw new NotFoundException("User with ID " +id+ " not found.");
    }

    return optionalUser.get();
}

 2.3.4.3. Annotations

There should be no blank space between neither annotation definition and its subject, and other annotations for the same. If multiple attributes contain an annotation, then it's advised to place a blank line to keep the declarations clean and understandable.

Examples:

// Correct
@AllArgsConstructor
@Service
public UserService {
    // Incorrect
    @Autowired

    private UserRepository repository;
}
public UserService {
    // Clean and clear separation of declarations
    @Autowired
    private UserRepository repository;

    @Autowired
    private UserGroupsService userGroupsService;
}
public UserService {
    // Incorrect, in case of tons of attributes this can
    // become quite difficult to read
    @Autowired
    private UserRepository repository;
    @Autowired
    private UserGroupsService userGroupsService;
}

 2.3.4.4. Parentheses

There should be even one-character spacing for either opening and closing brackets. An exception is made in methods and functions declaration, which brackets will contain a single space only after the closing, but not before the opening one. This rule does not apply on methods/functions calling since, in that specific case, it's required to keep the arguments definition without any spacing before and after the opening and closing brackets by most programming language design.

Examples:

// Correct usage of spacing rules
public User findUserById(int id) {
    Optional<User> optionalUser = userRepository.findById(id);

    // Correct, even spacing between brackets opening and closing
    if (optionalUser.isEmpty()) {
        throw new NotFoundException("User with ID " + id + " not found.");
    }

    return optionalUser.get();
}
// Incorrect, no spacing on the closing line
public User findUserById(int id){
    Optional<User> optionalUser = userRepository.findById(id);

    // No spacing between either the `if` statement, and the opening curly bracket
    if(optionalUser.isEmpty()){
        throw new NotFoundException("User with ID " + id + " not found.");
    }

    return optionalUser.get();
}

2.3.4.5. Comments

Comments should always begin with a space. This rule applies to all types of comment declarations (either single, and multi line).

Examples:

// Correct
public void doSomething() {
    // ... Some logic here ...
}

//Incorrect, needs a space
public void doSomething() {
    // ... Some logic here ...
}

2.3.5. Variables Declarations

Every variable declaration should declares only one variable. Declaring multiple variables in a single line is discouraged since it can become misleading or harder to read and understand in larger codebases.

Examples:

// Incorrect, less readable
int a = 5, b = 10;

// Cleaner, better solution
int a = 5;
int b = 10;

2.3.6. Logging

Logging is very important and should be used everywhere possible to make the code as a whole more professional, and drastically improve debugging experience. Using console logs is strongly discouraged, and is more appropriate to make use logging libraries such as Log4J or any other one of your choosing. Logging should follow the following pattern to ensure consistency between all the other projects, and should include:

  • Timestamp
  • Class name (working with an OOP Language)
  • Method name
  • Brief description of the operation being executed

Examples:

public void findById(int id) {
    try {
        // Correct usage of logging level
        logger.info("UserService.findById ::: Fetching user information for ID {}", id);
        userRepository.findById(id).orElseThrow(
                () -> new NotFoundException("User with ID {} not found");
        );
    } catch (NotFoundException e) {
        // Incorrect, missing class name and method name,
        // but correct usage of logging level
        logger.error("User with ID {} was not found.", e);
        throw e;
    } catch (Exception e) {
        // Correct logging pattern and level
        logger.error("UserService.findById ::: Unexpected error while fetching user info.", e);
        throw e;
    }
}

2.3.6.1. Logging Levels

The use of the appropriate logging levels helps the developer understanding the message severity, providing clear runtime insights about the application status, and enabling effective per-level logs filtering. The most used log levels in my projects are mainly INFO for messages about a method execution, and ERROR in catch blocks (or except in certain programming languages) to log the exception stack trace, but using the other levels in some specific cases is accepted as well.

2.3.7. Comments

2.3.7.1. Comments Style

Using comments now and then can help other developers (and yourself) better understand the purpose of a specific code block, and therefore its usage is advised. It's also advised, though, not to abuse comments, rather prefer using them for particularly tricky code blocks, or to explain the reason behind the choice of a solution over another. Indent the comments the same level as the surrounding code so that they can be more easily read, and prefer multi line comment blocks over single line ones.

2.3.7.2. Utility tags

While working on a feature, it's quite common to leave some comments as a note for a later time. To differentiate the scopes and quickly understand the "problem", it's advised to prepend specific tags at the beginning of the comment; some of those tags include:

  • TODO - To mark something that's supposed to be added later on during the development
  • FIXME - To report a bug that's to be fixed
  • WIP - To mark a code snippet as something that's intended to be a preview and, therefore is not intended to be added to version control's main branch or not ready for production yet.

To more easily distinguish the different tags, you may want to install an extension for your favourite IDE to highlight the comments based on such tags.

Examples:

public User getUserById(int id) throws NoSuchElementException {
    // TODO: Add a `try/catch` to handle possible empty `Optional`
    return repository.findById(id).get();
}

public User getUserByEmail(String email) throws NoSuchElementException {
    // FIXME: Finding user by first name instead of Email
    return repository.findByFirstName(email).get();
}

// WIP: still thinking about implementation
public User getUserByEmail(String email) {
    // What to do here?
}

2.3.8. Documentation

Most programming languages offer inline documentation features through specific formatting rules. Using them to improve APIs understanding is advised (but not mandatory). Each programming language has its own formatting rules, so assure to carefully follow such rules while writing documentation.

Examples:

/**
    * Validates the authentication token based on various
    * checks such as expiry date, signature, and more.
    *
    * @param authToken the token to validate
    *
    * @return whether the authentication token is valid or not
    * in form of boolean value
    */
public boolean validateAuthToken(Jwt authToken) {
    // ... Some logic here ...
}
/// Validates the authentication token based on various
/// checks such as expiry date, signature, and more.
///
/// # Arguments
/// * `auth_token` - The `Jwt` to validate.
///
/// # Returns
/// A `bool` value representing whether the authentication token
/// is valid or not
fn validate_auth_token(auth_token: &Jwt) -> bool {
    // ... Some logic here ...
}

3. Codebase Structure

This style guide section focuses on the packages organization of more complex projects, rather than simpler ones, therefore, this is no applicable for all projects.

3.1. Packages Structure

Packages in my projects follow the feature-based organization, and are structured similarly this way:

  • A commons package, enclosing all types of classes and functions used by any package in the application which cannot be classified for a specific feature; this package generally contains utility functions and classes, configuration properties, custom exceptions, and more based on the software
  • A features package, enclosing any feature class and function, each one in a more specific package.

Optionally, the application can also contain a special package defined as security enclosing security-related classes (if the application involves authentication).

Example (taken from a simplified version of my personal Maven Archetype):

src/
├── MainApplication.java
├── common/
│   ├── data/
│   │   ├── dto/
│   │   │   └── BaseGetDto.java
│   │   └── entity/
│   │       ├── BaseAuditingEntity.java
│   │       └── BaseEntity.java
│   ├── enums/
│   │   └── ValidationMessage.java
│   ├── exception/
│   │   ├── AuthenticationException.java
│   │   ├── ResourceNotFoundException.java
│   │   ├── ValidationException.java
│   │   ├── handler/
│   │   │   └── GeneralExceptionHandler.java
│   │   └── model/
│   │       └── ErrorResponse.java
│   ├── mapper/
│   │   └── BaseMapper.java
│   ├── repository/
│   │   └── BaseRepository.java
│   └── service/
│       ├── AbstractFileService.java
│       └── AbstractService.java
├── configuration/
│   └── CorsConfig.java
├── features/
│   └── user/
│       ├── data/
│       │   ├── User.java
│       │   └── dto/
│       │       ├── request/
│       │       │   ├── UserCreateDto.java
│       │       │   └── UserUpdateDto.java
│       │       └── response/
│       │           ├── UserDto.java
│       │           └── UserPageDto.java
│       ├── mapper/
│       │   └── UserMapper.java
│       ├── repository/
│       │   └── UserRepository.java
│       └── service/
│           └── UserService.java
└── security/
    ├── SecurityConfig.java
    └── annotations/
        ├── HasRole.java
        └── HasRoleAspect.java

3.1.1. Package Structure Notes

This section explains the ideal structure a codebase should have, but it's important to state that this may or may not be ideal for every project as they can serve different scopes and, therefore, require a different packages organization.

4. Version Control

4.1. Repository Naming

Repositories should use kebab-case.

4.2. Branches Naming

Branches should keep a consistent naming even though the naming such convention may vary based on the project. The casing to use is camelCase, and MUST NOT include spaces.

Examples:

#This is generally used for larger and more complex projects,
#usually involving sprint-based tasks organization
issue_{version}/task_{card code}

#These are acceptable formats for smaller projects as well
feat/authentication
fix/userDeletion

4.3. Commits

Commits styling follow Conventional Commits rules. You can refer to their accurate documentation to know more about how to deliver the best quality in commits as well.

5. Document Changelog

  • 2025-10-31, 22:02 UTC - mfacecchia - Created Document
  • 2025-11-01, 00:23 UTC - mfacecchia - Updated code formatting, and logging sections
  • 2025-11-01, 12:32 UTC - mfacecchia - Updated spacing && version control rules
  • 2025-11-01, 16:53 UTC - mfacecchia - Updated comments-related style rules
  • 2025-11-01, 18:40 UTC - mfacecchia - Updated packages structure style rules

 6. Credits

This document was written and curated by mfacecchia.

About

Code styleguide document for all my projects

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors