· Jose Antonio López  · 6 min lectura

Guia d'Agents.md per a desenvolupadors Java i Spring Boot

Layout base amb bones pràctiques per a desenvolupar amb agents intel·ligents en Java i Spring Boot.

Layout base amb bones pràctiques per a desenvolupar amb agents intel·ligents en Java i Spring Boot.

Objectiu

L’objectiu d’aquest article és disposar d’un arxiu base anomenat AGENTS.md que serveixi com a referència per a bones pràctiques en desenvolupar en Spring Boot i Java amb agents o amb eines d’autocompletat de codi com GitHub Copilot o Gemini Code Assistant.

L’arxiu recull tota una sèrie de pràctiques opinionades en base a l’experiència adquirida en projectes reals, i està dissenyat per ser utilitzat com a plantilla inicial en projectes nous o existents que vulguin adoptar aquestes pràctiques.

Estructura del Projecte

L’estructura recomanada dins del projecte és situar-lo a l’arrel. Aquí tens un exemple de com hauria de veure’s dins d’una estructura de projecte:

├── AGENTS.md
├── compose.yaml
├── Dockerfile
├── .env
├── .git
├── .gitignore
├── .idea
├── .mvn
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src

L’arxiu AGENTS.md també pot anomenar-se d’altres maneres diferents. Et suggereixo visitar la pàgina oficial de GitHub Copilot per a més detalls.

Contingut de l’Arxiu AGENTS.md

## Code Fromatting

- Indentation: 4 spaces.
- Blank Lines: Use to separate logical blocks of code.
- Line Length: Maximum 120 characters.
- Use IntelliJ IDEA default code style for Java.

## Java Style

- Use UTF-8 encoding.
- Use descriptive names for classes, methods, and variables.
- Avoid `var` keyword, prefer explicit types.
- All method parameters should be `final`.
- All variables should be declared as `final` where possible.
- Preference for immutability:
- Avoid mutations of objects, specially when using for-each loops or Stream API using `forEach()`.
- Avoid magic numbers and strings; use constants instead.
- Check emptiness and nullness before operations on collections and strings.
- Avoid methods using `throws` clause; prefer unchecked exceptions.

- Avoid comments.
- Comments could be applied for: cron expressions, Regex patterns, TODOs or given/when/then separation in tests.
- Use `@Override` annotation when overriding methods.
- Avoid Objects.*isNull() and Objects.*nonNull() for one or two variables; prefer direct null checks for better performance.
- Wrap multiple conditions in a boolean variable for better readibility
- Prefer early returns.
- Avoid else statements when not necessary and try early returns.

## Lombok Annotations

- Use `@RequiredArgsConstructor` from Lombok for dependency injection via constructor.
- Use `@Slf4j` from Lombok for logging.
- Use `@Builder(setterPrefix = "with"))` for complex object creation.
- Avoid `@Data` annotation; prefer `@Getter` and `@Setter` for granular control.

## Annotations

- **`@Service`**: For business logic classes.
- **`@Repository`**: For data access classes that extend JPA repositories or interact with the database.
- **`@RestController`**: For web controllers.
- **`@Component`**: For generic Spring components.
- **`@Configuration`**: For Spring configuration classes.
- **`@Autowired`**: Prefer constructor injection for production code and field injection only for tests.
- **`@ConfigurationProperties`**: For binding related properties avoid multiple `@Value` annotations. From more than 2 properties, consider using this annotation.
- **`@Transactional`**: Only Service classes should be annotated with @Transactional at class level to avoid transaction management in each method.
- **`@Validated`**: To enable Bean Validation in method parameters or classes.
- **`@PreAuthorize`**: at the controller layer when using Spring Security to enforce method-level security.
- Circular dependencies should be avoided. Avoid `@Order` annotation for dependency resolution.

## Mappers(Com a equip de desenvolupament tria MapStruct o Mappers estrictament estàtics)

**Usa MapStruct**

- Per a mapejar entre DTOs i entitats.
- Defineix interfícies de mapeig amb l'anotació `@Mapper`.
- Usa l'anotació `@Mapping` per a mapejos de camps personalitzats.
- Usa `componentModel = "spring"` per a permetre que Spring gestioni les instàncies del mapejador.
- El mapejador ha de tenir com a sufix `Mapper` (p. ex., `UserMapper`).
- Anomena els mètodes del mapejador clarament (p. ex., `toDto`, `toEntity`).
- Exemple d'Interfície de Mapejador:

  ```java
  @Mapper(componentModel = "spring")
  public interface UserMapper {
      @Mapping(source = "email", target = "emailAddress")
      UserDTO toDto(User user);
      @Mapping(source = "emailAddress", target = "email")
      User toEntity(UserDTO userDto);
  }
  ```

- Per a provar els mapejadors, usa `Mappers.getMapper(UserMapper.class)` per a obtenir una instància del mapejador.

**Usa Mapejadors Estàtics**

- Defineix un constructor privat per a evitar la instanciació amb `UnsupportedOperationException("This class should never be instantiated")`.
- Usa mètodes estàtics per a mapejar entre DTOs i entitats.
- Anomena els mètodes del mapejador clarament (p. ex., `toDto`, `toEntity`).
- Exemple de Classe de Mapejador Estàtic:

  ```java
  public class UserMapper {
      private UserMapper() {
          throw new UnsupportedOperationException("This class should never be instantiated");
      }
      public static UserDTO toDto(final User user) {
          if (user == null) {
              return null;
          }
          return UserDTO.builder()
              .withId(user.getId())
              .withEmailAddress(user.getEmail())
              .build();
      }
      public static User toEntity(final UserDTO userDto) {
          if (userDto == null) {
              return null;
          }
          return User.builder()
              .withId(userDto.getId())
              .withEmail(userDto.getEmailAddress())
              .build();
      }
  }
  ```

## Gestió d'Excepcions

- Excepcions Personalitzades: Crea classes d'excepcions de domini personalitzades que estenguin `RuntimeException`.
- Gestor d'Excepcions Global: Usa `@ControllerAdvice` i `@ExceptionHandler` per a gestionar excepcions globalment.
- Codis d'Estat HTTP: Mapeja les excepcions a codis d'estat HTTP apropiats en els controladors REST.
- Estructura de Resposta d'Error: Defineix una estructura de resposta d'error consistent.

## Proves

- Usa JUnit 5 per a proves unitàries i d'integració.
- Usa Mockito per a simular dependències en proves unitàries.
- Usa `@WebMvcTest(ControllerClass.class)` per a provar controladors Spring MVC.
- Usa `@SpringBootTest` per a proves d'integració que requereixen el context de Spring.
- Usa l'estructura `given/when/then` en els mètodes de prova per a més claredat.
- El nom dels mètodes pot seguir la convenció snake_case o camelCase per a mètodes de prova (p. ex., `get_user_by_id_ok`, `get_user_by_id_not_found_ko`).
- Evita la reflexió en les proves.
- Evita la lògica de negoci en les proves; centra't en la verificació del comportament.

## Registres

- Usa l'anotació `@Slf4j` de Lombok per a registrar per a evitar codi repetitiu amb instàncies de Logger.
- Registra a nivells apropiats: `DEBUG`, `INFO`, `WARN`, `ERROR`.
- Inclou informació contextual en els registres (p. ex., IDs de sol·licitud, IDs d'usuari).
- Evita registrar informació sensible.
- Usa registres estructurats per a una millor gestió dels registres.
- Formata els missatges de registre amb marcadors de posició (p. ex., `{}`) en lloc de la concatenació de cadenes.
- El codi de registre d'informació podria seguir aquesta plantilla: log.info("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: response: {}, userId: {}", body, userId);
- El codi de registre d'error podria seguir aquesta plantilla: log.error("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: errorMessage: {}, userId: {}", errorMessage, userId);

Recomanacions

Pots copiar i enganxar el següent contingut en el teu arxiu AGENTS.md per a establir bones pràctiques en el teu projecte. Recorda que si treballes en equip, és important que tots els membres estiguin d’acord amb aquestes pràctiques i les segueixin consistentment.

També és recomanable revisar i actualitzar periòdicament l’arxiu AGENTS.md per a adaptar-lo a noves pràctiques o tecnologies que puguin sorgir en l’ecosistema de Java i Spring Boot.

Tingues en compte que el codi generat per agents o eines d’autocompletat ha de ser revisat curosament per a assegurar que compleix amb els estàndards i pràctiques definides.

Manteniment

Aniré mantenint i actualitzant aquest arxiu AGENTS.md, així que pot ser que en el futur hi hagi noves versions amb millores o canvis en les pràctiques recomanades.

  • Spring Boot
  • Java
  • Agents
Compartir: