AI Engineering

How AI Is Changing Software Engineering

Afzal AhmedAfzal Ahmed
·12 June 2026·7 min read
ClaudeKiroGitHub CopilotChatGPTSemantic KernelAzure AI

Why This Matters

Rather than replacing developers, AI is becoming another tool in the engineering toolbox. This article shares how I use Claude, Kiro, ChatGPT, GitHub Copilot, and Azure AI to accelerate architecture, documentation, implementation planning, debugging, and software delivery while maintaining sound engineering principles.

How AI Is Changing Software Engineering

AI Doesn't Replace Engineers

Let me be clear from the start: AI tools do not replace software engineers. They make experienced engineers more productive. The key word is experienced — you need to know what good software looks like in order to evaluate what AI produces.

How I Use AI Daily

Architecture Exploration

When I'm designing a new module, I use Claude to rapidly explore architectural options. "What are the trade-offs between a state machine and a simple status field for this workflow?" The AI provides a starting point for thinking — I make the final decision.

Documentation

Technical documentation is essential but time-consuming. AI helps me generate README files, API documentation, onboarding guides, and architecture decision records. I review and refine — but the first draft comes faster.

Implementation Planning

Before building a feature, I often discuss the implementation approach with Claude. "Given this domain model, what would a clean CQRS implementation look like?" It helps me think through edge cases I might have missed.

Code Generation

GitHub Copilot and Kiro help me write boilerplate code faster — entity configurations, DTOs, validators, test scaffolding. The repetitive parts of development that add up to hours of typing.

Debugging

When investigating a complex production issue, AI can help analyse stack traces, suggest root causes, and propose fixes. It's like having a colleague to bounce ideas off.

What AI Cannot Do

AI cannot:

  • Understand your business context without being told
  • Make architectural decisions with long-term consequences
  • Evaluate whether a solution is appropriate for your team's skill level
  • Understand the political and organisational context of technical decisions
  • Take responsibility for production incidents
These require engineering judgement built over years of experience.

The Engineering Judgement Layer

I think of AI as operating beneath a layer of engineering judgement:

Engineering Judgement (human)
    ↓ decides what to build and why
AI Assistance (tools)
    ↓ accelerates implementation
Production Software (output)

The value of AI is in acceleration — not automation. I review everything. I make the decisions. The tools help me get there faster.

Professional Development

In 2025, I completed specialisations in Generative AI Software Engineering, AI Agent Development, and Generative AI Data Analysis through Vanderbilt University. These helped me understand:

  • How AI models work (at a practical level)
  • Prompt engineering for software development
  • AI agent architectures
  • Responsible use of AI in enterprise contexts

My Position

I believe the best software will continue to be built by skilled engineers supported by intelligent tools. The engineers who thrive will be those who embrace AI while maintaining the engineering discipline that makes software reliable, maintainable, and valuable.


A Practical Field Guide to AI-Assisted Software Engineering

1. Choosing the right problem for AI assistance

Choosing the right problem for AI assistance matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of choosing the right problem for ai assistance. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

2. Writing useful engineering context

Writing useful engineering context matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of writing useful engineering context. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

3. Separating exploration from commitment

Separating exploration from commitment matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of separating exploration from commitment. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

4. Reviewing generated code as untrusted input

Reviewing generated code as untrusted input matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of reviewing generated code as untrusted input. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

5. Protecting secrets and customer data

Protecting secrets and customer data matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of protecting secrets and customer data. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

6. Checking dependencies and licences

Checking dependencies and licences matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of checking dependencies and licences. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

7. Using AI for architecture exploration

Using AI for architecture exploration matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of using ai for architecture exploration. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

8. Producing implementation plans

Producing implementation plans matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of producing implementation plans. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

9. Generating safe scaffolding

Generating safe scaffolding matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of generating safe scaffolding. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

10. Improving automated tests

Improving automated tests matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of improving automated tests. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

11. Debugging with evidence

Debugging with evidence matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of debugging with evidence. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

12. Reviewing database changes

Reviewing database changes matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of reviewing database changes. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

13. Working with unfamiliar codebases

Working with unfamiliar codebases matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of working with unfamiliar codebases. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

14. Creating documentation that remains truthful

Creating documentation that remains truthful matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of creating documentation that remains truthful. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

15. Designing effective prompts

Designing effective prompts matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of designing effective prompts. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

16. Managing context windows

Managing context windows matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of managing context windows. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

17. Avoiding confident hallucinations

Avoiding confident hallucinations matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of avoiding confident hallucinations. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

18. Measuring productivity honestly

Measuring productivity honestly matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of measuring productivity honestly. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

19. Preserving developer learning

Preserving developer learning matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of preserving developer learning. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

20. Pairing junior engineers with AI

Pairing junior engineers with AI matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of pairing junior engineers with ai. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

21. Using AI in pull-request reviews

Using AI in pull-request reviews matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of using ai in pull-request reviews. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

22. Handling security-sensitive code

Handling security-sensitive code matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of handling security-sensitive code. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

23. Evaluating agentic workflows

Evaluating agentic workflows matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of evaluating agentic workflows. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

24. Building human approval gates

Building human approval gates matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of building human approval gates. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

25. Maintaining audit trails

Maintaining audit trails matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of maintaining audit trails. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

26. Responding to production incidents

Responding to production incidents matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of responding to production incidents. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

27. Refactoring legacy systems

Refactoring legacy systems matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of refactoring legacy systems. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

28. Testing non-deterministic outputs

Testing non-deterministic outputs matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of testing non-deterministic outputs. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

29. Establishing team policies

Establishing team policies matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of establishing team policies. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

30. Selecting tools and models

Selecting tools and models matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of selecting tools and models. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

31. Managing cost and latency

Managing cost and latency matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of managing cost and latency. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

32. Communicating AI use to stakeholders

Communicating AI use to stakeholders matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of communicating ai use to stakeholders. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

33. Preparing for organisational change

Preparing for organisational change matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Begin by making the current behaviour visible. Interview the people who use and support the system, inspect representative production evidence, and write down assumptions before changing code. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

A credible implementation includes a happy-path example, at least one boundary case, a deliberate failure case and an explanation of what operators will observe. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of preparing for organisational change. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

34. Recognising when not to use AI

Recognising when not to use AI matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Treat the design as a contract rather than a coding trick. Name the inputs, outputs, failure modes, ownership boundary and observable evidence that would prove the behaviour is correct. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

The review should ask which assumptions are enforced mechanically, which remain conventions and which depend on an external service or a human decision. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of recognising when not to use ai. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

35. Building an AI-assisted delivery workflow

Building an AI-assisted delivery workflow matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Deliver the smallest end-to-end example first. A thin working path exposes misunderstandings earlier than a large speculative framework and gives reviewers something concrete to challenge. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

Production readiness means considering security, accessibility, performance, recoverability and support—not merely demonstrating that the code compiles. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of building an ai-assisted delivery workflow. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

36. Defining professional responsibility

Defining professional responsibility matters in an engineering team using generative AI while remaining accountable for production software. The practical objective is faster delivery without surrendering correctness, security, maintainability or professional judgement. This topic is easy to reduce to a slogan, but useful engineering requires us to connect the idea to decisions, evidence and operational consequences.

Optimise for the next engineer who must diagnose the feature under pressure. Clear names, explicit decisions, focused tests and useful telemetry are more valuable than impressive abstraction. Start with one concrete scenario and follow it through every relevant boundary. Record where information originates, where it is transformed, who is allowed to act, how failure is represented and how the result becomes visible. That exercise often reveals hidden coupling and ambiguous ownership before implementation begins.

A production-minded approach

First, define the desired outcome in language a product owner or operational user can verify. Second, identify the smallest contract that expresses that outcome without leaking internal implementation details. Third, implement the rule close to the data and knowledge required to enforce it. Fourth, add tests at the cheapest level that can genuinely prove the behaviour. Finally, expose enough structured telemetry to distinguish a user mistake, a validation failure, a dependency outage and a programming defect.

If the team cannot explain how to test, monitor and reverse the change, the design is still incomplete even when the primary scenario appears to work. Reviewers should be able to trace the reasoning from requirement to contract, from contract to implementation and from implementation to observable result. When that chain is missing, teams compensate with tribal knowledge and production debugging becomes guesswork.

Failure modes to challenge

Common mistakes include accepting ambiguous input, hiding failure behind a default value, trusting data that crossed a runtime boundary, coupling unrelated responsibilities, and adding an abstraction before the team understands the variation it must support. Another warning sign is a test suite that mirrors private implementation details but never demonstrates the user-visible rule. Prefer explicit behaviour and small replaceable components.

Ask the following during design and review:

  • What invariant are we protecting, and where is it enforced?
  • Which inputs are untrusted or incomplete at runtime?
  • What happens during retries, concurrency, cancellation or partial failure?
  • What evidence will appear in logs, metrics, traces or an audit history?
  • Can a new team member understand the decision without reconstructing months of context?

Mentoring conversation

Junior developer asks: “How do I know whether my solution is good enough?”

A useful answer is to test the reasoning at several levels. Does it represent the business rule accurately? Does it reject invalid input rather than silently reinterpret it? Is the main path easy to read? Can failures be diagnosed? Can the design evolve without changing unrelated code? Perfection is not required, but the trade-offs should be intentional and visible. Write a short decision note when the reason would otherwise disappear from the code.

Practical exercise

Take one feature from a system you know and write a one-page review of defining professional responsibility. Include the current behaviour, one problematic edge case, the proposed contract, a test matrix, security considerations, operational signals and a rollback approach. Then explain the proposal aloud in five minutes. Any part that is difficult to explain probably needs a clearer model rather than more code.

Bringing the Practices Together

The chapters in this guide are not independent boxes to tick. They form a feedback loop: understand the real outcome, model it honestly, implement a narrow slice, verify behaviour, observe production evidence and use what you learn to improve the next decision. Mature engineering teams make that loop routine.

The recurring theme is accountability. Tools, frameworks and abstractions can accelerate work, but they cannot own the consequences. Engineers remain responsible for the assumptions encoded in software, the people affected by failure and the clarity with which future maintainers can reason about the system.

Use this guide selectively. Apply the most relevant chapter to the risk in front of you, capture the decision, and return after the feature has met real users. The goal is faster delivery without surrendering correctness, security, maintainability or professional judgement. That goal is achieved through disciplined practice, not through vocabulary alone.

Applied In

The thinking in this article has been applied throughout my enterprise portfolio, where architecture, workflows, permissions, notifications, reporting and modular design are all built around real business operations rather than isolated technical features.

View Continuous Learning →
Afzal Ahmed

Afzal Ahmed

Senior Full Stack Engineer & Technical Lead

A hands-on engineer with 15+ years in commercial software. I publish what I am studying, revising and testing so visitors can see both established experience and learning still in progress.

How would you approach this problem? I'd love to hear your thoughts or continue the discussion.

Connect on LinkedIn →