Java with AI - Tip #1 - Single Responsibility Principle

Published on


Tip: Apply the Single Responsibility Principle

To get the most out of AI, your code should be easy to understand, easy to isolate, and easy to reason about. And SRP is perfect for this.


Most developers already know SRP as one of the SOLID principles, but with AI assisted development, its value becomes even more obvious. Here’s why.

1. AI gives better output when the task is small

If you give an AI model a messy 300 line class with mixed responsibilities, the output tends to be vague or error prone. But when the class has a single purpose, you can ask the model:

  • “Implement this interface.”
  • “Write tests for this one responsibility.”
  • “Refactor this single piece of logic.”

This way AI can produce sharper and more accurate code because the prompt is pinpointed.

2. Isolated classes are easier to test

AI is exceptionally good at generating test cases when the code is deterministic and scoped. A class dedicated to a single job has a few advantages with regard to code generation:

  • Fewer conditional branches;
  • Fewer dependencies;
  • It’s easier for AI to reason about;
  • It produces more accurate tests;

All of these lead to more stable code and cleaner refactoring.

3. Incremental feature building

When each class has a single responsibility, delegating tasks becomes trivial:

  • “Generate a service that only parses this input.”
  • “Create a validator class for this specific rule.”
  • “Refactor the date normalization logic into its own component.”

AI becomes much more reliable when operating on smaller, well defined components instead of complex, multi purpose services.

4. SRP reduces context confusion

AI models thrive on clear boundaries. With SRP, the model easily understands each class’s purpose, behavior, dependencies and eventual extension points. This reduces hallucinations and incorrect assumptions.


Example #1

Imagine a connector like class that has a few things to do:

  • validates complex inputs
  • calls an external API, with retries and backoff strategies
  • validates and transforms the result
  • logs the output

If you ask AI to write tests for class, you will definitely get a tangled result that will be very hard to follow and to double check. Instead, split responsibilities around the main functionalities:

  • InputValidator
  • ExternalApiClient
  • ResponseTransformer
  • ResultLogger

Now you can ask AI:

  • “Write unit tests for InputValidator.”
  • “Generate a mock for ExternalApiClient.”
  • “Propose better naming for ResponseTransformer.”

Each task becomes simple, accurate, and easy for AI to support.

Example #2

Imagine an entity transformer. It receives an input and performs multiple actions on that entity:

  • validates the caller’s permissions for that entity
  • makes change 1 on the entity
  • makes change 2 on the entity
  • saves the entity to db
  • logs the new entity

Again, if you ask AI to generate the code for this class it will result in a ball of mud. A better way is to split each action in separate classes with single purposes:

  • InputValidator
  • PriceCalculator
  • DiscountApplier
  • EntityRepositor
  • ResultLogger

Now AI can perform better when asked:

  • “Write unit tests for PriceCalculator.”
  • “Write content of PriceCalculator in order to do: .... Make sure tests pass.”
  • “Write unit tests for DiscountApplier.”
  • “Write content of DiscountApplier in order to do: .... Make sure tests pass.”

Stop splitting too much

Like any principle, SRP can be (and often is) over applied. If you find yourself creating dozens of one method classes or splitting logic so finely that understanding the flow requires jumping through tens of files, you’ve gone too far.

Don’t lose sight of the fact that the goal is clarity, not class count. A good rule of thumb: if a class is easy to name, easy to test, and changes for only one reason, you’ve hit the sweet spot.