Boilerplate in App Development: What It Is, Examples and How to Reduce It

Author: IT Sectr Published: 2026-07-26 Reading time: 10 min

Boilerplate is template code that developers write with minimal changes in each new module or project. It does not contain unique business logic, but simply prepares the infrastructure: configuration, library imports, standard handlers and DTO classes. According to the CodeScene Engineering Productivity Report (2025), boilerplate makes up 20 to 40 percent of all code in a typical commercial application. The main problem with such code is not that it repeats, but that each repetition is a point of failure: an error in one copy does not sync with others, and bugs multiply throughout the project. Automating boilerplate generation through code generation, annotations and macros is one of the most effective ways to speed up development without losing quality.

Key Takeaways

  • Boilerplate — template code that repeats from module to module without changes in business logic.
  • Main sources: DI configuration, DTO classes, form screens, network requests and ORM mapping.
  • Boilerplate slows down development and increases the number of errors when copying.
  • Reduction tools: code generation, annotations (Lombok, Data classes), macros and screen generators.
  • The goal is not to eliminate boilerplate entirely, but to automate its creation and synchronization.

What Is Boilerplate?

Boilerplate code is fragments of source code that repeat in different parts of a project with minimal variations. The term comes from the printing industry, where boilerplate referred to pre-written text blocks for newspapers that did not need rewriting. In programming, it is any code you are forced to write over and over to satisfy the requirements of a framework, language or architecture.

Boilerplate is not technical debt in the classic sense — it does not contain bugs and does not violate SOLID principles. However, it increases the amount of code that needs to be maintained, tested and read. Every line of boilerplate is a potential spot for a typo that the compiler cannot always catch.

According to the JetBrains Developer Ecosystem (2025) report, 67 percent of developers consider boilerplate the main cause of reduced productivity. In mobile development, this figure is higher: Android projects in Java contain a significant amount of template code for findViewById, Intents, RecyclerView adapters and ContentProviders. Kotlin and Swift solved some of these problems with syntactic means, but boilerplate has not completely disappeared.

When designing architecture, try to choose solutions that minimize template code. For example, instead of manually writing Parcelable implementation, use @Parcelize in Kotlin. Instead of factories for ViewModel — Hilt with @HiltViewModel. Each such optimization saves hours of development at the project scale.

Examples of Boilerplate in Mobile Projects

The most recognizable example of boilerplate in Android development is the RecyclerView.Adapter. Before Kotlin and ViewBinding, each adapter required about 80–100 lines of template code: onCreateViewHolder, onBindViewHolder, getItemCount, inner ViewHolder class, constructor, field binding. With ViewBinding the code shrank, but did not completely disappear.

Adapter Boilerplate Without Optimizations

kotlin
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)
        }
    }
}

Another illustrative example is JSON mapping in Java without libraries. Manually parsing an API response requires writing dozens of methods, each checking for a key, getting the value and assigning it to a field. With libraries like Gson, Moshi or Kotlin Serialization — it is one @Serializable annotation.

In iOS development, classic boilerplate is the implementation of CodingKey and Decodable for each API response, especially when JSON keys differ from camelCase property names. Despite automatic Codable generation, manually listing CodingKeys remains a source of template code.

Use code generation to create boilerplate at build time. In Android — Annotation Processing (KSP) for Room, Dagger, Moshi. In iOS — Sourcery for Codable and AutoMockable. For every hour spent setting up generation, you save days of manual copying.

Why Template Code Is Harmful

Boilerplate harms a project in three ways: it slows down writing new functionality, complicates reading existing code and creates desynchronization points during changes.

The slowdown in development is obvious: a developer spends time writing code that does not contain business logic. Instead of implementing a new feature (for example, adding a field to a user profile), they write a DB migration, DTO class, mapper to domain entity, screen with input field, validation and tests for each layer. Most of this work is mechanical.

Desynchronization is a more insidious problem. When a data structure changes in one place (for example, a field is added to an API response), the developer must update the DTO, mapper, model, screen and tests. If one spot is missed, the application compiles but crashes at runtime — or worse, shows incorrect data without an error. The more layers of boilerplate, the higher the chance of such desynchronization.

Analyze your project for repeating patterns. If you see three identical classes with different names — that is a candidate for generation. Introduce code generation as part of the architectural solution, not as a one-time optimization. It pays off with every new module.

Code Generation for Boilerplate Automation

Code generation is the most reliable way to fight boilerplate. Instead of manually writing template code, the developer describes metadata (annotations, schemas, configurations), and the generator creates ready-made code at compile time.

In the Android ecosystem, the standard code generation tool is KSP (Kotlin Symbol Processing). It replaces the outdated KAPT and works faster due to direct access to the Kotlin AST without generating Java stubs. KSP is used by Room (DAO implementation generation), Moshi (JsonAdapter generation), Glide (target loading class generation) and Dagger (DI graph generation).

Room Entity Generation with KSP

kotlin
@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?
}

In iOS development, the role of code generation is performed by Sourcery — a tool that processes Stencil templates and generates Swift code based on annotations in comments. Typical scenarios: AutoMockable (mock generation for tests), AutoCodable (Decodable implementation without CodingKeys), AutoEquatable and AutoLenses.

For Flutter projects, boilerplate is reduced by generators via build_runner: json_serializable for JSON mapping, freezed for immutable models with copyWith, retrofit_generator for API clients and injectable_generator for DI. Each of these generators turns 10–20 lines of annotations into hundreds of lines of ready code.

Reduction Through Annotations and Macros

Annotations and macros are a declarative way to tell the compiler or preprocessor what code to generate. The developer does not write the implementation, but only marks the intent, and the generator turns the markup into ready code.

The most striking example is Lombok in Java (historically) and Kotlin data class. Data class in Kotlin automatically generates equals, hashCode, toString, componentN and copy — in Java this would require about 80 lines of hand-written code or using Lombok with @Data. Kotlin solved the problem at the language level, making boilerplate implicit.

In Swift, a similar role is played by macros (Swift Macros, introduced in Swift 5.9). Instead of manually writing Codable implementation, the developer marks the struct with @Codable — and the compiler generates the necessary code. Other built-in macros: @Observable (observable state), @ResultBuilder (result builders) and @MainActor (main thread dispatching).

swift
@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
// }

When choosing between code generation and macros, prefer macros if the language supports them. Macros work at the compiler level, do not require build script configuration, do not slow down compilation (unlike Annotation Processing) and are always synchronized with the source code. If macros are not available — use external generators via KSP, Sourcery or build_runner.

Language-Specific Reduction Practices

Each language and platform offers its own tools for minimizing boilerplate. Below are specific practices for the main mobile development stacks.

PlatformTool / TechniqueWhat It Replaces
Android / Kotlindata classequals, hashCode, toString, copy, componentN
Android / Kotlin@ParcelizeParcelable implementation
Android / KotlinViewBinding / DataBindingfindViewById, ButterKnife
iOS / SwiftCodable + macrosManual JSON parsing, CodingKeys
iOS / SwiftSourceryAutoMockable, AutoEquatable, AutoLenses
Flutter / Dartfreezed + json_serializablecopyWith, sealed classes, equals/hashCode, JSON
Flutter / Dartretrofit_generatorAPI client with typed requests and responses

For web frontend (React Native / TypeScript), the main tool is type generation from OpenAPI specification (openapi-typescript, swagger-codegen). Each endpoint automatically gets a typed request and response — the developer does not need to manually describe interfaces for hundreds of API calls.

Introduce code generation at early stages of a project. Migrating an existing project to generators is more difficult than designing with them from scratch. If the project is already written — start with the most painful point: Java → Kotlin (data class), manual adapters → ListAdapter with DiffUtil, manual JSON mapping → Moshi / Kotlin Serialization.

Frequently Asked Questions

How is boilerplate different from technical debt?

Boilerplate is not debt, but redundancy: the code is correct, but there is too much of it. Technical debt is a deliberate compromise decision that will have to be fixed later. Boilerplate does not require fixing — it requires automation.

Is it always bad to have boilerplate?

No, in small projects boilerplate can be justified by simplicity: it is immediately visible and easy to change. The problem arises at scale — when there are more than ten similar modules, manual copying ceases to be effective and it is time to introduce generation.

What boilerplate cannot be automated?

Code that depends on external services with non-standard logic (custom SDKs, proprietary protocols) is difficult to generate. In such cases, boilerplate is written manually but isolated into separate modules to minimize spread across the project.

Should I use Lombok in new Java projects?

For new projects, it is better to switch directly to Kotlin, where data class solves the same tasks at the language level. If the project stays on Java — Lombok remains the de facto standard, but keep in mind that it requires an IDE plugin and may conflict with new Java versions.

Does code generation increase build time?

Yes, code generation adds time to the build. KSP works faster than KAPT but still adds seconds or minutes to a full build. Optimization: use incremental builds and cache generation results between builds.

Summary

  • Boilerplate — template code that repeats in every module and does not contain unique business logic.
  • Main sources: DTO classes, mappers, network requests, adapters, DI configuration and ORM entities.
  • Boilerplate slows down development, increases the risk of desynchronization and complicates code reading.
  • The main method of fighting it — code generation via KSP, Sourcery, build_runner or openapi-typescript.
  • Annotations and macros (data class, Codable, @Parcelize, freezed) automate the most common patterns.
  • Choose code generation at the architecture design stage, not as a late optimization.
  • Each language has its own tools: Kotlin data class, Swift macros, Dart freezed — use them by default.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also