ИТ развој

Stop Chasing AI Trends, Build Indispensable Systems Instead

Престанете да бркате трендови во вештачката интелигенција, наместо тоа изградете незаменливи системи

The easiest way to make a software team feel busy is to keep it chasing AI trends. Every week brings a new model, framework, agent pattern, or prompt technique that seems capable of transforming the product overnight.

Some of those tools will matter. Many will be useful in narrow places. But the systems that make a business dependable are rarely the flashy ones. They are the boringly essential parts: the API that behaves predictably, the database that preserves truth, the job queue that recovers from failure, and the deployment process that does not turn a small change into an incident.

For backend engineers, the strategic question is not “How can we add AI?” It is “What would make this system more indispensable to the people and processes that rely on it?”

Indispensable beats impressive

An impressive demo can summarize a document, classify a support request, or generate a draft response. An indispensable system can accept an order exactly once, reconcile payment state, retain an audit trail, notify the right people, and remain understandable six months later.

That distinction matters because production systems live under conditions that demos avoid: incomplete data, duplicate requests, slow dependencies, expired credentials, partial outages, concurrent writes, and human mistakes.

AI can improve a workflow, but it does not remove these engineering realities. In fact, adding an AI service often makes them more important. A model call can time out. Its output can be malformed. A provider can enforce limits. Sensitive data may require careful handling. The surrounding system must still be accountable.

Start with the constraint that costs the most

Before choosing a new tool, identify the constraint that is actually slowing the product or its users. This usually requires following a workflow from beginning to end rather than optimizing an isolated endpoint.

Consider a PHP application that processes customer uploads. The visible request might be fast, but the business workflow could still be slow because files are scanned synchronously, metadata is inconsistent, retries create duplicates, and operations staff cannot see why a job failed.

Adding an AI classifier may be valuable later. First, make the workflow reliable:

  • Store an immutable record of the upload and its processing state.
  • Move long-running work to a queue.
  • Give each job an idempotency key so retries do not repeat side effects.
  • Record structured failure information that people can investigate.
  • Expose a clear status API for the user interface and support team.

Once those foundations exist, an AI classifier can become a replaceable step in a durable pipeline rather than a fragile feature embedded in a controller.

Design APIs for failure, not just success

Backend code often looks cleanest on the happy path. The real quality of an API appears when clients retry, requests arrive out of order, or a downstream service is unavailable.

For operations that create external side effects, use an idempotency key. A client can safely retry a request after a network failure, while the server returns the result of the original operation instead of creating another record.

public function createInvoice(Request $request): JsonResponse
{
    $key = $request->header('Idempotency-Key');

    if (!$key) {
        return response()->json([
            'error' => 'Idempotency-Key header is required',
        ], 400);
    }

    $existing = InvoiceRequest::where('key', $key)->first();

    if ($existing) {
        return response()->json($existing->response_payload, 200);
    }

    // Persist the request key before triggering external side effects.
    // Use a database constraint on key to handle concurrent requests.

    // Create the invoice, persist the response, then return it.
}

The comment about a database constraint is not a detail to skip. An application-level lookup alone can race when two identical requests arrive together. A unique index turns the desired rule into a property the database enforces.

The same mindset applies to webhooks. Verify authenticity, persist the event identifier, reject or ignore duplicates safely, and process the event asynchronously where appropriate. A webhook endpoint should be able to receive the same event more than once without corrupting state.

Let the database protect business truth

Application code expresses intent; the database should protect invariants. If an email address must be unique, enforce it with a unique constraint. If a record must reference an existing account, use a foreign key when the architecture permits it. If money values require exact arithmetic, choose an appropriate fixed-precision representation instead of relying on floating-point calculations.

Indexes should follow real query patterns, not intuition. Start by examining the queries that matter: common filters, joins, ordering, and pagination. Then validate the query plan in the environment closest to production that is safely available.

Pagination deserves particular care. Offset pagination is easy to implement but can become expensive for large offsets and may shift while new rows are inserted. For time-ordered, high-volume feeds, cursor-based pagination can offer more stable behavior when backed by a deterministic ordering and a suitable index.

Containers should simplify operations

Docker is valuable when it makes local development, testing, and deployment more consistent. It is less valuable when it adds a layer of ceremony no one can debug.

A pragmatic PHP container setup typically separates responsibilities: an application image, a web server or runtime layer as needed, and external services such as a database or queue managed through explicit configuration. Keep images reproducible, avoid putting secrets into images, and make runtime configuration visible through environment variables or a managed secret mechanism.

The goal is not to make every environment identical in every detail. The goal is to make important differences intentional and documented. A developer should be able to answer basic operational questions quickly: which image is running, which configuration version it uses, where logs go, and how a failed deployment is rolled back.

Measure before tuning

Performance work becomes expensive when teams optimize based on feeling. Begin with a concrete symptom: a slow endpoint, queue backlog, database saturation, memory growth, or a costly third-party call.

Then trace the path. Is the application issuing repeated queries? Is a missing index forcing a large scan? Is serialization producing an oversized response? Is a worker blocked on a remote dependency? Is a cache hiding a correctness problem rather than solving a load problem?

Caching is powerful, but every cache creates an invalidation and freshness policy. Define those policies before adding the cache. Know what happens on a miss, how stale data is handled, and whether an outage in the cache should make the core workflow unavailable.

Make change inexpensive and safe

Maintainability is not an aesthetic preference. It determines how quickly a team can respond when requirements, traffic, or failures change.

Keep boundaries clear. Controllers should translate HTTP concerns, application services should coordinate use cases, and infrastructure code should isolate databases, queues, and third-party APIs. The exact pattern matters less than avoiding a codebase where every layer knows everything about every other layer.

Prefer small, reversible releases. Use database migrations that tolerate mixed application versions during deployment. Add observability around new workflows before declaring them complete. Treat retries, timeouts, and rollback behavior as part of the feature rather than operational afterthoughts.

The most valuable system is not the one with the most fashionable components. It is the one people can trust with important work.

AI will continue to change what software can do. That is reason to improve your engineering judgment, not abandon it. Build systems with clear contracts, protected data, observable behavior, and recoverable failure paths. Then introduce new capabilities where they solve a real constraint.

Trends can attract attention. Indispensable systems earn dependency, trust, and longevity.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.