<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AI Archives - Ronnie Schaniel</title>
	<atom:link href="https://ronnieschaniel.com/category/ai/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Blog</description>
	<lastBuildDate>Mon, 30 Mar 2026 16:35:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Agent Experience Optimisation in Large Code Bases &#8211; Skill vs. Prompt only</title>
		<link>https://ronnieschaniel.com/ai/agent-experience-optimisation-in-large-code-bases-skill-vs-prompt-only/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 16:33:09 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2884</guid>

					<description><![CDATA[<p>Tokens are valuable and so is our time. Let's optimise.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/agent-experience-optimisation-in-large-code-bases-skill-vs-prompt-only/">Agent Experience Optimisation in Large Code Bases &#8211; Skill vs. Prompt only</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="572" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_experience_optimisation_1-1024x572.png" alt="" class="wp-image-2885" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_experience_optimisation_1-1024x572.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_experience_optimisation_1-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_experience_optimisation_1-768x429.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_experience_optimisation_1.png 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>AI-aided coding is popular. Almost all developers know the feeling when tokens or premium requests run out towards the end of the month. Still lots of devs blindly use their AI agent without much optimisation in mind. We can do better and will see here how to optimise a code base for an AI agent and how much this can save in time and tokens.</p>



<h2 class="wp-block-heading">Agent Experience is the New Dev Experience</h2>



<p>In the previous years code bases were optimised for humans. Good READMEs, nice scripts, a clear structure, verification tests for the code design, etc. Now we have a second actor with AI agents that start to contribute and dominate already in most cases. Agents do not complain much about code bases usually. That means it is on you to optimise it for them. You can still ask an agent what it needs to do its work in an ideal way. Optimising for agent experience will save tokens and time, but it will also improve the quality of your changes and make sure the code base follows a defined structure.</p>



<h2 class="wp-block-heading">Adding an Entity as a concrete Use Case</h2>



<p>In my Java Spring Boot <a href="https://github.com/rschaniel/hexagonal_spring_demo">demo project</a> we will add a new entity in an optimised way.</p>



<figure class="wp-block-image size-full is-resized mt-4"><img decoding="async" width="572" height="314" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/scaffold_entity_skill.png" alt="" class="wp-image-2890" style="width:397px;height:auto" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/scaffold_entity_skill.png 572w, https://ronnieschaniel.com/wp-content/uploads/2026/03/scaffold_entity_skill-300x165.png 300w" sizes="(max-width: 572px) 100vw, 572px" /></figure>



<p>In that skill folder we have got references and a script alongside the SKILL.md file. The details of the skill can be found on <a href="https://github.com/rschaniel/hexagonal_spring_demo/tree/main/.github/skills/scaffold-entity" target="_blank" rel="noreferrer noopener">GitHub</a>. Notably the skill creates a spec file and then uses that in scaffold-entity.sh. The script generates multiple files for the entity:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">| # | Layer          | File                                |
|---|----------------|-------------------------------------|
| 1 | Domain         | `&lt;Entity&gt;.java`                     |
| 2 | Domain         | `&lt;Entity&gt;Repository.java`           |
| 3 | Application    | `Create&lt;Entity&gt;UseCase.java`        |
| 4 | Application    | `Get&lt;Entity&gt;UseCase.java`           |
| 5 | Application    | `GetAll&lt;Plural&gt;UseCase.java`        |
| 6 | Application    | `Delete&lt;Entity&gt;UseCase.java`        |
| 7 | Application    | `Create&lt;Entity&gt;Command.java`        |
| 8 | Application    | `&lt;Entity&gt;NotFoundException.java`    |
| 9 | API            | `&lt;Entity&gt;Controller.java`           |
| 10| Infrastructure | `&lt;Entity&gt;Entity.java`               |
| 11| Infrastructure | `&lt;Entity&gt;RepositoryAdapter.java`    |
| 12| Infrastructure | `Jpa&lt;Entity&gt;Repository.java`        |
| 13| Test           | `Create&lt;Entity&gt;UseCaseTest.java`    |
| 14| Test           | `&lt;Entity&gt;ControllerTest.java`       |</code></pre>



<p>Like that you receive the complete hexagonal structure for an entity with its basic CRUD operations. Some tests are also introduced.</p>



<p>Compared to a prompt-only approach this is cheaper and faster. The potential savings are summarised in the table below:</p>



<figure class="wp-block-table mt-4"><table class="has-fixed-layout"><thead><tr><th><br></th><th>Without skill (today)</th><th>With skill</th></tr></thead><tbody><tr><td><strong>Agent reads</strong></td><td>5 instruction files + 6-8 reference files (~9,000 input tokens)</td><td>SKILL.md only (~500 input tokens)</td></tr><tr><td><strong>Agent generates</strong></td><td>14 files of boilerplate (~4,000 output tokens)</td><td>1 spec file + 1 shell command (~200 output tokens)</td></tr><tr><td><strong>Tool call overhead</strong></td><td>14&nbsp;<code>create_file</code>&nbsp;calls (~2,800 tokens overhead)</td><td>1&nbsp;<code>create_file</code>&nbsp;+ 1&nbsp;<code>run_in_terminal</code>&nbsp;(~400 tokens)</td></tr><tr><td><strong>Customization</strong></td><td>N/A (interleaved with generation)</td><td>2-3 small edits (~500 output tokens)</td></tr><tr><td><strong>Total tokens</strong></td><td><strong>~16,000-20,000</strong></td><td><strong>~1,600-2,000</strong></td></tr><tr><td><strong>Token savings</strong></td><td>—</td><td><strong>~85-90%</strong></td></tr><tr><td><strong>Wall-clock time</strong></td><td>~3-5 min (many sequential LLM calls)</td><td><strong>~30-45 sec</strong>&nbsp;(one script + small edits)</td></tr><tr><td><strong>Quality</strong></td><td>LLM may deviate from patterns</td><td><strong>Script output is deterministic</strong></td></tr></tbody></table><figcaption class="wp-element-caption"><em>Table by Claude Opus 4.6.</em></figcaption></figure>



<p>You can see that we save 85%-90% in tokens and around the same in time. In addition we make sure that the script creates the same structure every time. A review and a few edits are of course necessary. Let us see in the next section how to further optimise for agent experience.</p>



<h2 class="wp-block-heading">Further Optimisations for AI Coding Agents to Explore</h2>



<p>This is only one way to optimise your coding agent&#8217;s behaviour there are many more aspect. Those I list below.</p>



<ul class="wp-block-list">
<li><strong>Keep a project manifest or architecture summary</strong>&nbsp;— One concise file that tells the agent where things live, what depends on what, and what the conventions are. Without it, every conversation starts with the agent reading half your codebase just to get oriented.</li>



<li><strong>Write scoped instruction files per directory or layer</strong>&nbsp;— Use&nbsp;<code>applyTo</code>&nbsp;patterns so the agent only loads the rules that matter for the file it&#8217;s editing. No need to feed it the entire rulebook when it&#8217;s just touching one corner of the project.</li>



<li><strong>Create prompt files for things you keep asking for</strong>&nbsp;— If you&#8217;ve explained the same task twice, it should be a&nbsp;<code>.prompt.md</code>&nbsp;you invoke with one line. The agent doesn&#8217;t need to rediscover the pattern every time, and you don&#8217;t need to re-type the instructions.</li>



<li><strong>Batch independent reads, sequence dependent ones</strong>&nbsp;— When the agent needs to understand context, let it read multiple files in parallel rather than one by one. But if step B depends on step A&#8217;s result, don&#8217;t let it guess — make that dependency explicit in your instructions. This alone can cut exploration time in half.</li>



<li><strong>Make the agent run tests before it&#8217;s done</strong>&nbsp;— Add a rule that every change ends with a test run. You&#8217;d be surprised how many issues this catches automatically. It&#8217;s cheaper to fail fast in the same conversation than to debug a broken build in the next one.</li>



<li><strong>Be specific in what you ask for</strong>&nbsp;— &#8220;Add a&nbsp;<code>getByStatus</code>&nbsp;method to the Order repository&#8221; costs a fraction of &#8220;make orders filterable by status.&#8221; The more precise the request, the less the agent needs to explore, guess, and over-engineer.</li>



<li><strong>Use a structured change request template</strong>&nbsp;— Three to five lines: what, where, constraints, tests needed. It removes ambiguity completely. The agent stops asking questions and starts working immediately.</li>



<li><strong>Record gotchas and decisions somewhere the agent can find them</strong>&nbsp;— When you hit a tooling quirk or make a design decision that isn&#8217;t obvious from the code, write it down in repo memory. Otherwise the agent will rediscover it the hard way every single time, and you&#8217;ll pay for that investigation in tokens.</li>



<li><strong>Designate a golden reference implementation</strong>&nbsp;— Pick one well-tested vertical slice and treat it as the canonical example. The agent copies from working code instead of interpreting prose rules, which means fewer deviations and more consistency across the board.</li>



<li><strong>Add architecture tests and static analysis to the build</strong>&nbsp;— ArchUnit, ESLint, Checkstyle — whatever fits your stack. Convention violations become build errors, not suggestions the agent might overlook. The feedback loop is instant and doesn&#8217;t depend on anyone reading instructions carefully.</li>
</ul>



<p>Using a coding agent should not just be done blindly, but always with optimisation techniques in mind. Try out different aspects to optimise your coding agent. The good thing is that you can also ask the agent to optimise itself. Make it a habit to regularly update your project for your agent if needed. Agent experience is the new dev experience!</p>
<p>The post <a href="https://ronnieschaniel.com/ai/agent-experience-optimisation-in-large-code-bases-skill-vs-prompt-only/">Agent Experience Optimisation in Large Code Bases &#8211; Skill vs. Prompt only</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A Debug Skill for Your Coding Agent</title>
		<link>https://ronnieschaniel.com/ai/a-debug-skill-for-your-coding-agent/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 08 Mar 2026 12:10:05 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2860</guid>

					<description><![CDATA[<p>Bugs still happen and having AI support to solve them is helpful.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/a-debug-skill-for-your-coding-agent/">A Debug Skill for Your Coding Agent</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="571" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_debug_skill-1024x571.png" alt="" class="wp-image-2862" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_debug_skill-1024x571.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_debug_skill-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_debug_skill-768x428.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/agent_debug_skill.png 1377w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Generated by Gemini.</figcaption></figure>



<p>Even in the age of AI coding bugs inevitably happen. Some say AI is causing more bugs than we had before. Anyway, also for debugging we can receive some help from AI. That is why I created an Agent Skill for debugging.</p>



<h2 class="wp-block-heading">The Debug Agent Skill</h2>



<p>Our debug skill should take a stack trace or error description as input. Based on that and the project at hand, it should form hypotheses and create tests to reproduce the issue in the code. <a href="https://code.visualstudio.com/docs/copilot/customization/agent-skills" target="_blank" rel="noreferrer noopener">Skills</a> are an independent, shareable and modular way to customise coding assistants. They are meant for repeatable tasks and they are not only instructions but can also involve more context and scripts.</p>



<p>Today we create a skill in a full stack project that consists of a Java Spring Boot backend and a Angular frontend. The two are connected through an API. We create a debug folder in our skills folder and also place the skill file in there:</p>



<p><code>skills/debug/SKILL.md</code></p>



<p>How does the skill file look like?</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">---
name: debug
description: Analyze pasted stack traces from any environment, form 2-3 concrete hypotheses, visualize likely failure paths, and reproduce the bug with a failing test before fixing code.
---

# Skill: Debug from Stack Trace

## Purpose

Use this skill when a user pastes a stack trace, error log, or production failure excerpt and wants help debugging the issue in this repository.

This skill is optimized for cases where:

- the failure happened in another environment
- only logs or stack traces are available
- the root cause is uncertain
- the bug should be reproduced with a test before changing code

## Core workflow

Follow this sequence strictly:

**Hard stop rule:** if there is no clear stack trace, no concrete error, or the failure mode is still ambiguous, the very first response must stay in diagnosis mode. That means: summarize what is known, state what is unknown, present 2-3 ranked hypotheses, and ask how to continue or what additional evidence is available. Do not edit code, do not write tests, and do not propose a fix until the uncertainty has been reduced enough to justify a reproduction path.

1. **Parse the stack trace**
   - Extract the exception type, message, top application frames, and repeated patterns.
   - Distinguish framework noise from application frames.
   - Identify the most relevant user-code entry points first.
   - If there is no stack trace, then do not guess blindly. Instead, state what is known vs unknown and what minimal additional evidence would reduce uncertainty.
   - If there is a vague symptom but no clear failure signal, do the same: remain in diagnosis mode first.
   - Build some hypotheses as described in step 2 (without the stack trace evidence if needed), clearly label them as speculative, and ask how to continue before doing anything else.
   - You also do not need to run tests if there is no clear evidence that the bug is in the application code. In that case, give bounded debugging guidance or ask for more information.

2. **Build 2-3 hypotheses**
   - Produce 2 or 3 plausible causes only.
   - This step is mandatory before any implementation work whenever the issue is not already clear from evidence.
   - For each hypothesis include:
     - why it matches the trace
     - which files/classes likely participate
     - what evidence would confirm or disprove it
   - Rank them from most likely to least likely.

3. **Show a diagram**
   - Render a Mermaid flowchart of the likely failing path.
   - The diagram should show:
     - triggering API/use case entry point
     - intermediate collaborators
     - the suspected failing branch or null/missing state
     - the thrown exception
  - The file needs to be created in the root of the project such that I can view it.

4. **Choose the smallest reproduction test**
   - Prefer the narrowest test that can reproduce the bug reliably.
   - In this project, use:
     - **JUnit 5 + Mockito** for application/use-case bugs
     - **`@WebMvcTest`** for controller/API behavior bugs
     - **integration-style test only when necessary** for cross-layer behavior that cannot be reproduced in isolation
   - Avoid `@SpringBootTest` unless there is no smaller realistic reproduction.

5. **Write the test first**
   - Add or update a test that reproduces the suspected issue.
   - The test must fail first.
   - State clearly why that failing test reproduces the bug.

6. **Only then fix the code**
   - After the failure is confirmed, implement the smallest safe fix.
   - Preserve architecture boundaries:
     - `api` → `application` → `domain` ← `infrastructure`
   - Do not introduce framework code into domain classes.

7. **Verify after the fix**
   - Re-run the reproduction test.
   - Re-run related tests if needed.
   - Summarize root cause, fix, and why the test now passes.

## Output format

When using this skill, structure the response like this:

If the issue is unclear or there is no clear stack trace, stop after sections 1 and 2 first, then ask for confirmation or more evidence before moving on.

### 1. Observations
- exception type
- important message
- most relevant application frames

### 2. Hypotheses
- Hypothesis 1
- Hypothesis 2
- Hypothesis 3 (optional)

### 3. Failure diagram
- Mermaid flowchart showing the likely failing path

### 4. Reproduction plan
- whether to use a unit, MVC, or integration test
- what exact scenario should fail first

### 5. Fix plan
- smallest likely code change after the test fails

## Hypothesis guidelines

Good hypotheses are:

- specific
- tied to concrete classes or methods
- falsifiable
- based on evidence from the trace

Avoid vague guesses like:

- "something is null somewhere"
- "configuration issue maybe"

Prefer concrete statements like:

- "`GetRaceUseCase.execute()` likely dereferences a missing repository result because the trace ends at `Optional.get()` and the API path is `GET /races/{id}`."

## Diagram template

Use a Mermaid flowchart similar to this:

```mermaid
flowchart TD
    A[HTTP request enters controller] --&gt; B[Controller calls use case]
    B --&gt; C[Use case queries repository]
    C --&gt; D{Expected entity present?}
    D -- No --&gt; E[Missing state / null / empty Optional]
    E --&gt; F[Exception thrown]
    D -- Yes --&gt; G[Normal response]
```

Adjust node labels to the concrete stack trace and code path.

## Test selection guidelines

### Use a unit test when

- the failure is inside a use case
- collaborators can be mocked
- the bug is a null, missing `Optional`, mapping error, or branch error

### Use a controller test when

- the failure depends on HTTP request handling
- status codes, JSON bodies, path variables, or request binding matter

### Use an integration test when

- multiple layers must collaborate to trigger the bug
- persistence or serialization is essential to reproduce it

## Project-specific rules

For this repository:

- application tests should use **JUnit 5 + Mockito**
- controller tests should use **`@WebMvcTest`**
- avoid `@SpringBootTest` for ordinary debugging work
- use domain repository interfaces as mocks, not JPA repositories
- keep use cases single-purpose with one public `execute(...)` method

## If the stack trace is incomplete

If the user provides only a partial trace, still proceed:

- identify the best visible application frame
- state what is known vs unknown
- give 2-3 bounded hypotheses
- suggest the minimal additional evidence that would reduce uncertainty

## Recommended default behavior

For this project, prefer the following order:

1. analyze pasted stack trace or available evidence
2. if the issue is unclear, stop and produce 2-3 hypotheses first
3. only after the failure path is credible, show Mermaid diagram
4. write failing reproduction test
5. fix code
6. verify the test passes

Do not skip the failing-test step unless the user explicitly asks to.
Do not skip the hypotheses-first step when the evidence is weak or ambiguous.</code></pre>



<p>Let us see next, how we can use that skill.</p>



<h2 class="wp-block-heading">Applying the Debug Skill on Different Problems</h2>



<h3 class="wp-block-heading">Easy Bug with Stack Trace</h3>



<p>I&#8217;ve added a &#8220;java.util.NoSuchElementException: No value present&#8221; issue deliberately into our code. And triggered that issue. The resulting stack trace contains the following</p>



<pre class="wp-block-code"><code lang="java" class="language-java">There was an unexpected error (type=Internal Server Error, status=500).
No value present
java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:143)
	at com.ultratrail.application.GetRaceUseCase.execute(GetRaceUseCase.java:16)
	at com.ultratrail.api.RaceController.getRace(RaceController.java:46)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:565)</code></pre>



<p>We can now chat to Copilot and we see below that a skill was read and that skill is the debug one:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="1024" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated-1024x1024.png" alt="" class="wp-image-2867" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated-1024x1024.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated-300x300.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated-150x150.png 150w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated-768x768.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_activated.png 1280w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>It generated a diagram that describes the issue. I believe this is important to review the issue easily. The diagram explains it in a way such that it only takes a few seconds. That helps to keep the understanding of the system alive and spot additional issues that could appear:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="769" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-1024x769.png" alt="" class="wp-image-2868" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-1024x769.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-300x225.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-768x577.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-1536x1154.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_diagram_explanation-2048x1538.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Then it continued by creating a test to reproduce the issue. This helps that the issue does not reappear in the future. It also fixed the issue because it is an easy fix:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="142" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_issue_fixed-1024x142.png" alt="" class="wp-image-2870" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_issue_fixed-1024x142.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_issue_fixed-300x42.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_issue_fixed-768x107.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_issue_fixed.png 1382w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Finally the view in our chat shows that the test was failing first. Then the fix (shown above) was applied and the rerun of the test also proved that the problem is fixed:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="383" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_testing_and_retesting-1024x383.png" alt="" class="wp-image-2869" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_testing_and_retesting-1024x383.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_testing_and_retesting-300x112.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_testing_and_retesting-768x287.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_testing_and_retesting.png 1074w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>This ensures that we don&#8217;t have follow up issues and that the issue was reproduced and (most likely) correctly fixed. If we now would visit http://localhost:8080/api/races/12312 the result is &#8220;Race not found with id: 12312&#8221;.</p>



<h3 class="wp-block-heading">Harder Issues where we Need Hypotheses</h3>



<p>Now we try something harder that does not even have a stack trace:</p>



<p><code>Sometimes I have an issue on Production and the database is not responding with the results I would expect. Please help me. It's in the area of races. Sometimes it looks like there is just no connection to the DB.</code></p>



<p>How will CoPilot handle that?</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="734" src="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses-1024x734.png" alt="" class="wp-image-2873" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses-1024x734.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses-300x215.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses-768x550.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses-1536x1100.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/03/debug_skill_hypotheses.png 1826w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We see that it helped telling in the <code>SKILL.md</code> that there should be no guesses. Thanks to those hypotheses listed we can deliver more evidence first before aimlessly trying to solve an unclear issue.</p>



<h2 class="wp-block-heading">Consequences of Having a Debug Skill</h2>



<p>For me mainly two aspects were important:</p>



<ol class="wp-block-list numeric-list">
<li>There&#8217;s a well defined debug procedure that allows to use AI.</li>



<li>But on the other hand, AI debugging should be kept inside some boundaries.</li>
</ol>



<p>We all know that LLMs and coding agents try to always find a solution. I have seen coding agents iterating forever to find an issue. With above solution I wanted to prevent this endless loop of stupidly trying to solve and issue that might not even be in the context of the application. That is why the stopping condition is very important. The hypotheses and the collection of more evidence help to pinpoint the issue. </p>



<p>Developers will use AI to debug. That is guaranteed. I still believe that there should be a general understanding of issues. This helps to steer the agent better for further changes. That is why I also wanted a diagram as output. The diagram should explain the problem such that the develop understands in a few seconds what was happening.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/a-debug-skill-for-your-coding-agent/">A Debug Skill for Your Coding Agent</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Agent Skills for Hexagonal Architecture in Spring Boot</title>
		<link>https://ronnieschaniel.com/ai/agent-skills-for-hexagonal-architecture-in-spring-boot/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 14:54:57 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2837</guid>

					<description><![CDATA[<p>Define portable, modular, on-demand AI capabilities for specific tasks.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/agent-skills-for-hexagonal-architecture-in-spring-boot/">Agent Skills for Hexagonal Architecture in Spring Boot</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/agent_skills_for_hexagonal_architecture-1024x572.png" alt="" class="wp-image-2838" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/agent_skills_for_hexagonal_architecture-1024x572.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/agent_skills_for_hexagonal_architecture-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/agent_skills_for_hexagonal_architecture-768x429.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/agent_skills_for_hexagonal_architecture.png 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Image generated by Gemini</figcaption></figure>



<p>Agent skills are folders of instructions, scripts, and resources. Copilot can load the files when required to fulfil specialised tasks. <a href="https://github.com/agentskills/agentskills" target="_blank" rel="noreferrer noopener">Agentskills</a> is an open standard and therefore should be a good choice for sharing. We will try it out and see how skills can be helpful in a Java Spring Boot project based on hexagonal architecture.</p>



<h2 class="wp-block-heading">What Agent Skills do we need?</h2>



<p>Our demo application is the same that we used in <a href="https://ronnieschaniel.com/ai/hexagonal-architecture-in-spring-boot-projects-with-ai/">Hexagonal Architecture in Spring Boot Projects with AI</a>.  The theme is the one of Ultra Trail races. And the backend currently allows to manage races with their plans, segments, and accommodation. Alongside the Spring backend that offers the DB and the APIs we have a Angular frontend in the same repository.</p>



<p>In such a full-stack mono repo, I can think about the following agent skills:</p>



<ol class="wp-block-list numeric-list">
<li>Transforming the Java DTOs on the backend to TypeScript models on the frontend.</li>



<li>Generating a use case on the backend.</li>



<li>Implementation of a backend HTTP call to a third-party system based on an Open API definition.</li>



<li>Creating a e2e test based on the frontend and the backend mocks.</li>



<li>Retrieve the latest CI/CD log for failures and support in fixing.</li>



<li>Create API tests for the backend based on domain knowledge.</li>
</ol>



<p>Let us explore the first idea in more detail and create a skill for model creation out of DTOs.</p>



<h2 class="wp-block-heading">Creating the Agent Skills</h2>



<p>Because a skill can involved scripts, we will make use of that. Under the <code>.github</code> folder in our repository we create a <code>skills</code> folder and add a first skill folder <code>controller-data-to-ts-models</code>. Now inside that folder we need a SKILL.md file with a defined structure:</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
name: controller-data-to-ts-models
description: Generate TypeScript model files from data contracts exposed by Spring controllers (@RequestBody and ResponseEntity&lt;T&gt;). Use this when asked to keep frontend models aligned with API controller contracts.
---

# Skill: Controller Data → TypeScript Models

## Purpose

Generate frontend TypeScript model files from the data contracts exposed by Spring controllers:

- request payload types from `@RequestBody`
- response payload types from `ResponseEntity&lt;T&gt;`

This keeps Angular models aligned with API contracts instead of generating from every domain class.

## Scope

The generator scans:

- `src/main/java/com/ultratrail/api/*Controller.java`

It resolves and emits models for referenced classes from:

- `src/main/java/com/ultratrail/application/*Command.java`
- `src/main/java/com/ultratrail/domain/*.java`

## Output

Generated files are written to:

- `frontend/src/app/models/*.model.ts`

If a model file already exists with the same name, it is overwritten.

## Run

From project root:

```bash
node .github/skills/controller-data-to-ts-models/generate-controller-ts-models.mjs
```

Or from any directory inside the repository:

```bash
node /absolute/path/to/repo/.github/skills/controller-data-to-ts-models/generate-controller-ts-models.mjs
```

## Mapping rules

- `String`, `LocalDate`, `LocalDateTime`, `Instant`, `UUID` → `string`
- `Integer`, `Long`, `Double`, `Float`, `BigDecimal` → `number`
- `Boolean` → `boolean`
- `List&lt;T&gt;`, `Set&lt;T&gt;`, `Collection&lt;T&gt;` → `T[]`
- Java nested enums (e.g., `Race.RaceStatus`) are emitted as TS union types.
- Field `id` is generated as optional (`id?: ...`).

## Notes

- The generator is intentionally contract-focused and does not modify existing handcrafted models.
- If you change controller request/response types, rerun the generator to refresh the generated files.</code></pre>



<p>And alongside the standard file follows our script <code>generate-controller-ts-models.mjs</code>. Here just some extracts of it such that you get the basic understanding:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">...

function listControllerFiles() {
  if (!fs.existsSync(apiDir)) return [];
  return fs
    .readdirSync(apiDir)
    .filter((file) =&gt; file.endsWith('Controller.java'))
    .map((file) =&gt; path.join(apiDir, file));
}

... 

function parseFields(content) {
  const fields = [];
  const fieldRegex = /private\s+([A-Za-z0-9_$.&lt;&gt;]+)\s+([A-Za-z0-9_]+)\s*;/g;
  let match;
  while ((match = fieldRegex.exec(content)) !== null) {
    fields.push({
      javaType: sanitizeType(match[1]),
      name: match[2],
    });
  }
  return fields;
}</code></pre>



<p>This is the skill. And now we need to see how we can use it.</p>



<h2 class="wp-block-heading">Make CoPilot use the new Agent Skill</h2>



<p>First of all you need to make sure that CoPilot skills are enabled in your IDE. I&#8217;m taking vscode as an example and you can search for &#8220;skills&#8221; in the settings and tick the checkbox:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="770" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings-1024x770.png" alt="Screenshot showing where to enable agent skills in VC code." class="wp-image-2841" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings-1024x770.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings-300x225.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings-768x577.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings-1536x1154.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skills_settings.png 1578w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Then we are ready to go. Let us have a look at the AccommodationController.java where we find various endpoints using DTOs:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@GetMapping
public ResponseEntity&lt;List&lt;Accommodation&gt;&gt; getAccommodations(@PathVariable String raceId) {
    return ResponseEntity.ok(getAccommodationsByRaceUseCase.execute(raceId));
}</code></pre>



<p>In this case here, the DTO would be <code>Accommodation</code> and it looks as follows:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Accommodation {
    private String id;
    private String raceId;
    private String name;
    private String location;
    private AccommodationType type;
    private LocalDate checkIn;
    private LocalDate checkOut;
    private Boolean breakfastIncluded;
    private BigDecimal pricePerNight;
    private BigDecimal distanceToStartKm;
    private BigDecimal distanceToFinishKm;
    private RoomType roomType;
    private Integer numberOfGuests;

    public enum AccommodationType {
        RACE_START, RACE_FINISH, FULL_STAY
    }

    public enum RoomType {
        SINGLE, DOUBLE
    }
}</code></pre>



<p>Now over to Copilot:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="502" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_found-1024x502.png" alt="" class="wp-image-2842" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_found-1024x502.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_found-300x147.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_found-768x377.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_found.png 1130w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>I click &#8220;Allow&#8221; and the script&#8217;s skill starts to do its work and reports back after only a few seconds. In my case it updated all the models which is okay:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="233" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_done-1024x233.png" alt="" class="wp-image-2843" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_done-1024x233.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_done-300x68.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_done-768x174.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/vscode_agent_skill_done.png 1118w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>This gives us the following model in the frontend for the Accommodation interface:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export interface Accommodation {
  id?: string;
  raceId: string;
  name: string;
  location: string;
  type: AccommodationType;
  checkIn: string;
  checkOut: string;
  breakfastIncluded: boolean;
  pricePerNight: number;
  distanceToStartKm: number;
  distanceToFinishKm: number;
  roomType: RoomType;
  numberOfGuests: number;
}

export type AccommodationType = 'RACE_START' | 'RACE_FINISH' | 'FULL_STAY';
export type RoomType = 'SINGLE' | 'DOUBLE';</code></pre>



<p>We see that the types were mapped correctly.</p>



<h2 class="wp-block-heading">What are the Differences to Instructions, Prompts and Custom Agents?</h2>



<p>Agent Skills are modular, on-demand, and portable AI capabilities containing specific instructions and tools, whereas custom instructions are persistent, general-purpose directives that apply to every interaction. In my experience agent skills are a great combination of well defined scripts and the power of an LLM. You have the determinism of a script that gives you more safety. Other than that, it&#8217;s also cheaper to execute the scripts than to really on AI to do the transformation. Prompts are on-demand commands executed by typing, e.g. <code>/review</code>, for a review prompt. They are made for repeatable one-shot functionalities.</p>



<p>If we would like to compare all of it, the following table can help:</p>



<figure class="wp-block-table mt-4"><table class="has-fixed-layout"><tbody><tr><td><strong>Concept</strong></td><td><strong>Description</strong></td><td><strong>Best used for</strong></td></tr><tr><td><a href="https://docs.github.com/en/copilot/tutorials/customization-library/custom-instructions" target="_blank" rel="noreferrer noopener">Instructions</a></td><td>Always on, standards and default behaviours</td><td>Coding standards, team preferences, broad context</td></tr><tr><td><a href="https://docs.github.com/en/copilot/tutorials/customization-library/prompt-files" target="_blank" rel="noreferrer noopener">Prompts</a></td><td>A manual and on-demand execution of a prompt</td><td>A simple task that does not need any loop</td></tr><tr><td><a href="https://docs.github.com/en/copilot/concepts/agents/about-agent-skills" target="_blank" rel="noreferrer noopener">Skills</a></td><td>Combination of instructions, scripts and resources that are loaded when needed</td><td>Detailed instructions for a very specific task that requires more than just a simple prompt</td></tr><tr><td><a href="https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-custom-agents" target="_blank" rel="noreferrer noopener">Custom agents</a></td><td>Agents for specific development tasks that can use tools and MCP</td><td>Used if you need to tailor the coding agent to your unique workflows, coding conventions, and use cases</td></tr></tbody></table></figure>



<p>Best is if you try out the various possibilities you have. And remember that you can always let AI itself create the skills, prompts, instructions and agents.</p>



<p><sup><em>All my articles are written by myself. AI is used for some of the title images and in some cases to improve the wording and flow.</em></sup></p>
<p>The post <a href="https://ronnieschaniel.com/ai/agent-skills-for-hexagonal-architecture-in-spring-boot/">Agent Skills for Hexagonal Architecture in Spring Boot</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Hexagonal Architecture in Spring Boot Projects with AI</title>
		<link>https://ronnieschaniel.com/ai/hexagonal-architecture-in-spring-boot-projects-with-ai/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Tue, 24 Feb 2026 19:31:52 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2797</guid>

					<description><![CDATA[<p>How to give coding agents boundaries by adding ArchUnit tests and instruction files.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/hexagonal-architecture-in-spring-boot-projects-with-ai/">Hexagonal Architecture in Spring Boot Projects with AI</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_in_spring_boot_projects_with_AI-1024x572.png" alt="" class="wp-image-2799" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_in_spring_boot_projects_with_AI-1024x572.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_in_spring_boot_projects_with_AI-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_in_spring_boot_projects_with_AI-768x429.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_in_spring_boot_projects_with_AI.png 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Generated by Gemini</figcaption></figure>



<p>The advent of AI has revolutionised the way software engineers approach programming. While we can now leverage code generation in various ways, I firmly believe that structure remains essential! AI excels at recognising patterns and working consistently when given guidance. Moreover, the abstraction level has increased, allowing developers to focus more on business logic as well as overall architecture and less on implementation details. Given this, combining AI-generated code with hexagonal architecture should be an intriguing combination. In this article, we will delve into this concept in the context of a full-stack application, specifically focusing on an ultra-running theme (races longer than 42.2km or 26 miles).</p>



<h2 class="wp-block-heading">The Application and its Hexagonal Structure</h2>



<p>Our application is designed to manage races and related athlete information. The main view provides an overview of upcoming events, as depicted in the image below:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="187" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-1024x187.png" alt="" class="wp-image-2827" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-1024x187.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-300x55.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-768x140.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-1536x280.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/races_overview-2048x374.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>On the detail view of a specific race, users can edit attributes, add segments, and input other relevant details, as shown in the next screenshot:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="733" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-1024x733.png" alt="" class="wp-image-2828" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-1024x733.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-300x215.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-768x549.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-1536x1099.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view-2048x1465.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now, let&#8217;s take a more technical look at our application. At its core lies the principle of hexagonal, onion, or clean architecture, which dictates that everything revolves around the domain. In this context, infrastructural aspects such as storage and API exposure are dependent on the domain, rather than the other way around. Use cases complete the picture by describing what happens within the domain.</p>



<p>The following diagram provides a visual representation of our hexagonal structure, highlighting a single use case for the Race domain as an example:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="701" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-1024x701.png" alt="" class="wp-image-2803" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-1024x701.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-300x206.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-768x526.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-1536x1052.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/hexagonal_architecture_structure-2048x1403.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In the next section, we&#8217;ll explore how AI coding agents can be informed about the desired structure and important details, enabling seamless integration with our application.</p>



<h2 class="wp-block-heading">Defining Guardrails for AI with ArchUnit and Instruction Files</h2>



<p>To ensure our architecture remains consistent, we&#8217;ll employ <a href="https://www.archunit.org/" target="_blank" rel="noreferrer noopener">ArchUnit</a>, a Java library designed to unit test architectural structures. This approach provides guardrails that help maintain the desired structure. Additionally, we&#8217;ll create instruction files for GitHub CoPilot to specify the preferred Java code style.</p>



<h3 class="wp-block-heading">Describing the Application Architecture with ArchUnit</h3>



<p>We will write tests in five areas to ensure our architecture is well-defined:</p>



<ol class="wp-block-list">
<li><strong>Dependency Allowance</strong>: Verifying the allowed dependencies between the domain, API, infrastructure, and application layers.</li>



<li><strong>Boundary Checks:</strong> Additional checks for boundaries not covered by the initial architecture test (e.g., library usage).</li>



<li><strong>Naming Conventions:</strong> Enforcing consistent naming conventions throughout the codebase.</li>



<li><strong>Structural Rules for Classes:</strong> Validating class structure rules to maintain a cohesive architecture.</li>



<li><strong>Circular Dependency Check:</strong> Ensuring that dependencies between application parts are respected and follow the desired design without circles.</li>
</ol>



<p>Below is the most important check that ensures the dependencies rules between the different parts of the application are respected:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@ArchTest
static final ArchRule layerDependenciesAreRespected =
    layeredArchitecture()
        .consideringAllDependencies()
        .layer("Domain").definedBy("com.ultratrail.domain..")
        .layer("Application").definedBy("com.ultratrail.application..")
        .layer("API").definedBy("com.ultratrail.api..")
        .layer("Infrastructure").definedBy("com.ultratrail.infrastructure..")

        .whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "API", "Infrastructure")
        .whereLayer("Application").mayOnlyBeAccessedByLayers("API")
        .whereLayer("Infrastructure").mayNotBeAccessedByAnyLayer()
        .whereLayer("API").mayNotBeAccessedByAnyLayer();</code></pre>



<p>To begin, we define the packages for each layer: Domain, Application, API, and Infrastructure. This serves as the foundation for our architecture, allowing us to identify the distinct layers.<br>Next, we determine which layers may be accessed by others. For instance, the Domain layer should not access other layers directly, ensuring a clear separation of concerns. By defining these boundaries, we establish the guardrails that govern our application&#8217;s architecture.</p>



<p>For additional boundaries, we add another test:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@ArchTest
static final ArchRule domainMustBeFrameworkFree =
    noClasses().that().resideInAPackage("com.ultratrail.domain..")
        .should().dependOnClassesThat()
        .resideInAnyPackage(
                "org.springframework..",
                "jakarta.persistence..",
                "javax.persistence.."
        )
        .because("The domain layer must not depend on any framework.");

@ArchTest
static final ArchRule applicationMustNotUseJpa =
    noClasses().that().resideInAPackage("com.ultratrail.application..")
        .should().dependOnClassesThat()
        .resideInAnyPackage("jakarta.persistence..", "javax.persistence..")
        .because("The application layer must not use JPA directly.");

@ArchTest
static final ArchRule applicationMustNotUseSpringMvc =
    noClasses().that().resideInAPackage("com.ultratrail.application..")
        .should().dependOnClassesThat()
        .resideInAnyPackage("org.springframework.web..", "jakarta.servlet..")
        .because("The application layer must not depend on Spring MVC or Servlet API.");

@ArchTest
static final ArchRule apiMustNotUseJpa =
    noClasses().that().resideInAPackage("com.ultratrail.api..")
        .should().dependOnClassesThat()
        .resideInAnyPackage("jakarta.persistence..", "javax.persistence..")
        .because("The API layer must not use JPA directly.");</code></pre>



<p>A third test covers naming conventions, ensuring consistency and clarity in our codebase:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@ArchTest
static final ArchRule useCasesMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.application..")
        .and().areAnnotatedWith(org.springframework.stereotype.Service.class)
        .should().haveSimpleNameEndingWith("UseCase")
        .because("All @Service classes in the application layer must be named *UseCase.");

@ArchTest
static final ArchRule commandsMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.application..")
        .and().areNotAnnotatedWith(org.springframework.stereotype.Service.class)
        .and().areNotAssignableTo(RuntimeException.class)
        .and().areNotInterfaces()
        .should().haveSimpleNameEndingWith("Command")
        .because("Non-use-case, non-exception classes in the application layer must be named *Command.");

@ArchTest
static final ArchRule exceptionsMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.application..")
        .and().areAssignableTo(RuntimeException.class)
        .should().haveSimpleNameEndingWith("NotFoundException")
        .because("Domain exceptions in the application layer must be named *NotFoundException.");

@ArchTest
static final ArchRule controllersMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.api..")
        .and().areAnnotatedWith(org.springframework.web.bind.annotation.RestController.class)
        .should().haveSimpleNameEndingWith("Controller")
        .because("All REST controllers must be named *Controller.");

@ArchTest
static final ArchRule repositoryAdaptersMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.infrastructure..")
        .and().areAnnotatedWith(org.springframework.stereotype.Component.class)
        .and().areNotInterfaces()
        .should().haveSimpleNameEndingWith("RepositoryAdapter")
        .because("Infrastructure adapters must be named *RepositoryAdapter.");

@ArchTest
static final ArchRule jpaEntitiesMustBeNamedCorrectly =
    classes().that().resideInAPackage("com.ultratrail.infrastructure..")
        .and().areAnnotatedWith(jakarta.persistence.Entity.class)
        .should().haveSimpleNameEndingWith("Entity")
        .because("JPA entity classes must be named *Entity.");</code></pre>



<p>Additionally, more structural rules are defined below to further refine our architectural design.</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@ArchTest
static final ArchRule useCaseFieldsMustBeFinal =
    classes().that().resideInAPackage("com.ultratrail.application..")
        .and().haveSimpleNameEndingWith("UseCase")
        .should().haveOnlyFinalFields()
        .because("Use case classes must have only final (injected) fields — no mutable state.");

@ArchTest
static final ArchRule noFieldInjectionAnywhere =
    noFields().that().areDeclaredInClassesThat()
        .resideInAnyPackage(
                "com.ultratrail.domain..",
                "com.ultratrail.application..",
                "com.ultratrail.api..",
                "com.ultratrail.infrastructure.."
        )
        .should().beAnnotatedWith(org.springframework.beans.factory.annotation.Autowired.class)
        .because("Field injection with @Autowired is forbidden. Use constructor injection.");

@ArchTest
static final ArchRule controllersMustNotDependOnRepositories =
    noClasses().that().resideInAPackage("com.ultratrail.api..")
        .and().areAnnotatedWith(org.springframework.web.bind.annotation.RestController.class)
        .should().dependOnClassesThat()
        .haveSimpleNameEndingWith("Repository")
        .because("Controllers must not directly depend on repository interfaces — inject use cases instead.");</code></pre>



<p>And finally, we ensure that no circular dependencies occur, guaranteeing the stability and maintainability of our architecture.</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@ArchTest
static final ArchRule noCircularDependenciesBetweenLayers =
    slices().matching("com.ultratrail.(*)..").should().beFreeOfCycles()
        .because("There must be no circular dependencies between architecture layers.");</code></pre>



<p>With these ArchUnit tests in place, our AI coding agents are provided with clear boundaries to operate within. Now, let&#8217;s explore further steering possibilities through instruction files.</p>



<h3 class="wp-block-heading">Creating Instruction Files to Guide GitHub CoPilot</h3>



<p><a href="https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions" target="_blank" rel="noreferrer noopener">Instruction files</a> play a crucial role in providing context and guidance for your AI coding agents. By placing these files in the&nbsp;<code>.github/instructions</code>&nbsp;directory, you can help your agent understand how to build, test, and validate changes.</p>



<p>Let&#8217;s begin by creating instructions for the core of our hexagonal architecture – the Domain. This will be defined in a&nbsp;<code>domain.instructions.md</code>&nbsp;file:</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
applyTo: "src/main/java/com/ultratrail/domain/**"
---

# Domain Layer Rules

You are generating code in the **domain layer** (`com.ultratrail.domain`).
This layer is the core of the hexagonal architecture and must remain 100 % framework-free.

## Strict Rules

### Allowed imports
- `java.*`
- `lombok.*`
- Other `com.ultratrail.domain.*` classes

### Forbidden imports – NEVER add these
- `org.springframework.*`
- `jakarta.persistence.*` / `javax.persistence.*`
- `com.ultratrail.application.*`
- `com.ultratrail.api.*`
- `com.ultratrail.infrastructure.*`

### Domain Entities
- Annotate every entity with `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor` (Lombok).
- All IDs are `String` (UUID format).
- Do **not** add `@Entity`, `@Table`, `@Column`, or any JPA annotation.
- Embed domain-specific enums as static nested enums inside the owning entity.
- Do not add Spring bean annotations (`@Service`, `@Component`, `@Repository`).
- No business logic methods that depend on external services.

### Repository Interfaces (Ports)
- Repository interfaces are pure Java interfaces — they define the port, not the implementation.
- Name them `&lt;Entity&gt;Repository` (e.g., `RaceRepository`).
- Only use domain types as parameter and return types.
- Common methods: `save`, `findById`, `findAll`, `delete`. Add domain-specific finders as needed.

## Example

```java
package com.ultratrail.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Race {
    private String id;
    private String name;

    public enum RaceStatus { PLANNED, REGISTERED, COMPLETED, DNF, DNS }
}
```

```java
package com.ultratrail.domain;

import java.util.List;
import java.util.Optional;

public interface RaceRepository {
    Race save(Race race);
    Optional&lt;Race&gt; findById(String id);
    List&lt;Race&gt; findAll();
    void delete(String id);
}
```</code></pre>



<p>The Application part is described in&nbsp;<code>application.instructions.md</code>:</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
applyTo: "src/main/java/com/ultratrail/application/**"
---

# Application Layer Rules

You are generating code in the **application layer** (`com.ultratrail.application`).
This layer orchestrates use cases and acts as the bridge between the API and the domain.

## Strict Rules

### Allowed imports
- `com.ultratrail.domain.*`
- `org.springframework.stereotype.Service` (use cases only)
- `lombok.*`
- `java.*`

### Forbidden imports – NEVER add these
- `com.ultratrail.api.*`
- `com.ultratrail.infrastructure.*`
- `jakarta.persistence.*` / `javax.persistence.*`
- `org.springframework.web.*`
- `jakarta.servlet.*`
- Any Spring MVC annotation (`@RestController`, `@RequestMapping`, etc.)

---

## Use Cases

- Each use case is a **single class with one public method** named `execute(...)`.
- Annotate with `@Service` and `@AllArgsConstructor` — no other Spring annotations.
- Use constructor injection only. Never use `@Autowired` on fields.
- Inject domain repository interfaces (ports), never JPA repositories.
- Generate new IDs with `UUID.randomUUID().toString()`.
- Naming: `&lt;Verb&gt;&lt;Entity&gt;UseCase` (e.g., `CreateRaceUseCase`, `UpdateRaceStatusUseCase`).

```java
@Service
@AllArgsConstructor
public class CreateRaceUseCase {
    private final RaceRepository raceRepository;

    public Race execute(CreateRaceCommand command) {
        Race race = Race.builder()
                .id(UUID.randomUUID().toString())
                .name(command.getName())
                // ... map remaining fields
                .build();
        return raceRepository.save(race);
    }
}
```

---

## Commands

- Commands are plain data holders with **no business logic**.
- Annotate with `@Data`, `@NoArgsConstructor`, `@AllArgsConstructor` (Lombok).
- No validation annotations unless explicitly requested.
- Naming: `&lt;Verb&gt;&lt;Entity&gt;Command` (e.g., `CreateRaceCommand`, `AddSegmentCommand`).

```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CreateRaceCommand {
    private String name;
    private String location;
}
```

---

## Domain Exceptions

- Extend `RuntimeException`.
- Belong in this package (not in domain).
- Naming: `&lt;Entity&gt;NotFoundException` (e.g., `RaceNotFoundException`, `RacePlanNotFoundException`).

```java
public class RaceNotFoundException extends RuntimeException {
    public RaceNotFoundException(String id) {
        super("Race not found with id: " + id);
    }
}
```</code></pre>



<p>Yet another important aspect is defined in&nbsp;<code>infrastructure.instructions.md</code>.</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
applyTo: "src/main/java/com/ultratrail/infrastructure/**"
---

# Infrastructure Layer Rules

You are generating code in the **infrastructure layer** (`com.ultratrail.infrastructure`).
This layer is the outbound adapter: it implements domain ports using Spring Data JPA.

## Strict Rules

### Allowed imports
- `com.ultratrail.domain.*` (to implement repository ports)
- `org.springframework.data.jpa.repository.*`
- `org.springframework.stereotype.Component`
- `jakarta.persistence.*`
- `lombok.*`
- `java.*`

### Forbidden imports – NEVER add these
- `com.ultratrail.api.*`
- `com.ultratrail.application.*`
- `org.springframework.stereotype.Service`
- `org.springframework.web.*`

---

## Repository Adapters

- Annotate with `@Component` and `@AllArgsConstructor`.
- Each adapter **implements exactly one domain repository interface**.
- Delegate every method to a Spring Data JPA repository.
- Convert between domain objects and JPA entities using `fromDomain()` and `toDomain()`.
- JPA entities must **never** appear in method signatures exposed to other layers.
- Naming: `&lt;Entity&gt;RepositoryAdapter` (e.g., `RaceRepositoryAdapter`).

```java
@Component
@AllArgsConstructor
public class RaceRepositoryAdapter implements RaceRepository {
    private final JpaRaceRepository jpaRaceRepository;

    @Override
    public Race save(Race race) {
        return jpaRaceRepository.save(RaceEntity.fromDomain(race)).toDomain();
    }

    @Override
    public Optional&lt;Race&gt; findById(String id) {
        return jpaRaceRepository.findById(id).map(RaceEntity::toDomain);
    }

    @Override
    public List&lt;Race&gt; findAll() {
        return jpaRaceRepository.findAll().stream()
                .map(RaceEntity::toDomain)
                .collect(Collectors.toList());
    }

    @Override
    public void delete(String id) {
        jpaRaceRepository.deleteById(id);
    }
}
```

---

## Spring Data JPA Repositories

- Interface extending `JpaRepository&lt;Entity, String&gt;`.
- Naming: `Jpa&lt;Entity&gt;Repository` (e.g., `JpaRaceRepository`).
- Only add custom query methods as needed.

```java
public interface JpaRaceRepository extends JpaRepository&lt;RaceEntity, String&gt; {
    List&lt;RaceEntity&gt; findByStatus(Race.RaceStatus status);
}
```

---

## JPA Entities

- Annotate with `@Entity`, `@Table`, `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor`.
- Must include `fromDomain(Domain d)` static factory method and `toDomain()` instance method.
- JPA entities stay confined to this package — never returned from use cases or controllers.
- Naming: `&lt;Entity&gt;Entity` (e.g., `RaceEntity`).

```java
@Entity
@Table(name = "races")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RaceEntity {
    @Id
    private String id;

    @Column(nullable = false)
    private String name;

    public static RaceEntity fromDomain(Race race) {
        return RaceEntity.builder()
                .id(race.getId())
                .name(race.getName())
                .build();
    }

    public Race toDomain() {
        return Race.builder()
                .id(this.id)
                .name(this.name)
                .build();
    }
}
```</code></pre>



<p>The API exposes our functionality as RESTful HTTP endpoints, described in&nbsp;<code>api.instructions.md</code>.</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
applyTo: "src/main/java/com/ultratrail/api/**"
---

# API Layer Rules

You are generating code in the **API layer** (`com.ultratrail.api`).
This layer is the inbound adapter: it receives HTTP requests and delegates work to use cases.

## Strict Rules

### Allowed imports
- `com.ultratrail.application.*` (use cases and commands)
- `com.ultratrail.domain.*` (domain entities used only as response types)
- `org.springframework.web.*`
- `org.springframework.http.*`
- `lombok.AllArgsConstructor`
- `java.*`

### Forbidden imports – NEVER add these
- `com.ultratrail.infrastructure.*`
- `jakarta.persistence.*` / `javax.persistence.*`
- Any JPA repository interface
- `org.springframework.stereotype.Service`

---

## Controllers

- Annotate with `@RestController`, `@RequestMapping`, `@AllArgsConstructor`.
- Inject **only use cases** — never repositories, domain services, or infrastructure classes.
- Every HTTP method calls exactly one use case via `.execute(...)`.
- Return `ResponseEntity&lt;T&gt;` for every handler method.
- No business logic inside controllers. Mapping between HTTP and domain happens only by passing commands.
- Use `@PathVariable`, `@RequestBody`, `@RequestParam` for input binding.
- Naming: `&lt;Entity&gt;Controller` (e.g., `RaceController`, `RaceSegmentController`).

```java
@RestController
@RequestMapping("/races")
@AllArgsConstructor
public class RaceController {
    private final CreateRaceUseCase createRaceUseCase;
    private final GetRaceUseCase getRaceUseCase;
    private final DeleteRaceUseCase deleteRaceUseCase;

    @PostMapping
    public ResponseEntity&lt;Race&gt; createRace(@RequestBody CreateRaceCommand command) {
        return ResponseEntity.status(HttpStatus.CREATED).body(createRaceUseCase.execute(command));
    }

    @GetMapping("/{id}")
    public ResponseEntity&lt;Race&gt; getRace(@PathVariable String id) {
        return getRaceUseCase.execute(id)
                .map(ResponseEntity::ok)
                .orElseGet(() -&gt; ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public ResponseEntity&lt;Void&gt; deleteRace(@PathVariable String id) {
        deleteRaceUseCase.execute(id);
        return ResponseEntity.noContent().build();
    }
}
```

---

## Controller Tests

Use `@WebMvcTest` with mocked use cases. Never load the full application context for controller tests.

```java
@WebMvcTest(RaceController.class)
class RaceControllerTest {
    @Autowired MockMvc mockMvc;
    @MockBean CreateRaceUseCase createRaceUseCase;
    // ...
}
```</code></pre>



<p>Besides all the application layers, we also define a testing aspect, which is described in&nbsp;<code>testing.instructions.md</code>.</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
applyTo: "src/test/java/com/ultratrail/**"
---

# Testing Rules

You are generating test code for the Ultra Trail Manager project.
Follow these rules to ensure tests are focused, fast, and do not violate the hexagonal architecture.

---

## Use Case Tests (Application Layer)

- Use **plain JUnit 5 + Mockito** — no Spring context.
- Annotate with `@ExtendWith(MockitoExtension.class)`.
- Mock domain repository interfaces with `@Mock`. Never mock JPA repositories.
- Instantiate use cases manually via constructor.
- Naming: `&lt;UseCaseClass&gt;Test` (e.g., `CreateRaceUseCaseTest`).

```java
@ExtendWith(MockitoExtension.class)
class CreateRaceUseCaseTest {

    @Mock
    private RaceRepository raceRepository;

    private CreateRaceUseCase useCase;

    @BeforeEach
    void setUp() {
        useCase = new CreateRaceUseCase(raceRepository);
    }

    @Test
    void shouldCreateRaceWithPlannedStatus() {
        CreateRaceCommand command = new CreateRaceCommand("UTMB", "Chamonix");
        when(raceRepository.save(any(Race.class))).thenAnswer(inv -&gt; inv.getArgument(0));

        Race result = useCase.execute(command);

        assertNotNull(result.getId());
        assertEquals(Race.RaceStatus.PLANNED, result.getStatus());
        verify(raceRepository).save(any(Race.class));
    }
}
```

---

## Controller Tests (API Layer)

- Use `@WebMvcTest(&lt;Controller&gt;.class)` — loads only the web layer.
- Mock all use cases with `@MockBean`.
- Inject `MockMvc` with `@Autowired`.
- Do **not** use `@SpringBootTest` for controller tests.

```java
@WebMvcTest(RaceController.class)
class RaceControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private CreateRaceUseCase createRaceUseCase;

    @Test
    void shouldReturnCreatedStatusOnPost() throws Exception {
        when(createRaceUseCase.execute(any())).thenReturn(Race.builder().id("1").build());

        mockMvc.perform(post("/races")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\":\"UTMB\"}"))
                .andExpect(status().isCreated());
    }
}
```

---

## Architecture Tests

- Use ArchUnit in `HexagonalArchitectureTest` to enforce all layer boundaries.
- These tests live in `src/test/java/com/ultratrail/architecture/`.
- Do **not** use `@SpringBootTest` here.
- Run as standard JUnit 5 tests (`@AnalyzeClasses` + `@ArchTest`).

---

## General Rules

- Do **not** use `@SpringBootTest` for unit tests. It loads the full application context and is too heavy.
- Test class must be in the same package as the class under test.
- One test class per production class.
- Test method names use `should&lt;Behaviour&gt;When&lt;Condition&gt;` format.</code></pre>



<p>These files provide the necessary structure for our project, offering clear guidelines for our AI coding agents to work within.</p>



<h2 class="wp-block-heading">Extending the Application</h2>



<p>Now that we have our foundation in place, let&#8217;s put our ArchUnit tests and instruction files to the test. We&#8217;ve already established a solid structure with races, segments, and plans for each race. As we continue to grow our application, we&#8217;ll explore more features.</p>



<p>For instance, ultra races often take place far from home, spanning multiple days if the distance is significant, such as 100 miles or 160km. Planning accommodations as an athlete is crucial in these situations. Sometimes, the start and finish of a race can even be located in different areas.</p>



<p>To extend our application, I&#8217;ll send this prompt:</p>



<pre class="wp-block-code"><code class="">Extend the application by another feature. The feature is about accommodation. Each race needs accommodation possibilities that one can maintain in a CRUD manner. There could be a single accommodation for the duration of the race, and the days, before and after. But there could also be the case where an accommodation is taken before the race at the race start, and another one at the race finish location. Breakfast is an important option that should be made visible if available. Other than that the price and the distance to start or distance to the finish line are crucial. Another aspects is the number of guests. Sometimes you would like to travel with someone and need a double room. Sometimes a single room is enough and also cheaper.</code></pre>



<p>How does CoPilot work? After submitting the prompt, CoPilot springs into action, analyzing the request and generating a list of potential next steps. In this case, it identifies six TODOs that can be explored further.</p>



<p>The AI agent then uses its existing knowledge to study these patterns and find ways to integrate them seamlessly:</p>



<figure class="wp-block-image size-large mt-4"><img decoding="async" width="1024" height="492" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/copilot_at_work_to_add_accommodations-1024x492.png" alt="" class="wp-image-2821" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/copilot_at_work_to_add_accommodations-1024x492.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/copilot_at_work_to_add_accommodations-300x144.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/copilot_at_work_to_add_accommodations-768x369.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/copilot_at_work_to_add_accommodations.png 1494w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>CoPilot summarizes the changes by providing a report of all the passed tests, including the Hexagonal Architecture Test. This ensures that our codebase continues to adhere to the architecture we&#8217;ve established, ensuring stability and maintainability in the long run.</p>



<figure class="wp-block-image size-full mt-4"><img decoding="async" width="988" height="764" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/after_adding_the_feature.png" alt="" class="wp-image-2819" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/after_adding_the_feature.png 988w, https://ronnieschaniel.com/wp-content/uploads/2026/02/after_adding_the_feature-300x232.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/after_adding_the_feature-768x594.png 768w" sizes="(max-width: 988px) 100vw, 988px" /></figure>



<p>Finally, we can visually inspect our application to ensure everything is working as intended. For instance, let&#8217;s take a closer look at the Domain class:</p>



<pre class="wp-block-code"><code lang="java" class="language-java">@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Accommodation {
    private String id;
    private String raceId;
    private String name;
    private String location;
    private AccommodationType type;
    private LocalDate checkIn;
    private LocalDate checkOut;
    private Boolean breakfastIncluded;
    private BigDecimal pricePerNight;
    private BigDecimal distanceToStartKm;
    private BigDecimal distanceToFinishKm;
    private RoomType roomType;
    private Integer numberOfGuests;

    public enum AccommodationType {
        RACE_START, RACE_FINISH, FULL_STAY
    }

    public enum RoomType {
        SINGLE, DOUBLE
    }
}</code></pre>



<p>I like the categorisation in&nbsp;<code>RACE_START</code>,&nbsp;<code>RACE_FINISH</code>, and&nbsp;<code>FULL_STAY</code>. Additionally, the frontend has been extended (by a separate prompt) to display accommodation options, providing users with a more comprehensive view of their stay arrangements.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="963" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation-1024x963.png" alt="" class="wp-image-2829" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation-1024x963.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation-300x282.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation-768x722.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation-1536x1445.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/race_detail_view_with_accommodation.png 1888w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>And there you have it! By leveraging ArchUnit tests and instruction files, we were able to extend our application with a new feature in just 10 minutes, without compromising its underlying structure or architecture. This approach has proven to be highly effective in promoting maintainability, scalability, and extensibility for future features.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>As software engineers we ask ourselves how much we should vibe code? Additionally, we wonder what an application would look like if it were extended solely by AI over an extended period?</p>



<p>I believe that an application seriously deteriorates in quality over time if only extended by AI in a naive way without much guardrails. Understanding the architecture is more crucial than ever. But once that is defined well and put into mechanisms to verify, the engineer can focus on what really matters: the business logic and new features.</p>



<p>By striking a balance between human oversight and AI-assisted development, we can create applications that are both maintainable and scalable – a true win-win for software engineers.</p>



<p><sup><em>All my articles are written by myself. AI is used for some of the title images and in some cases to improve the wording and flow.</em></sup></p>
<p>The post <a href="https://ronnieschaniel.com/ai/hexagonal-architecture-in-spring-boot-projects-with-ai/">Hexagonal Architecture in Spring Boot Projects with AI</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The Cost and Time Model of AI-Assisted Software Engineering</title>
		<link>https://ronnieschaniel.com/ai/the-cost-and-time-model-of-ai-assisted-software-engineering/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 08 Feb 2026 13:57:32 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2761</guid>

					<description><![CDATA[<p>The impact of coding assistants on the SDLC.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/the-cost-and-time-model-of-ai-assisted-software-engineering/">The Cost and Time Model of AI-Assisted Software Engineering</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://ronnieschaniel.com/wp-content/uploads/2026/01/AI_aided_software_engineering_costs_gemini-1024x572.png" alt="" class="wp-image-2763" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/01/AI_aided_software_engineering_costs_gemini-1024x572.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/01/AI_aided_software_engineering_costs_gemini-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/01/AI_aided_software_engineering_costs_gemini-768x429.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/01/AI_aided_software_engineering_costs_gemini.png 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Generated by Gemini.</figcaption></figure>



<p>AI coding assistants emerged in spring 2023. Since then, those who aren&#8217;t familiar with software engineering have predicted that the role of the software engineer would become obsolete. Three years on, we&#8217;re still here. While our daily work has undergone changes, so too must our calculations of costs and understanding of time.</p>



<h2 class="wp-block-heading">The Cost and Time View before AI Coding Assistants</h2>



<p>Let us first consider the traditional approach. When faced with a task, one, two, or many engineers would be assigned to implement it, depending on their Agile methodology. The design phase, whether lengthy or brief, would precede implementation. The engineer(s) involved would have an in-depth understanding of all details. Next, the development process would unfold, including reviewing written code, manually or automatically testing on integration environments, and deployment and release. In the event of detected issues, they would be addressed. Crucially, knowledge was embedded within the engineers participating in each phase, making subsequent changes more manageable.</p>



<p>Typically, developers focused on a single task at a time, aiming to minimize context switches due to their inherent cost. Team velocity was calculated by dividing delivered story points by capacity.</p>



<p>This is how I see software engineering without AI support:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="2560" height="243" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-scaled.png" alt="" class="wp-image-2767" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-scaled.png 2560w, https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-300x28.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-1024x97.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-768x73.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-1536x146.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/non_ai_software_engineering-2048x194.png 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<ul class="wp-block-list">
<li>In Agile environments, the design phase is relatively brief. You might consider how a new user story fits into the overall system, but you wouldn&#8217;t typically document every detail of your planned implementation.</li>



<li>The majority of work is invested in the implementation and maintenance phases. While some may argue for an even longer maintenance period.</li>



<li>The review phase, which includes merge request reviews, relies heavily on the quality and clarity of the implementation. It tends to be shorter than the implementation phase itself.</li>



<li>Testing encompasses both automated and manual acceptance testing, with the majority of testing ideally taking place during the implementation phase. The quality of the implementation has a significant impact on this process. In general, writing automated acceptance tests at the UI level requires some time.</li>
</ul>



<p>From a cost or effort perspective, we observe the following:</p>



<ul class="wp-block-list">
<li>Developers typically focus on one task at a time, dedicating their attention to that specific project.</li>



<li>On the cost side, there is the developer&#8217;s salary, as well as expenses for traditional tools and licenses.</li>
</ul>



<p>Now, let us examine how this has evolved with the emergence of coding assistants.</p>



<h2 class="wp-block-heading">The Current State of AI-Supported Software Engineering</h2>



<p>We are having a look at the situation when AI coding assistants are used by the developers. The following picture illustrates the shifted distribution of phases:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="2560" height="242" src="https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-scaled.png" alt="" class="wp-image-2769" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-scaled.png 2560w, https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-300x28.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-1024x97.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-768x73.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-1536x145.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2026/02/ai_software_engineering-2048x193.png 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>



<ul class="wp-block-list">
<li>In this new scenario, the design phase typically becomes longer. This is because you need to provide more detailed specifications upfront for the AI agent to effectively implement the requirements.</li>



<li>The most significant change occurs in the Implementation phase, which tends to be shortened. Writing code is relatively easy for coding assistants to handle.</li>



<li>On the other hand, the review process becomes even more crucial and time-consuming. First, you must read the description of what the AI assistant did, followed by a review of the actual code itself.</li>



<li>The testing phase itself might become slightly shorter, as automated acceptance tests can also be generated by AI. On the other hand you need to ensure that the right thing was implemented by the AI and acceptance criteria are met.</li>



<li>Finally, I would argue that the maintenance phase is expanded relatively seen. As you haven&#8217;t been intimately involved in every detail yourself, finding bugs and understanding existing code can be more challenging. Moreover, AI often tends to create verbose code, making implementation more complicated than it needs to be – a situation that leads to more and harder-to-maintain code. For sure, also AI can be used to debug which again helps to keep the effort lower.</li>
</ul>



<p>From a cost or effort perspective, we observe the following:</p>



<ul class="wp-block-list">
<li>Developers can now work on multiple tasks at a time, especially when utilizing the agentic mode of AI coding assistants. However, this comes with increased context switching, which has its own set of drawbacks.</li>



<li>On the cost side, there is the developer&#8217;s salary, as well as traditional tools and licenses. Furthermore, expenses arise from the fee associated with using the coding assistant.</li>
</ul>



<h2 class="wp-block-heading">Consequences for Software Engineering</h2>



<h3 class="wp-block-heading">The Design Phase: More Important than Ever</h3>



<p>In this new world of AI-assisted software engineering, the design phase becomes even more critical. Implicit knowledge that was previously shared through informal channels or coffee breaks now needs to be documented and provided as input for AI.</p>



<h3 class="wp-block-heading">Implementation Phase</h3>



<p>Developers are typically fast typists, but AI can generate code even faster. This results in a shortened implementation phase. Moreover, multiple agents can run in parallel, allowing developers to perform other tasks simultaneously. A developer can have a coding agent running in the background while checking emails, for instance.</p>



<p>However, this increased productivity also introduces the danger of complacency. Developers might become too reliant on AI-generated code and neglect the importance of reviewing and maintaining it. As such, the review phase assumes greater significance, requiring more time and expertise from engineers.</p>



<h3 class="wp-block-heading">Review</h3>



<p>When so much code is produced, review can become a bottleneck (also suggested in the <a href="https://dora.dev/research/2025/dora-report/">2025 DORA report</a>). And if it is not done properly, it can lead to quality issues. What makes reviewing even more challenging, is that the code which was produced is not necessarily understandable by juniors or even some seniors. While being careful is also here more important than ever, using AI in the review process itself can also help.</p>



<h3 class="wp-block-heading">Testing</h3>



<p>Testing remains a vital aspect of software engineering. While some automated acceptance tests can be generated by AI, manual testing is still essential for ensuring the quality of the final product.</p>



<h3 class="wp-block-heading">Maintenance Phase</h3>



<p>Maintaining code is all about fixing problems, monitoring performance, and extending functionality. In this new world, I believe this phase requires more effort relative to the original process. Developers are less familiar with the generated code, which can lead to increased mental stress when switching between multiple instances of AI-generated code.</p>



<h3 class="wp-block-heading">Cost Considerations</h3>



<p>License and tool costs have always been a consideration in software engineering. The rise of AI-assisted coding tools like Copilot, Amazon Q, and others may introduce new expenses. As these subscriptions evolve, it&#8217;s crucial to factor them into the overall economic calculation of software development costs.</p>



<h3 class="wp-block-heading">Limitations of AI-Assistance</h3>



<p>While AI can certainly augment human capabilities, there are still cases where traditional expertise is essential. For instance, when dealing with complex bugs or system design issues, human intuition and experience are invaluable assets.</p>



<h3 class="wp-block-heading">Velocity and Complexity</h3>



<p>It&#8217;s possible that the increased productivity in the implementation phase will lead to higher throughput and more story points delivered per capacity. However, this might also introduce new complexities that require reevaluation of estimation methods. Only time and experience will tell how these changes play out.</p>



<p>Ultimately, as AI-assisted software engineering becomes more prevalent, it&#8217;s crucial that we have enough capable engineers on hand to design, review, and maintain the generated code properly. Otherwise, there may be bottlenecks and no overall efficiency gain can be achieved. In the same direction, supporting only one activity in the whole software development life cycle will lead to bottlenecks or inefficiencies. It is crucial to apply AI in every phase to support engineers.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Please note that these thoughts are based on a somewhat idealistic and simplistic model. As a software developer myself, I am aware that our daily work does not always align with this scenario. Nevertheless, our work has undergone changes, and our understanding of the job must adapt too. One thing is certain: we require competent engineers like always.</p>



<p><sup><em>All my articles are written by myself. AI is used for some of the title images and in some cases to improve the wording and flow.</em></sup></p>
<p>The post <a href="https://ronnieschaniel.com/ai/the-cost-and-time-model-of-ai-assisted-software-engineering/">The Cost and Time Model of AI-Assisted Software Engineering</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Gamify Software Engineering by letting AI rate your changes</title>
		<link>https://ronnieschaniel.com/ai/gamify-software-engineering-by-letting-ai-rate-your-changes/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 24 Jan 2026 18:07:32 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2732</guid>

					<description><![CDATA[<p>Can you score high on the CoPilot code review? An example of how to gamify the AI usage.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/gamify-software-engineering-by-letting-ai-rate-your-changes/">Gamify Software Engineering by letting AI rate your changes</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="535" src="https://ronnieschaniel.com/wp-content/uploads/2026/01/gamify_software_engineering-1024x535.png" alt="" class="wp-image-2733" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/01/gamify_software_engineering-1024x535.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/01/gamify_software_engineering-300x157.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/01/gamify_software_engineering-768x401.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/01/gamify_software_engineering.png 1408w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Generated by Gemini.</figcaption></figure>



<p>Some developers are vibe-coding whole applications (if you believe them). Others are using AI coding assistants for a more intelligent autocomplete, to generate or edit some snippets, or just asking questions about code or other topics. And yet another group of software engineers are totally against AI coding assistants and rarely use them. Anyway, having your code reviewed by AI is usually not a bad idea. And gamifying that approach could motivate all of the above types.</p>



<h2 class="wp-block-heading">The prompt</h2>



<p>The goal for our review is to have an output considering different factors. Each factor should be rated from 1 to 10 in 0.5 increments. There should then be also actionable suggestion on how to improve the code. I have tried various variants and ended up with the following:</p>



<pre class="wp-block-code"><code lang="adoc" class="language-adoc">Assess the provided code based on the following criteria using a 1-10 scale:

Potential Bugs (1=high risk, 10=very low risk)
How likely is this code to introduce bugs or errors?

Tests (1=no tests, 10=comprehensive coverage)
Are there sufficient tests? Is the testing strategy robust?

Clarity (1=very unclear, 10=crystal clear)
How easy is it to understand the code's intent, logic, and structure through reading?

Consistency (1=very inconsistent, 10=fitting in perfectly)
How consistent is the added code. Are there new patterns in naming, design, style or is it very consistent with existing code?

Testability (1=very difficult to test, 10=highly testable)
Can the code be easily tested in isolation?

Design (1=poorly designed, 10=well-designed)
How well-architected is the code in terms of organization and modularity?

Security (1=high risk, 10=very low risk)
Are there potential security vulnerabilities?

Average Score: Calculate the average of the six criteria.

List the scores per category in a table with the average in the last row (always in the form of x/10). Provide the 2-5 most urgent suggestions to improve in a compact form. Ask the developer if more information about improvements are needed. You need to rate consistently throughout.</code></pre>



<p>This delivered for me the best results. I wanted to have a brief summary with only a few suggestions in the beginning. This would allow me to revisit the mentioned code myself and ask for more details if needed. Of course you could even ask AI to do the improvements itself.</p>



<h2 class="wp-block-heading">Review some bad code</h2>



<p>I have tried the above prompt on some code and got the following compact response:</p>



<figure class="wp-block-image size-large mt-5"><img decoding="async" width="774" height="1024" src="https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_bad_example-774x1024.png" alt="" class="wp-image-2740" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_bad_example-774x1024.png 774w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_bad_example-227x300.png 227w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_bad_example-768x1016.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_bad_example.png 1086w" sizes="(max-width: 774px) 100vw, 774px" /></figure>



<p>So here we have a lot of potential to improve.</p>



<h2 class="wp-block-heading">Scoring well</h2>



<p>After some improvements I can run the prompt again and I score now 8.3 on average, compared to the 4.6 before:</p>



<figure class="wp-block-image size-large mt-5"><img decoding="async" width="1024" height="910" src="https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_after_improvements-1-1024x910.png" alt="" class="wp-image-2742" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_after_improvements-1-1024x910.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_after_improvements-1-300x267.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_after_improvements-1-768x683.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/01/ai_review_prompt_after_improvements-1.png 1118w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Is the code now very good and I don&#8217;t need a human review at all? Definitely not! Even you should review again if the changes were done by AI. But once pushed to the remote your peers will probably be more happy about the Merge Request that should now look more pleasant than before.</p>



<h2 class="wp-block-heading">Make it reusable</h2>



<p>Finally we would like to have the prompt always ready. That is why you can create a .github/copilot/prompts folder with a prompt file codeReviewAssessment.prompt.md. The file is started with the following block and contains the prompt below that:</p>



<pre class="wp-block-code"><code lang="markdown" class="language-markdown">---
name: codeReviewAssessment
description: Evaluate code quality across seven dimensions with consistent scoring and actionable feedback.
argument-hint: The selected code or codebase to review
---</code></pre>



<p>This enables us to access the prompt by typing /codeReviewAssessment.</p>



<figure class="wp-block-image size-large mt-5"><img decoding="async" width="1024" height="205" src="https://ronnieschaniel.com/wp-content/uploads/2026/01/prompt_ready_for_code_review_assessment-1024x205.png" alt="" class="wp-image-2745" srcset="https://ronnieschaniel.com/wp-content/uploads/2026/01/prompt_ready_for_code_review_assessment-1024x205.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2026/01/prompt_ready_for_code_review_assessment-300x60.png 300w, https://ronnieschaniel.com/wp-content/uploads/2026/01/prompt_ready_for_code_review_assessment-768x154.png 768w, https://ronnieschaniel.com/wp-content/uploads/2026/01/prompt_ready_for_code_review_assessment.png 1098w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
<p>The post <a href="https://ronnieschaniel.com/ai/gamify-software-engineering-by-letting-ai-rate-your-changes/">Gamify Software Engineering by letting AI rate your changes</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>50 AI Mini Use Cases for Software Engineers: Boost Your Productivity with GPT and Coding Assistants</title>
		<link>https://ronnieschaniel.com/ai/50-ai-mini-use-cases-for-software-engineers-boost-your-productivity-with-gpt-and-coding-assistants/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 21 Dec 2025 13:02:44 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2651</guid>

					<description><![CDATA[<p>The key is to be creative.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/50-ai-mini-use-cases-for-software-engineers-boost-your-productivity-with-gpt-and-coding-assistants/">50 AI Mini Use Cases for Software Engineers: Boost Your Productivity with GPT and Coding Assistants</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img decoding="async" width="1022" height="781" src="https://ronnieschaniel.com/wp-content/uploads/2025/12/mini_ai_use_cases_as_software_engineer.png" alt="" class="wp-image-2653" srcset="https://ronnieschaniel.com/wp-content/uploads/2025/12/mini_ai_use_cases_as_software_engineer.png 1022w, https://ronnieschaniel.com/wp-content/uploads/2025/12/mini_ai_use_cases_as_software_engineer-300x229.png 300w, https://ronnieschaniel.com/wp-content/uploads/2025/12/mini_ai_use_cases_as_software_engineer-768x587.png 768w" sizes="(max-width: 1022px) 100vw, 1022px" /><figcaption class="wp-element-caption">This picture was generated by Gemini.</figcaption></figure>



<p>The advent of General-Purpose Transformational (GPT) models, followed by coding assistants like GitHub Copilot, has revolutionized the software engineering landscape. However, many developers struggle to go beyond basic use cases. A bit of creativity is needed. To unleash the full potential of AI in your daily work, I&#8217;ve compiled a comprehensive list of 50 AI mini use cases that you can apply using general GPT or a coding assistant.</p>



<p>Before diving into these use cases, please keep two essential points in mind: first, ensure you have the necessary permissions to input information into the chat bot from a security perspective; and second, always review the output generated by the AI tool.</p>



<h2 class="wp-block-heading">GPT Use Cases</h2>



<p>This is for use cases outside of your integrated development environment (IDE). It contains simple things that you probably did manually in the past. The order is random.</p>



<ol class="wp-block-list numeric-list">
<li><strong>Translate</strong>: use it to understand any text.</li>



<li><strong>Test data generation:</strong> based on classes or examples.</li>



<li><strong>Dashboard explanation:</strong> export a monitoring or analytics dashboard source. Paste it into the chat and ask it to describe the dashboard in natural language, including where the data comes from and how numbers are calculated.</li>



<li><strong>Query parameter generation:</strong> paste a JSON and ask it for transforming into a query parameter string.</li>



<li><strong>Test scenarios:</strong> generate test scenarios based on a feature description.</li>



<li><strong>Drafting documents:</strong> draft documentation and manuals.</li>



<li><strong>SQL queries</strong>: write or optimise SQL queries.</li>



<li><strong>Write queries for your monitoring system</strong>, e.g. Splunk or Grafana.</li>



<li><strong>Summarise feedback</strong>: textual user feedback and suggest improvement ideas.</li>



<li><strong>Release notes: </strong>Generate release notes based on GIT commits.</li>



<li><strong>Scripts: </strong>Write simple scripts.</li>



<li><strong>Meeting notes:</strong> Summarise meeting notes and create a task/action list.</li>



<li><strong>Data validation rules</strong>: Given a dataset schema, generate a set of data validation rules (e.g., 3-5 rules) to ensure the data meets certain criteria and is consistent with the schema.</li>



<li><strong>Draft presentations:</strong> create a first version or an outline for a presentation.</li>



<li><strong>Review architectures:</strong> describe how you plan to implement a feature on the architectural level to get feedback, descriptions or diagrams.</li>



<li><strong>Generate checklists:</strong> create checklists for deployments, releases or other critical tasks.</li>



<li><strong>Evaluate skills:</strong> explain your current skills and ask for an evaluation and list of gaps to guide your next learning steps.</li>



<li><strong>Summarise technical articles</strong>: to learn about topics.</li>



<li><strong>Quizzes:</strong> generate a quiz based on a technical article or documentation.</li>



<li><strong>Interview preparation:</strong> ask for potential questions based on a job description.</li>



<li><strong>Create survey or forms:</strong> generate questions and answer options. Also use it later to summarise replies.</li>



<li><strong>Glossary:</strong> generate a list of terms that are not generally understandable.</li>



<li><strong>Generate the agenda for a meeting:</strong> draft the meeting invitation.</li>



<li><strong>Explain a dataset:</strong> take a dataset and explain the latest trends and highlights.</li>



<li><strong>Vulnerability analysis</strong>: describe a setup or solution and ask for a threat modelling and potential vulnerabilities.</li>
</ol>



<p>These were the general chat use cases. Some of them could also be done in the IDE directly of course. Anyway, in the next chapter you find use cases that are more typical to be directly executed by your AI coding assistant.</p>



<h2 class="wp-block-heading">Coding Assistant Use Cases</h2>



<p>The use cases below are all about using CoPilot and co. in a way to help you working.</p>



<ol class="wp-block-list numeric-list">
<li><strong>User Story to code:</strong> copy a complete User Story description into the chat, use agent mode, and ask it to generate the code for the story.</li>



<li><strong>Review code changes:</strong> at the end of implementing a change, ask the coding assistant to review your changes for security, clarity, potential bugs or other issues.</li>



<li><strong>Visualise logic: </strong>open a class or module that contains lots of logic. Ask to generate a <a href="https://www.mermaidchart.com/" target="_blank" rel="noreferrer noopener">mermaid</a> diagram definition (text based diagram).</li>



<li><strong>Regex:</strong> ask to generate a regex based on a textual description or examples.</li>



<li><strong>Generate specific values:</strong> generate UUIDs or other random data that you occasionally need.</li>



<li><strong>Tests: </strong>ask to generate unit tests for a certain class or module.</li>



<li><strong>TDD: </strong>generate the implementation based on tests.</li>



<li><strong>Test coverage:</strong> ask which cases are not tested yet.</li>



<li><strong>Error explanation:</strong> paste a stack trace of an error and ask for a fix.</li>



<li><strong>Data transformation:</strong> transform data from one representation to another, e.g. JSON to TypeScript.</li>



<li><strong>Document code:</strong> ask to generate a documentation based on code.</li>



<li><strong>3rd party library:</strong> get information about a third party library that you want to use.</li>



<li><strong>Review accessibility:</strong> review html code for accessibility issues or make it compliant.</li>



<li><strong>Technology migration:</strong> switch from one implementation version to another, e.g. Java 20 to 21, RestTemplate to WebClient.</li>



<li><strong>Improve performance:</strong> ask about performance issues in the code and ways to improve.</li>



<li><strong>Understand:</strong> explain code.</li>



<li><strong>Port between languages:</strong> transform code from one language into another.</li>



<li><strong>Generate commit messages:</strong> generate git commit messages based on the changes.</li>



<li><strong>Overview</strong>: ask for a general overview of a project&#8217;s source code if it&#8217;s new to you to understand conventions, patterns and libraries used.</li>



<li><strong>Refactoring to patterns: </strong>if you see a code smell and the possibility to refactor to a design pattern, use the coding assistant.</li>



<li><strong>Generate performance tests:</strong> create performance tests, e.g. JMeter scripts, based on the APIs.</li>



<li><strong>Optimise internal exceptions and error:</strong> draft text for internal errors and exception for your fellow engineers and your future self.</li>



<li><strong>Generate API requests</strong>: create API requests in curl, postman, bruno or any other API tool.</li>



<li><strong>README:</strong> generate READMEs based on the code.</li>



<li><strong>Improvement and refactoring</strong>: ask for potential changes to your code.</li>
</ol>



<p>These use cases are designed to help you unlock the full potential of GPT and coding assistants in your daily workflow. Whether you&#8217;re a seasoned software engineer or just starting out, these mini use cases will inspire you to find innovative solutions to common challenges.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/50-ai-mini-use-cases-for-software-engineers-boost-your-productivity-with-gpt-and-coding-assistants/">50 AI Mini Use Cases for Software Engineers: Boost Your Productivity with GPT and Coding Assistants</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Make your Gen AI Project a Success</title>
		<link>https://ronnieschaniel.com/ai/make-your-gen-ai-project-a-success/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 21 Dec 2025 09:03:20 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=2628</guid>

					<description><![CDATA[<p>How to design, implement and roll out Generative AI solutions that deliver value.</p>
<p>The post <a href="https://ronnieschaniel.com/ai/make-your-gen-ai-project-a-success/">Make your Gen AI Project a Success</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://ronnieschaniel.com/wp-content/uploads/2025/12/usage_of_AI_in_projects-1024x572.png" alt="" class="wp-image-2627" title="Generated by Gemini" srcset="https://ronnieschaniel.com/wp-content/uploads/2025/12/usage_of_AI_in_projects-1024x572.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2025/12/usage_of_AI_in_projects-300x167.png 300w, https://ronnieschaniel.com/wp-content/uploads/2025/12/usage_of_AI_in_projects-768x429.png 768w, https://ronnieschaniel.com/wp-content/uploads/2025/12/usage_of_AI_in_projects.png 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">This picture was generated by Gemini.</figcaption></figure>



<p>The release of ChatGPT in November 2022 sparked excitement about the possibilities of Generative AI. In just five days, it gained over a million users. As businesses began to explore how to leverage this technology, they quickly realized that using AI internally was crucial.</p>



<p>Fast-forward three years, and many companies have jumped on the Generative AI bandwagon, building their own GPT or LLM-based solutions. However, what I often see is that creators simply add an LLM with Retrieval Augmented Generation (RAG) to their data, hoping for the best. But does this approach truly deliver value? I have some doubts.</p>



<p>This sentiment is also confirmed by various studies, MITs &#8220;<a href="https://api.directual.com/fileUploaded/directual-site/e8ed57ab-19a8-4834-815f-9109a4c06f0e.pdf" target="_blank" rel="noreferrer noopener">State of AI in Business 2025</a>&#8221; reports that &#8220;Despite $30–40 billion in enterprise investment into GenA (&#8230;) 95% of organizations are getting zero return&#8221;. In this post we speak about software companies or companies that have at least their own IT department and are planning to build their own AI solutions.</p>



<h2 class="wp-block-heading">The naive approach for Generative AI projects</h2>



<p>Cost pressure is high in many tech companies. And so is the hype around AI. An easy strategy is therefore to just invest in AI. An LLMs capability can look impressive, but the main issues is that it doesn&#8217;t have access to company data out of the box. Retrieval augmented generation can help there and extend the LLMs context by data in files or on wiki pages. It&#8217;s also not super difficult to implement. So, many just start to RAGify everything they have. This is nice to have and the use cases around it are many, but:</p>



<ul class="wp-block-list">
<li>The data that is retrieved is often in bad quality and can be outdated.</li>



<li>As the use cases are endless, end-users struggle to understand how to exactly use the new possibilities. I&#8217;ve got that wiki page no in a chat bot, nice, but what now? What should I do with it?</li>



<li>Even if there is a chat bot available somewhere backed by RAG, it&#8217;s usually a standalone app. This requires users to switch context and leads to a fragmented tool landscape.</li>



<li>The return on investment (ROI) of such solutions is not measured or not understood. </li>



<li>Projects look fancy in the beginning because you get impressive answers very soon. But optimising the solution to reach production state is hard. Project teams often miss to have an evaluation pipeline and defined KPIs.</li>



<li>Big use cases are tackled early on and take months to implement, delaying the benefits and in the worst case leading to a solution that is not usable at all.</li>



<li>The core of the AI solution might be built within a few days. But integrating it into the existing system landscape, considering security, compliance, people training, data maintenance, and other factors can take months.</li>
</ul>



<p>Still the pressure remain, we have to do something with AI! And in the next section I would like to highlight a few points that help you to make your project a success.</p>



<h2 class="wp-block-heading">How to tackle Generative AI projects</h2>



<p>I&#8217;m convinced that AI has benefits in it for most businesses. How do we make it a success? First of all, slow down! Don&#8217;t follow the latest trends daily, but have a robust AI strategy that is dynamic enough to adapt, but doesn&#8217;t lead to jumping always onto the latest technological advances in the field of AI. Because there&#8217;s just too much going on.</p>



<p>And then more importantly. Don&#8217;t take Generative AI and RAG as a technology and ask yourself what it can solve. That&#8217;s the wrong direction! Ask what problems do you have in your company and design a solution for it. And then ask what parts of the solution can be covered or improved by generative AI.</p>



<p>Also don&#8217;t forget how software was built in the last years. Don&#8217;t forget agile! Put the user, feedback and short iterations into the center.</p>



<p>Consider the following when you&#8217;re planning to build an AI solution in your organisation:</p>



<ul class="wp-block-list">
<li>Start with problems, not technology: Design a solution for specific company challenges, and then ask how AI can help.</li>



<li>Use agile principles as in any other software product you have built in the last years.</li>



<li>Don&#8217;t build standalone solutions, but make sure AI is integrated into the existing workflows.</li>



<li>Educate and train the user. This starts even by making sure the AI strategy is understood by everyone and nobody has to fear for their jobs.</li>



<li>As AI is non-deterministic, define KPIs that you need to achieve to make your solution useful. Iterate and improve.</li>



<li>Define the ROI you want to see when you plan the solution. What is your business case? What can your colleagues do with the solution you&#8217;re building?</li>



<li>Consider data management, security, compliance, and other non-functional requirements early!</li>
</ul>



<p>Finally, you might put a generative AI solution into production that makes some work faster or better. Ask yourself what the time freed up by that, can be used for. If you make a process faster only to run into waiting times or have colleagues who can&#8217;t use their newly won time, you&#8217;ve failed too.</p>



<p></p>
<p>The post <a href="https://ronnieschaniel.com/ai/make-your-gen-ai-project-a-success/">Make your Gen AI Project a Success</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
