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
| Principio | Descrizione | Beneficio |
|---|---|---|
| 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
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
## 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
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
## 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
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
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
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







