DEV Community

Cover image for AI coding philosophy
Marco Sbragi
Marco Sbragi

Posted on • Edited on

AI coding philosophy

Introduction

Since I started using AI for development, I've immediately noticed several problems along with the many benefits. This is especially true when projects aren't simple standalone or disposable tools.

If you develop complex projects with dozens of modules and/or services that interact with each other, you'll quickly notice code redundancy and unwanted repetition. It's a bit like going back to the mythical days of copy and paste. Of course, the code implementation is good (it depends a lot on the model you use).

Another very important aspect is that for very complex projects, the context becomes so large that everything slows down and the model tends to forget where we started.

To summarize

  1. Duplicate or unoptimized code
  2. As the code grows, the model "forgets" and tends to hallucinate
  3. Changing models results in different implementations that often don't follow the rules.
  4. The costs of cloud-based models are increasing exponentially.

To solve these problems, I've tried to find a way to properly "train" the various models I use, to get the most out of them.

Goal

  1. When I ask for something, the model must always develop a strategy before writing code.
  2. It must check for reusable code or already implemented services without reinventing the wheel.
  3. It must ask for confirmation and discuss the proposed solutions with me.
  4. It must always create a TODO file with the exact method to follow.
  5. It must absolutely wait for my order before starting to write code.

Benefits of this approach

  • You can use a more "intelligent" and expensive model for planning and less expensive models for implementation that only need to follow the TODO instructions (Architect => Senior => Junior)
  • There's no need for long, cumbersome sessions, but rather many small sessions to solve a specific problem.
  • Individual sessions can be reused for modifications, debugging, and refactoring.
  • Understanding of patterns and code is improved because they're discussed together before implementation.

Example

As an example, I'll show you the instructions file I normally use as a template.
What do you think? Where can it be improved?
I look forward to your comments and suggestions.

TIA

# Global Project Governance & AI Persona

## 1. AI Role & Context
- **Role**: Senior Full-Stack Architect.
- **Expertise**: Agile methodologies (User Stories, Sprint Planning), Angular 20, and NestJS.
- **Goal**: Guide development using Agile practices while ensuring production-ready, highly abstracted code.
- **Environment**: Multi-workspace environment with BASE_DIR at `/YOUR_PROJECT_PATH`.

## 2. Directory & Path Mapping
- **System Root**: `${BASE_DIR}` translates to `/YOUR_PROJECT_PATH`.
- **Project Structure**:
    - Backend: `${BASE_DIR}/backend` (NestJS)
    - Frontend: `${BASE_DIR}/frontend` (Angular)
- **Strict Rule**: Always use absolute paths starting with `${BASE_DIR}` when referencing configurations, Docker files, or cross-project documentation.

## 3. The "todo.md" Protocol (Mandatory)
Before writing any code for a new feature, you MUST:
1. Check if a `todo.md` exists in the feature's target directory.
2. If it doesn't exist, **STOP** and ask the user to perform an "Analysis Phase" to create it.
3. Follow the `todo.md` step-by-step. Do not skip steps. Do not jump to the "Delivery" phase before the "Architecture" phase is ticked.

## 4. Development Philosophy (BMAD)
- **Brief**: Re-state the requirement to ensure alignment.
- **Models**: Define Interfaces/DTOs before logic.
- **Architecture**: Always extend `BaseService` or `BaseEntity`. No shortcuts.
- **Delivery**: Generate code only after the user approves the architectural plan.

## 5. Coding Standards
- **DRY & Abstraction**: If a logic is repeated, it belongs to a `Common` service or a `Base` class.
- **Immutability**: Prefer readonly properties and immutable data patterns.
- **No Inventions**: Do not hallucinate methods. If you are unsure about an existing helper, ASK.

## 6. STRICT BMAD PROTOCOL (Mandatory for every feature/refactor or planning)
To avoid logic reinvention and maintain architectural integrity, you MUST follow these steps for every request:

1. **Analisys (B - Briefing)**: Re-state the requirements and context. Identify the goal without proposing code.
2. **Define all structure and types (M - Modeling)**: Define Interfaces, DTOs, and Data Models. Ensure they extend `BaseEntity` or follow project standards.
3. **Propose the structure (A - Architecture)**: List the files to be created/modified. Specify which `BaseService`, `ApiService`, or Core components will be used.
4. **Wait for approval (D - Delivery)**: STOP HERE. Do not write implementation code until the developer explicitly says "PROCEED" or "OK".

**Strict Rule**: If you skip to step 4 without completing 1, 2, and 3, the task is considered failed.
Enter fullscreen mode Exit fullscreen mode

Top comments (5)

Collapse
 
alex_tavor_7c6c1ec3797ad8 profile image
Alex Tavor

I am using a much stricter version of your approach, and it works well. I go with generic SOPs for all projects, per-project architectural rules, proof-based decisions and tradeoffs, ADRs, HLDs, LLDs - the full shebang, delivered as skills + agents + scripts.

How do you go about generating the constraints?

Collapse
 
bumbulik0 profile image
Marco Sbragi

Thanks for the comment! Your approach with automated SOPs and agents is highly structured.

In my workflow, I prefer a lighter but very strict approach based on context compartmentalization. My core constraint is the BMAD protocol (Brief, Model, Approve, Deliver) acting as the global system prompt.

Beyond that, my two non-negotiable golden rules for generating constraints are:

  1. No Workspace Guessing: If a requirement lacks detail, the assistant is strictly forbidden from "scavenging" the workspace to make creative assumptions. It must stop and ask. Communication overrides hallucination.
  2. Terminal Boundaries ("The terminal is mine"): The agent is not allowed to execute terminal commands, except for running strictly sandboxed tests if needed. It can suggest commands, but I am the only one running them.

On top of this behavior, I inject component-specific rules (frontend, backend, Docker) containing specific architectural constraints and reference implementation examples in the folder of the contained sources. Instead of building complex multi-agent layers to parse massive documentation stacks, I use these strict boundaries to keep the LLM as a precise executor, ensuring the developer remains the only gatekeeper of the system.

Excuse me, but my English is not the best. If I misunderstood your question, feel free to ask again!

Collapse
 
alex_tavor_7c6c1ec3797ad8 profile image
Alex Tavor

Thank you for the answers, Marco, they and your insights are much appreciated.

Do you have references to share about BMAD? Sounds interesting, and I am finding conflicting things about it online :)

You enforce "No Workspace Guessing" by keeping local docs for code areas, if I understand you correctly? How do you handle larger projects, where there are many interacting units and cross-system concerns?

Thread Thread
 
bumbulik0 profile image
Marco Sbragi • Edited

Hi Trevor, thanks for the observation. Regarding BMAD, I should clarify: I am using this acronym as a personal shorthand to define my own structured interaction protocol with the LLM. It is not intended to refer to established organizational or business frameworks found elsewhere. It is a concept a methodology you can find for a strict organization of work. In internet you can find also some other implementation called BMAD the pattern is similar adapted to different domains or situations.

For my day-to-day work, BMAD is simply the logical sequence I enforce to avoid 'Vibe Coding':

  1. Briefing the intent.
  2. Modeling the structure/logic (before generating code).
  3. Human Approval.
  4. Delivering the implementation.

You can find my implementation of this pattern in my posts (in the markdown with the core instructions for the llm). To be more explicit, the complete acronym is BMAD(v), where (v) stands for Verify. The model cannot proceed until all steps are performed and verified.

Regarding "No Workspace Guessing" and large projects:
You're right. I enforce the rule directly in the main system prompt ("If you don't know, stop and ask. Don't guess."), but I support it with what I call Spatial Architecture (the project layout). If I want to refactor code, I hate when the model starts searching or grepping through the entire workspace; I have already defined the constraints, and if anything is unclear, it must ask me.

When managing large projects with many interacting units, I strictly apply the principles of Domain-Driven Design and component isolation. I don't feed the entire monolithic workspace to the AI; this would inevitably cause cognitive overload and hallucinations.

Instead, cross-system concerns are handled exclusively through Contracts and Configurations.

For example, if the frontend needs to communicate with the backend, the AI working on the frontend doesn't need to read the backend source code. It only needs the API contract (such as OpenAPI/Swagger schemas or shared DTO definitions and interfaces).

In my backend, every DTO or entity implements an interface. This same interface is used in the frontend as the main contract. The backend response is standardized with a payload that contains:

  • time
  • url
  • data (where 'data' adheres to the specific interface)

In the frontend, I have an ApiService that hides the backend call logic. It is responsible for managing errors and messages. Every service simply implements the call to apiService (GET/POST/PUT, etc.) and unwraps the data from the returned payload using the correct interface.

If you have time you can take a look at my project for a rad framework on github where RAD stands for Rapid Architecture Development. This is how i choose to work after years in writing code.

It's the right way? "It is right for me"
Can be done better? "Sure! everything can be"

Collapse
 
bumbulik0 profile image
Marco Sbragi

Sorry Alex, I realised only now that this was my very first post on dev.to. I referenced in my comments my GitHub repository but didn't mention it in the article when i wrote it. You can find the RAD System FW here, and more info on my development strategies and mindset on my blog nospace.net.