As a software consultancy, we often find ourselves in a position where we do not own both the Frontend and Backend sides of a project. In cases where we depend on an independent infrastructure that we cannot modify, we are effectively forced to build our Frontend defensively to ensure a resilient user experience and create a good security net to protect them.
1. The API contract and the power of mocking
Time means money for our clients, and we won't lay down waiting for the Backend to be finished. High-quality engineers don't wait for the Backend to be "ready", there are plenty of ways to start the Frontend once the API contract is settled.
- Define the Contract Early: Before writing UI logic, properly define the API contract, including endpoints, request bodies, and exact response shapes.
- Start with Mock Data: By using the defined contract to create mocked responses (ideally on the backend side) you can build the entire Frontend flow in isolation.
- Building a Security Net: The provided Backend may not be as resilient as we wish. Even so, we must add value by using ternaries or "if" statements to prevent the Frontend from crashing, effectively building a strong security net.
- Consultative Reporting: Even if it is not your responsibility, document improvement ideas for the Backend and show your project manager and client a willingness to improve by reporting what needs to be addressed on their side. Prove that we are aware and not only care about our delivery.
2. Feature flags over release branches
In modern development, long-lived release branches are a liability. They accumulate merge conflicts that become difficult to solve and delay the delivery of value.
- Decouple Deployment from Release: Use Feature Flags to wrap new functionality. This allows you to merge code into the main branch daily without "releasing" it to users until it is fully tested.
- Avoid "Merge Hell": By integrating code frequently and hiding unfinished features behind toggles, you eliminate the technical debt associated with massive, obsolete release branches.
- Targeted Rollouts: Feature flags enable you to enable functionality for specific users or environments, providing a safety net if a bug is discovered in production.
3. Architecting for the "Unhappy path"
A static design only shows the "Happy Path" but a defensive engineer writes code for when things go wrong.
- Explicit Loading States: Never leave a user in the dark, every API call must have a corresponding loading state, skeleton, or spinner to manage expectations. Maybe you need to fake the loading state for cached responses, if this helps the user experience, then go ahead.
- Meaningful Error Handling: Specify good error messages instead of an "Unknown error". If possible, ask for translation keys to be sent from the backend side, even for single-language sites, to ensure clarity and potential translations and project scaling in the short or long term.
- Graceful Failure: Build your frontend to handle failed API calls or lost internet connections defensively. Ensure the app doesn't crash and provides a clear path for the user to "try again". Avoid that embarrassing "Shame on you" moment of a blank page or an uncontrolled 500.
- Parameter Integrity: Always validate or sanitize URL parameters, assume that a user might manually modify them to test the limits of your application.
4. Technical security and visibility
Defensive engineering also means protecting the application and making its status clear.
- Endpoint Security: Always question if an endpoint should be public or if it requires stricter authorization gates.
- Authentication Clarity: Never expose API keys or tokens. Clarify how the authentication process works and determine how often the JWT expires or if there are permissions or exceptions for certain users to build accordingly.
- Logic Placement: Differentiate and question what should be done in the Frontend versus the Backend, keeping business logic on the Backend whenever possible.
By prioritizing API contracts, leveraging Feature Flags, and obsessing over "unhappy path" scenarios, we ensure that the final product is not just a visual match to the design, but a technically superior tool built to last.