Il boilerplate è codice ripetitivo che gli sviluppatori scrivono con modifiche minime in ogni nuovo modulo o progetto. Non contiene logica di business unica, ma semplicemente prepara l'infrastruttura: configurazione, importazione di librerie, gestori standard e classi DTO. Secondo il CodeScene Engineering Productivity Report (2025), il boilerplate costituisce dal 20 al 40 percento di tutto il codice in un'applicazione commerciale tipica. Il problema principale di tale codice non è che si ripete, ma che ogni ripetizione è un punto di errore: un errore in una copia non si sincronizza con le altre e i bug si moltiplicano nel progetto. Automatizzare la generazione di boilerplate tramite generazione di codice, annotazioni e macro è uno dei modi più efficaci per accelerare lo sviluppo senza perdere qualità.
Punti chiave
Il codice boilerplate sono frammenti di codice sorgente che si ripetono in diverse parti di un progetto con variazioni minime. Il termine deriva dall'industria tipografica, dove boilerplate si riferiva a blocchi di testo pre-scritti per i giornali che non necessitavano di riscrittura. In programmazione, è qualsiasi codice che sei costretto a scrivere ripetutamente per soddisfare i requisiti di un framework, linguaggio o architettura.
Il boilerplate non è debito tecnico nel senso classico — non contiene bug e non viola i principi SOLID. Tuttavia, aumenta la quantità di codice da mantenere, testare e leggere. Ogni riga di boilerplate è un potenziale luogo per un errore di battitura che il compilatore non sempre può rilevare.
Secondo il rapporto JetBrains Developer Ecosystem (2025), il 67 percento degli sviluppatori considera il boilerplate la causa principale della riduzione di produttività. Nello sviluppo mobile, questa cifra è più alta: i progetti Android in Java contengono una quantità significativa di codice ripetitivo per findViewById, Intents, adapter RecyclerView e ContentProvider. Kotlin e Swift hanno risolto parte di questi problemi con mezzi sintattici, ma il boilerplate non è scomparso completamente.
Quando si progetta l'architettura, cerca di scegliere soluzioni che minimizzino il codice ripetitivo. Ad esempio, invece di scrivere manualmente l'implementazione Parcelable, usa @Parcelize in Kotlin. Invece di factory per ViewModel — Hilt con @HiltViewModel. Ogni ottimizzazione di questo tipo risparmia ore di sviluppo su scala di progetto.
L'esempio più riconoscibile di boilerplate nello sviluppo Android è l'RecyclerView.Adapter. Prima di Kotlin e ViewBinding, ogni adapter richiedeva circa 80–100 righe di codice ripetitivo: onCreateViewHolder, onBindViewHolder, getItemCount, classe ViewHolder interna, costruttore, binding dei campi. Con ViewBinding il codice si è ridotto, ma non è scomparso completamente.
class UserAdapter(
private val users: List<User>
) : RecyclerView.Adapter<UserAdapter.ViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
val view = LayoutInflater
.from(parent.context)
.inflate(R.layout.item_user, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(
holder: ViewHolder,
position: Int
) {
holder.bind(users[position])
}
override fun getItemCount(): Int = users.size
class ViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun bind(user: User) {
Glide.with(itemView)
.load(user.avatarUrl)
.into(itemView.avatar)
}
}
}
Un altro esempio illustrativo è il mapping JSON in Java senza librerie. L'analisi manuale di una risposta API richiede la scrittura di decine di metodi, ciascuno dei quali verifica la presenza di una chiave, ottiene il valore e lo assegna a un campo. Con librerie come Gson, Moshi o Kotlin Serialization — è una singola annotazione @Serializable.
Nello sviluppo iOS, il boilerplate classico è l'implementazione di CodingKey e Decodable per ogni risposta API, specialmente quando le chiavi JSON differiscono dai nomi delle proprietà in camelCase. Nonostante la generazione automatica di Codable, l'enumerazione manuale di CodingKeys rimane una fonte di codice ripetitivo.
Usa la generazione di codice per creare boilerplate in fase di compilazione. Su Android — Annotation Processing (KSP) per Room, Dagger, Moshi. Su iOS — Sourcery per Codable e AutoMockable. Per ogni ora spesa nella configurazione della generazione, risparmi giorni di copia manuale.
Il boilerplate danneggia un progetto in tre modi: rallenta la scrittura di nuove funzionalità, complica la lettura del codice esistente e crea punti di desincronizzazione durante le modifiche.
Il rallentamento dello sviluppo è ovvio: lo sviluppatore perde tempo scrivendo codice che non contiene logica di business. Invece di implementare una nuova funzionalità (ad esempio, aggiungere un campo al profilo utente), scrive una migrazione DB, classe DTO, mapper nell'entità di dominio, schermata con campo di input, validazione e test per ogni livello. La maggior parte di questo lavoro è meccanico.
La desincronizzazione è un problema più insidioso. Quando una struttura dati cambia in un punto (ad esempio, viene aggiunto un campo a una risposta API), lo sviluppatore deve aggiornare DTO, mapper, modello, schermata e test. Se un punto viene saltato, l'applicazione compila ma si blocca in fase di esecuzione o — peggio — mostra dati errati senza errore. Più strati di boilerplate ci sono, maggiore è la probabilità di tale desincronizzazione.
Analizza il progetto alla ricerca di pattern ripetuti. Se vedi tre classi identiche con nomi diversi — è un candidato per la generazione. Introduci la generazione di codice come parte della soluzione architetturale, non come ottimizzazione una tantum. Si ripaga con ogni nuovo modulo.
La generazione di codice è il modo più affidabile per combattere il boilerplate. Invece di scrivere manualmente codice ripetitivo, lo sviluppatore descrive metadati (annotazioni, schemi, configurazioni) e il generatore crea il codice pronto in fase di compilazione.
Nell'ecosistema Android, lo strumento standard di generazione di codice è KSP (Kotlin Symbol Processing). Sostituisce il vecchio KAPT e funziona più velocemente grazie all'accesso diretto all'AST di Kotlin senza generare stub Java. KSP è utilizzato da Room (generazione di implementazioni DAO), Moshi (generazione di JsonAdapter), Glide (generazione di classi di caricamento target) e Dagger (generazione del grafo DI).
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: Long,
@ColumnInfo(name = "full_name") val name: String,
@ColumnInfo(name = "avatar_url") val avatarUrl: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getById(@Param("id") id: Long): UserEntity?
}
Nello sviluppo iOS, il ruolo della generazione di codice è svolto da Sourcery — uno strumento che elabora template Stencil e genera codice Swift basato su annotazioni nei commenti. Scenari tipici: AutoMockable (generazione di mock per test), AutoCodable (implementazione Decodable senza CodingKeys), AutoEquatable e AutoLenses.
Per i progetti Flutter, il boilerplate viene ridotto da generatori tramite build_runner: json_serializable per il mapping JSON, freezed per modelli immutabili con copyWith, retrofit_generator per client API e injectable_generator per DI. Ciascuno di questi generatori trasforma 10–20 righe di annotazioni in centinaia di righe di codice pronto.
Le annotazioni e le macro sono un modo dichiarativo per dire al compilatore o preprocessore quale codice generare. Lo sviluppatore non scrive l'implementazione, ma marca solo l'intenzione, e il generatore trasforma il markup in codice pronto.
L'esempio più eclatante è Lombok in Java (storicamente) e la data class di Kotlin. La data class in Kotlin genera automaticamente equals, hashCode, toString, componentN e copy — in Java sarebbero necessarie circa 80 righe di codice scritto a mano o l'uso di Lombok con @Data. Kotlin ha risolto il problema a livello di linguaggio, rendendo il boilerplate implicito.
In Swift, un ruolo simile è svolto dalle macro (Swift Macros, introdotte in Swift 5.9). Invece di scrivere manualmente l'implementazione Codable, lo sviluppatore marca la struct con @Codable — e il compilatore genera il codice necessario. Altre macro integrate: @Observable (stato osservabile), @ResultBuilder (costruttori di risultati) e @MainActor (dispatch sul thread principale).
@Codable
struct UserProfile {
let id: Int
let displayName: String
let avatarURL: URL
let bio: String?
}
// @Codable macro generates:
// extension UserProfile: Codable { }
// private enum CodingKeys: String, CodingKey {
// case id, displayName, avatarURL, bio
// }
Quando si sceglie tra generazione di codice e macro, preferisci le macro se il linguaggio le supporta. Le macro funzionano a livello di compilatore, non richiedono configurazione di script di build, non rallentano la compilazione (a differenza di Annotation Processing) e sono sempre sincronizzate con il codice sorgente. Se le macro non sono disponibili — usa generatori esterni tramite KSP, Sourcery o build_runner.
Ogni linguaggio e piattaforma offre i propri strumenti per minimizzare il boilerplate. Di seguito sono riportate pratiche specifiche per i principali stack di sviluppo mobile.
| Piattaforma | Strumento / Tecnica | Cosa sostituisce |
|---|---|---|
| Android / Kotlin | data class | equals, hashCode, toString, copy, componentN |
| Android / Kotlin | @Parcelize | Implementazione Parcelable |
| Android / Kotlin | ViewBinding / DataBinding | findViewById, ButterKnife |
| iOS / Swift | Codable + macro | Parsing JSON manuale, CodingKeys |
| iOS / Swift | Sourcery | AutoMockable, AutoEquatable, AutoLenses |
| Flutter / Dart | freezed + json_serializable | copyWith, classi sealed, equals/hashCode, JSON |
| Flutter / Dart | retrofit_generator | Client API con richieste e risposte tipizzate |
Per il frontend web (React Native / TypeScript), lo strumento principale è la generazione di tipi dalla specifica OpenAPI (openapi-typescript, swagger-codegen). Ogni endpoint riceve automaticamente una richiesta e risposta tipizzate — lo sviluppatore non deve descrivere manualmente le interfacce per centinaia di chiamate API.
Introduci la generazione di codice nelle fasi iniziali del progetto. Migrare un progetto esistente verso generatori è più difficile che progettare con essi da zero. Se il progetto è già scritto — inizia dal punto più doloroso: Java → Kotlin (data class), adapter manuali → ListAdapter con DiffUtil, mapping JSON manuale → Moshi / Kotlin Serialization.
Domande frequenti
Il boilerplate non è debito, ma ridondanza: il codice è corretto, ma ce n'è troppo. Il debito tecnico è una decisione di compromesso consapevole che dovrà essere corretta in seguito. Il boilerplate non richiede correzione — richiede automazione.
No, nei progetti piccoli il boilerplate può essere giustificato dalla semplicità: è immediatamente visibile e facile da modificare. Il problema sorge su larga scala — quando ci sono più di dieci moduli simili, la copia manuale cessa di essere efficace ed è tempo di introdurre la generazione.
Il codice che dipende da servizi esterni con logica non standard (SDK personalizzati, protocolli proprietari) è difficile da generare. In tali casi, il boilerplate viene scritto manualmente ma isolato in moduli separati per minimizzare la dispersione nel progetto.
Per i nuovi progetti, è meglio passare direttamente a Kotlin, dove data class risolve gli stessi compiti a livello di linguaggio. Se il progetto rimane in Java — Lombok rimane lo standard de facto, ma tieni presente che richiede un plugin per IDE e potrebbe entrare in conflitto con le nuove versioni di Java.
Sì, la generazione di codice aggiunge tempo alla compilazione. KSP è più veloce di KAPT ma aggiunge comunque secondi o minuti a una compilazione completa. Ottimizzazione: usa build incrementali e memorizza nella cache i risultati della generazione tra le build.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche