Salta al contenuto principale

05 - Struttura del Codice e Organizzazione

Organizza il codice per la manutenibilità: folder structure, naming conventions, separation of concerns e configurazioni multi-ambiente.

Cosa ne pensi di questo articolo?

05 - Struttura del Codice e Organizzazione
ClaudeFoto:Matheus BertelliPexels

In Breve

Organizza il codice per la manutenibilità: folder structure, naming conventions, separation of concerns e configurazioni multi-ambiente.

Struttura del Codice: Organizzazione e Convenzioni

Una struttura del codice ben organizzata è il fondamento di un progetto mantenibile. Claude può aiutarti a definire convenzioni, organizzare le cartelle e mantenere separation of concerns in modo consistente durante tutto lo sviluppo.

In questo articolo esploreremo best practices per organizzare progetti Spring Boot e Angular, con focus su naming conventions, gestione configurazioni e pattern di organizzazione del codice.

Cosa Imparerai

  • Organizzazione cartelle per progetti scalabili
  • Naming conventions per file, classi e variabili
  • Separation of concerns efficace
  • Gestione configurazioni multi-ambiente
  • Pattern per codice condiviso

Principi di Organizzazione

I 5 Principi della Struttura Codice

PrincipioDescrizioneBeneficio
Colocazione File correlati vicini Navigazione rapida, meno context switching
Prevedibilità Struttura consistente Onboarding veloce, meno errori
Modularita Feature isolate Riusabilita, testing indipendente
Scalabilità Cresce senza refactor Manutenzione lungo termine
Esplicitezza Nomi descrittivi Codice autodocumentante

Struttura Backend: Spring Boot

Package by Feature vs Package by Layer

Package by Layer

com.company.app/
├── controller/
│   ├── OrderController
│   ├── ProductController
│   └── CustomerController
├── service/
│   ├── OrderService
│   ├── ProductService
│   └── CustomerService
├── repository/
│   ├── OrderRepository
│   └── ProductRepository
└── model/
    ├── Order
    └── Product

Pro: Semplice, familiare

Contro: Accoppiamento alto, difficile navigare

Package by Feature

com.company.app/
├── order/
│   ├── OrderController
│   ├── OrderService
│   ├── OrderRepository
│   └── Order
├── product/
│   ├── ProductController
│   ├── ProductService
│   └── Product
└── shared/
    └── ...

Pro: Alta coesione, facile navigare

Contro: Richiede disciplina

Raccomandazione

Per progetti personali e team piccoli, package by feature è preferibile. Mantiene il codice correlato insieme e facilità il refactoring in microservizi futuri.

Struttura Completa Spring Boot

Struttura Progetto Spring Boot
order-service/
├── src/
│   ├── main/
│   │   ├── java/com/company/orders/
│   │   │   ├── OrderServiceApplication.java
│   │   │   │
│   │   │   ├── order/                    # Feature: Orders
│   │   │   │   ├── api/                  # Web layer
│   │   │   │   │   ├── OrderController.java
│   │   │   │   │   ├── OrderMapper.java
│   │   │   │   │   └── dto/
│   │   │   │   │       ├── CreateOrderRequest.java
│   │   │   │   │       ├── OrderResponse.java
│   │   │   │   │       └── OrderItemDto.java
│   │   │   │   ├── domain/               # Business logic
│   │   │   │   │   ├── Order.java
│   │   │   │   │   ├── OrderItem.java
│   │   │   │   │   ├── OrderStatus.java
│   │   │   │   │   └── OrderService.java
│   │   │   │   ├── persistence/          # Data access
│   │   │   │   │   ├── OrderRepository.java
│   │   │   │   │   ├── OrderEntity.java
│   │   │   │   │   └── OrderJpaMapper.java
│   │   │   │   └── event/                # Domain events
│   │   │   │       ├── OrderCreatedEvent.java
│   │   │   │       └── OrderEventPublisher.java
│   │   │   │
│   │   │   ├── payment/                  # Feature: Payments
│   │   │   │   ├── api/
│   │   │   │   ├── domain/
│   │   │   │   └── client/               # External integration
│   │   │   │       ├── StripeClient.java
│   │   │   │       └── StripeConfig.java
│   │   │   │
│   │   │   ├── shared/                   # Cross-cutting
│   │   │   │   ├── exception/
│   │   │   │   │   ├── BusinessException.java
│   │   │   │   │   ├── NotFoundException.java
│   │   │   │   │   └── GlobalExceptionHandler.java
│   │   │   │   ├── validation/
│   │   │   │   │   └── ValidOrderStatus.java
│   │   │   │   └── util/
│   │   │   │       └── DateUtils.java
│   │   │   │
│   │   │   └── config/                   # Configuration
│   │   │       ├── SecurityConfig.java
│   │   │       ├── WebConfig.java
│   │   │       ├── KafkaConfig.java
│   │   │       └── properties/
│   │   │           └── AppProperties.java
│   │   │
│   │   └── resources/
│   │       ├── application.yml
│   │       ├── application-dev.yml
│   │       ├── application-prod.yml
│   │       └── db/migration/             # Flyway
│   │           ├── V1__create_orders.sql
│   │           └── V2__add_payment_ref.sql
│   │
│   └── test/
│       └── java/com/company/orders/
│           ├── order/
│           │   ├── api/
│           │   │   └── OrderControllerTest.java
│           │   └── domain/
│           │       └── OrderServiceTest.java
│           └── integration/
│               └── OrderIntegrationTest.java
│
├── docker/
│   └── Dockerfile
├── pom.xml
└── README.md

Naming Conventions Java

Convenzioni Naming Spring Boot
## CLASSI

# Controllers: {{ '{' }}Entity{{ '}' }}Controller
OrderController, ProductController, CustomerController

# Services: {{ '{' }}Entity{{ '}' }}Service o {{ '{' }}UseCase{{ '}' }}Service
OrderService, PaymentProcessingService, NotificationService

# Repositories: {{ '{' }}Entity{{ '}' }}Repository
OrderRepository, CustomerRepository

# DTOs: {{ '{' }}Action{{ '}' }}{{ '{' }}Entity{{ '}' }}Request/Response
CreateOrderRequest, OrderResponse, UpdateOrderRequest

# Entities: {{ '{' }}Entity{{ '}' }} o {{ '{' }}Entity{{ '}' }}Entity (per evitare conflitti)
Order, OrderEntity (se c'è domain model separato)

# Exceptions: {{ '{' }}Causa{{ '}' }}Exception
OrderNotFoundException, PaymentFailedException, ValidationException

# Events: {{ '{' }}Entity{{ '}' }}{{ '{' }}Action{{ '}' }}Event
OrderCreatedEvent, PaymentProcessedEvent, OrderShippedEvent


## METODI

# Controller: verbo HTTP implicito nel mapping
@PostMapping → create(...)
@GetMapping("/{id}") → getById(...)
@GetMapping → getAll(...)
@PutMapping → update(...)
@DeleteMapping → delete(...)

# Service: verbo esplicito
createOrder(), findOrderById(), updateOrderStatus(), cancelOrder()

# Repository: Spring Data naming
findById(), findByStatus(), findByCustomerIdAndStatus()


## VARIABILI

# Collections: plurale
List<Order> orders, Set<String> tags

# Singoli: singolare
Order order, Customer customer

# Booleani: is/has/can prefix
boolean isActive, boolean hasPayment, boolean canCancel

Struttura Frontend: Angular

Struttura Angular Scalabile
src/
├── app/
│   ├── core/                           # Singleton, app-wide
│   │   ├── services/
│   │   │   ├── api.service.ts
│   │   │   ├── auth.service.ts
│   │   │   ├── storage.service.ts
│   │   │   └── index.ts                # Barrel export
│   │   ├── interceptors/
│   │   │   ├── auth.interceptor.ts
│   │   │   ├── error.interceptor.ts
│   │   │   └── loading.interceptor.ts
│   │   ├── guards/
│   │   │   ├── auth.guard.ts
│   │   │   └── role.guard.ts
│   │   └── models/
│   │       ├── user.model.ts
│   │       └── api-response.model.ts
│   │
│   ├── shared/                         # Riutilizzabili
│   │   ├── components/
│   │   │   ├── button/
│   │   │   │   ├── button.component.ts
│   │   │   │   ├── button.component.html
│   │   │   │   ├── button.component.css
│   │   │   │   └── button.component.spec.ts
│   │   │   ├── modal/
│   │   │   ├── table/
│   │   │   ├── form-field/
│   │   │   └── index.ts
│   │   ├── pipes/
│   │   │   ├── currency-format.pipe.ts
│   │   │   └── date-ago.pipe.ts
│   │   ├── directives/
│   │   │   └── click-outside.directive.ts
│   │   └── utils/
│   │       └── validators.ts
│   │
│   ├── features/                       # Feature modules
│   │   ├── orders/
│   │   │   ├── components/
│   │   │   │   ├── order-list/
│   │   │   │   │   ├── order-list.component.ts
│   │   │   │   │   └── order-list.component.html
│   │   │   │   ├── order-detail/
│   │   │   │   ├── order-form/
│   │   │   │   └── order-card/         # Dumb component
│   │   │   ├── pages/                  # Route components
│   │   │   │   ├── orders-page/
│   │   │   │   └── order-detail-page/
│   │   │   ├── services/
│   │   │   │   └── order.service.ts
│   │   │   ├── models/
│   │   │   │   ├── order.model.ts
│   │   │   │   └── order-status.enum.ts
│   │   │   └── orders.routes.ts
│   │   │
│   │   ├── products/
│   │   ├── customers/
│   │   └── dashboard/
│   │
│   ├── layouts/
│   │   ├── main-layout/
│   │   │   ├── main-layout.component.ts
│   │   │   ├── header/
│   │   │   ├── sidebar/
│   │   │   └── footer/
│   │   └── auth-layout/
│   │
│   ├── app.component.ts
│   ├── app.config.ts
│   └── app.routes.ts
│
├── assets/
│   ├── images/
│   ├── icons/
│   └── i18n/                           # Traduzioni
│
├── environments/
│   ├── environment.ts
│   └── environment.prod.ts
│
└── styles/
    ├── _variables.css
    ├── _mixins.css
    └── global.css

Naming Conventions Angular

Convenzioni Naming Angular
## FILE

# Componenti: kebab-case.component.ts
order-list.component.ts
order-detail.component.ts
user-profile-card.component.ts

# Servizi: kebab-case.service.ts
order.service.ts
auth.service.ts
notification.service.ts

# Models: kebab-case.model.ts
order.model.ts
user.model.ts

# Pipes: kebab-case.pipe.ts
currency-format.pipe.ts
date-ago.pipe.ts

# Guards: kebab-case.guard.ts
auth.guard.ts
role.guard.ts

## CLASSI

# Componenti: PascalCase + Component suffix
export class OrderListComponent
export class UserProfileCardComponent

# Servizi: PascalCase + Service suffix
export class OrderService
export class AuthService

# Models/Interfaces: PascalCase (no suffix)
export interface Order
export type OrderStatus = 'PENDING' | 'COMPLETED'

## SELETTORI

# Prefix app- + kebab-case
selector: 'app-order-list'
selector: 'app-user-card'

## VARIABILI

# Signals: nomeSignal o nome (opinabile)
ordersSignal = signal<Order[]>([]);
loading = signal(false);

# Observables: nome$ suffix
orders$ = this.http.get<Order[]>(...)
user$ = this.authService.currentUser$

# Boolean: is/has prefix
isLoading = signal(false);
hasError = signal(false);

Gestione Configurazioni

Spring Boot: Multi-Environment

application.yml - Base
spring:
  application:
    name: order-service

  datasource:
    url: ${DATABASE_URL}
    username: ${DATABASE_USER}
    password: ${DATABASE_PASSWORD}

  jpa:
    hibernate:
      ddl-auto: validate
    open-in-view: false

app:
  cors:
    allowed-origins: ${CORS_ORIGINS:http://localhost:4200}
  security:
    jwt-secret: ${JWT_SECRET}
    jwt-expiration: 3600000
application-dev.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/orders_dev

  jpa:
    show-sql: true

logging:
  level:
    com.company.orders: DEBUG
    org.hibernate.SQL: DEBUG

app:
  cors:
    allowed-origins: http://localhost:4200

Angular: Environment Files

environment.ts
export const environment = {{ '{' }}
  production: false,
  apiUrl: 'http://localhost:8080/api/v1',
  features: {{ '{' }}
    enableAnalytics: false,
    enableDarkMode: true,
  {{ '}' }},
  auth: {{ '{' }}
    tokenKey: 'auth_token',
    refreshTokenKey: 'refresh_token',
  {{ '}' }}
{{ '}' }};

Checklist Struttura Codice

Checklist Organizzazione Progetto

  • Struttura cartelle documentata in README
  • Naming conventions definite e condivise
  • Package by feature per alta coesione
  • Shared/Core separati da features
  • Configurazioni per ambiente (dev, staging, prod)
  • Barrel exports per import puliti
  • Test colocati con codice sorgente

Conclusione e Prossimi Passi

In questo articolo abbiamo definito le basi per una struttura del codice mantenibile e scalabile. Nel prossimo articolo, esploreremo le tecniche avanzate di Prompt Engineering per ottenere il massimo da Claude in scenari complessi.

Punti Chiave da Ricordare

  • Package by feature: Mantieni codice correlato insieme
  • Naming consistente: Convezioni chiare per tutto il team
  • Core/Shared/Features: Separazione chiara delle responsabilità
  • Config per ambiente: Niente hardcoded, tutto configurabile
  • Documenta la struttura: README con albero cartelle

Prova Questi Strumenti

Strumenti gratuiti correlati a questo argomento.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti