Umjetna inteligencija (UI)

Beyond the Draft: Architecting Software Systems That AI Can't Replace

Iznad nacrta: Arhitektura softverskih sustava koje AI ne može zamijeniti

AI can produce a plausible function, a tidy API client, or a first-pass test suite in seconds. That is useful. It is also easy to mistake for the hard part of software development.

The draft is rarely the system. A working system has boundaries, failure behavior, ownership, observability, security, operating costs, and a reason to exist. Those are the places where software work becomes architecture rather than text generation.

The most durable developer skill is not typing faster than a model. It is designing environments in which generated code can become trustworthy software.

The gap between code and a system

A model can suggest an implementation for “send an order confirmation.” A technical lead still has to answer the questions that make the feature real: What happens if the payment provider succeeds but the email service fails? Can the same event arrive twice? Which data is allowed in the message? How does support staff discover and repair a stuck order?

None of these questions is a minor detail. Together, they define the behavior users experience when conditions are imperfect—which is most of the time in production.

AI is strongest when the problem has a clear local shape: transform this data, implement this interface, explain this error, generate test cases from an established pattern. It becomes less reliable as hidden assumptions, competing constraints, and cross-team consequences increase.

That suggests a useful division of labor. Let AI accelerate drafts and exploration. Keep humans accountable for intent, tradeoffs, and acceptance criteria.

Design the constraints before generating the solution

Teams often get disappointing AI output because they ask for an answer before describing the system around it. “Build a webhook handler” is underspecified. A better request includes the contract, trust boundary, storage rules, retry behavior, and definition of success.

Before asking an assistant to generate code, establish a compact design brief:

  • Purpose: What user or business outcome is this component responsible for?
  • Inputs and outputs: Which contracts are stable, and who owns them?
  • Failure policy: Which errors can be retried, surfaced, ignored, or compensated?
  • Security boundary: What must be authenticated, authorized, redacted, or retained?
  • Operational signals: Which logs, metrics, traces, and alerts make failure visible?
  • Verification: What tests or review checks demonstrate that the behavior is correct?

This brief does not need to be a heavyweight document. It can be a short design note attached to a ticket or pull request. Its value is that it turns a vague prompt into an engineering problem with inspectable constraints.

Build for the unhappy path

Generated code commonly looks most convincing on the happy path. Mature systems earn trust through their response to duplicate requests, partial outages, stale data, malformed events, timeouts, and operator mistakes.

Consider a service that consumes a payment event and creates a fulfillment job. A naive implementation receives the event, inserts a record, and calls a downstream API. It may appear correct in a demo. In production, a timeout after the downstream service accepts the request creates uncertainty: retrying might create a duplicate shipment; not retrying might lose an order.

The architectural answer is not merely “add a retry.” It may require an idempotency key, durable recording of event processing, a queue or outbox pattern, bounded retry rules, and a way to investigate exceptions. AI can help write portions of those mechanisms, but it cannot decide the acceptable business outcome without being given the policy.

Make retries intentional

Retries should be tied to error classification. A temporary network failure may justify another attempt. Invalid input, missing authorization, or a violated business rule usually does not. Every retrying operation also needs a stable identity so that repeated delivery does not repeat the side effect.

event received
  - validate signature and schema
  - record event identity durably
  - if already completed, return success
  - perform or schedule the side effect
  - mark completion only after confirmation
  - route unresolved failures for investigation

This is not a universal implementation recipe. It is a way to force the questions that code generation alone tends to hide.

Treat AI output as untrusted input

The sensible default is not distrust of AI; it is the same discipline applied to any external contribution. Review it against the surrounding system, run it through existing quality gates, and inspect the assumptions it introduced.

That means asking practical questions during review:

  • Does the code match the domain language and existing contracts?
  • Does it preserve authorization and data-handling rules?
  • Does it handle cancellation, timeouts, and resource cleanup?
  • Are errors meaningful to callers and useful to operators?
  • Did it add a dependency, configuration value, or compatibility assumption that has not been evaluated?
  • Do tests cover behavior rather than merely the generated implementation?

AI-generated tests deserve the same scrutiny. Tests can make a change look safe while simply encoding the same mistaken assumption as the implementation. Strong tests focus on observable behavior, boundary conditions, and failure paths. Contract tests, integration tests, and a carefully chosen manual scenario often reveal more than a large number of shallow unit tests.

Use agents as bounded collaborators

Agentic workflows become useful when they have a narrow role, explicit permissions, and a verification loop. An agent can summarize a codebase area, propose a migration plan, prepare a draft pull request, classify support issues, or generate a release checklist. It should not silently become the authority for production changes.

A healthy workflow separates planning, execution, and approval. For example, an agent may inspect a defined repository area and produce a proposed change. Automated checks then run in an isolated environment. A human reviewer evaluates the diff, the risk, and the rollout plan. Production deployment remains governed by the team’s normal controls.

The key is preserving a clear answer to: who is accountable if this action is wrong? If the answer is “the agent,” the workflow has already lost an essential control.

Invest in the context AI cannot infer

The better your engineering environment, the more valuable AI becomes. Clear architecture records, current runbooks, well-named domain types, stable interfaces, examples of good tests, and reliable automated checks give both people and models useful context.

This is an overlooked benefit of AI adoption: it exposes where organizational knowledge is trapped in memory or scattered across old conversations. If an assistant cannot determine the expected behavior from the repository and documentation, a new teammate probably cannot either.

Use that friction as a signal. Improve the system’s legibility instead of repeatedly compensating with longer prompts.

The work beyond the draft

AI will continue to make implementation faster and cheaper. That does not make software architecture less important; it makes architectural judgment more visible. When code is abundant, the scarce resource is confidence that the code belongs in the system and behaves safely after deployment.

The developers who remain essential will be the ones who can frame problems precisely, expose tradeoffs, design resilient boundaries, and create feedback loops that catch errors early. They will not compete with AI by producing more text. They will use it to spend more of their attention on the work that turns a draft into software people can depend on.

Portret autora bloga

Mihajlo

Ja sam Mihajlo — programer vođen znatiželjom, disciplinom i stalnom željom da stvorim nešto smisleno. Dijelim uvide, tutorijale i besplatne usluge kako bih pomogao drugima da pojednostave svoj rad i rastu u svijetu softvera i umjetne inteligencije koji se neprestano razvija.