I have utilized generative AI tools such as ChatGPT and GitHub Copilot for several years, but the central question that has consistently occupied my research is how to effectively apply these technologies within a production environment. Through dozens of experiments, I have moved beyond simple code generation to delivering production-ready stories with minimal manual intervention. My objective is to transition from viewing AI as a mere novelty to integrating it into a functional triad programming model.
The Evolution Toward Triad Programming
In my experience, modern enterprise software cannot be developed in isolation; it requires a collaborative team effort. For roughly six months, I have explored the transition from traditional pair programming to triad programming, where an AI teammate joins the human pair to facilitate development. This transition requires a cultural shift within the team to move from treating AI as a buzzword to utilizing it as a practical tool.
The support of technical leadership is an important prerequisite for this shift. Without such backing, changing established team initiatives and workflows is difficult. To support this cultural change, we organized internal sessions and weekly two-hour workshops dedicated to demystifying the technology. By exploring how to master context and refine instructions, the team can eliminate the magical perception often associated with artificial intelligence and treat it as a predictable component of the engineering process.
Establishing the AI Environment through Context
Defining the AI environment is an ongoing challenge, especially given the limitations inherent in production workflows. For my current purposes, I define the environment as the context provided to the model, which effectively makes the AI environment equal to its instructions. Whether these instructions are provided through a prompt, a specific configuration file, or an MCP server, they serve as the foundational constraints for the AI's output.
I believe it is essential to manage the AI environment as closely as possible to the development process. This allows the team to remain agile and make necessary changes without creating disconnected silos of instruction.
A significant advantage of this approach is the ability to leverage existing, plain-English documentation rather than creating specialized AI adaptations. For example, I use the team's standard Confluence page for quality assurance and testing strategies as a direct instruction set. This documentation outlines requirements such as ensuring every acceptance criterion is covered by a test and avoiding complex end-to-end suites in favor of integration coverage. Decoupling the testing strategy from AI-specific formatting ensures that if the team updates their standards, the AI's context is automatically updated, while the documentation remains readable for non-engineering stakeholders.
Architectural Constraints and Testing Strategies
To reduce cognitive load and provide clear boundaries for the AI, my team established a strict architectural agreement for our services. We utilize a hexagonal architecture, which is documented in Confluence to ensure consistency when engineers rotate between different services. This structure includes a defined hierarchy of adapters, controllers, and domain use cases.
The current structure organizes components into clear packages such as:
com.todo.adapter.controller for handling external requests and DTOs
com.todo.adapter.supplier for repository adapters and external client configurations
com.todo.domain for core exceptions, models, and use cases
While this structure is optimized for organizational clarity rather than pure readability, it serves as a robust framework that prevents the AI from generating unexpected or hallucinated results. By grounding the AI in these established conventions, we save significant time that would otherwise be spent on custom instruction maintenance.
The Practical Workflow: From Init Prompt to Autopilot
The bridge between our documentation and the code is the initialization prompt. I have found that the most effective flow involves using ChatGPT, which has integrated connections to Jira, Confluence, and our GitHub repositories. This allows me to create a prompt that references specific Jira stories and Confluence guidance pages directly.
When provided with these links, ChatGPT analyzes the story details, the codebase structure, and the architectural standards to generate a grounded implementation plan. This plan maps to actual ports and adapter conventions rather than generic advice. This approach also facilitates a dialogue between human pair partners, as the chat becomes a shared space for reaching an agreement before the final prompt is passed to GitHub Copilot.
Slicing and Iterative Implementation
A critical aspect of using AI in production is task slicing. To prevent the AI from attempting to generate non-existent dependencies, it is vital to isolate fragments of the story. For a simple task involving a controller, a use case, and a client, I follow a isolated sequence:
Implement a controller with a hard-coded response.
Implement the client that connects to the external service.
Develop the use case to bridge the domain model and the client.
Update the controller to utilize the new use case.
Each slice follows a rigorous autopilot loop within GitHub Copilot. I provide a specific instruction set that mandates a test-driven development cycle:
Analyze the task and the repository for alignment.
Create tests and mark them as skipped until the plan is approved.
Establish an implementation order for the tests.
Iterate through each test by removing the skip marker, implementing the code, and verifying the test passes.
Execute a full build, such as gradle clean build test, after each passing test to ensure overall system stability.
Human Oversight and Integration
Despite the high level of AI involvement, human oversight remains a non-negotiable requirement for production code. I request that Copilot organize the resulting files into commit groups that are easy for a person to understand before opening a pull request.
By keeping pull requests small and isolated, they remain manageable for human review, ensuring they meet specific client requirements and that the human engineers maintain a deep understanding of the codebase.
This workflow demonstrates that by leveraging existing organizational processes and treating AI as an integrated teammate rather than an external tool, we can deliver high-quality software with greater efficiency and consistency.
