Key Lessons I Learned as a Backend Developer Building Apps: Tips for Backend and Frontend Success
- Neeraj

- Aug 20
- 8 min read

What you’ll get from this blog:
From Backend Developer to App Builder: Lessons I Learned with SwiftUIKey insights on UX, State management, Performance, and app development for backend engineers exploring mobile apps.
Topics covered in this blog :
Intro: From APIs to Apps
User Experience (UX) and Interface Design Take Center Stage
API Contract is a UX feature
State Management and Client-Side Logic
Performance Optimization for Devices
Cross-Platform vs Native Decisions
Security and Privacy on the Client Side
Error Handling is UI Design
Deployment, Updates, and App Store Realities
Mindset Shift: From Logic to Empathy
I am not demeaning any of the backend developers with this blog, I am a Backend Developer from past 10 years and will always be a backend developer. But thinking for a whole will help us make better backend developers. Learning the constraints of peer teams will help us code better, secure, and robust platforms.
1. Intro: From APIs to Apps
As a backend developer, I thought users never ‘saw’ my work. Then SwiftUI taught me otherwise. When you develop APIs, and think about the performance, you rarely visualize. The visualisation comes when you start developing apps. A 200ms and a 400ms reponse doesn’t look much different in Postman or Insomnia or Httpie or whatever you use. On the screen, its noticeable. So when we put efforts in optimizing an API response, yes our work is visible and we make world a little more convenient.
2. User Experience (UX) and Interface Design Take Center Stage
A contract shared before the development cycle should be carefully understood and worked upon. It should be more clearly worked upon by a backend developer, as users only see the UX. In one of my previous companies, a feature broke everything due to lack of documentation (may be a topic for another day, let me know in comments). The Async call was not clearly async like all the product managers and developers are telling me. It was an sync call, and FE developer developed the feature based on the contract first and then changed it based on the API response. When I joined the team, I was the oldest developer in the team as everyone before me had left. I noticed this, I tried to fix the feature and everything broke. The reason, API contract was not thought upon and a Backend mistake unfortunately broke the whole page. We had to ask the FE team to fix it for us again. Twice the work for them sadly.
A backend mindset is always success = valid response.App developer mindset is success = screen feels smooth, intuitive, delightful
3. The API Contract is a UX Feature
So, as explained above, API contract should not always be a UX feature, but mutual work. The other way is also not correct when Backend creates and shares the contract with the App team.
4. State Management and Client-Side Logic
As backend developers, we often assume API clients are just dumb data consumers. We send data; they display it. Simple.
Then SwiftUI hits you with a reality check: state is the beating heart of an app.
In SwiftUI, everything revolves around state — whether it’s @State, @ObservedObject, or @EnvironmentObject. The UI isn’t just a passive canvas. It reacts to every tiny state change. And suddenly, the backend isn’t just delivering data; it’s shaping how state lives, updates, and conflicts on the client.
How API Response Design Affects State
A messy API leads to messy state. If your API returns unpredictable field names, nullable chaos, or deeply nested objects, the SwiftUI developer ends up with a jungle of if let checks and brittle bindings, resulting in bad design due to Backend’s impact.
For example:
if response.status == "active" { userState = .active} else if response.status == "inactive" { userState = .inactive} else if response.status == "error" { print("WTH this developer is doing. DIE you mf DIE.") userState = .unknown} else { userState = .unknown}A cleaner API design (with enums or strict contracts) directly translates into simpler SwiftUI state management:
userState = UserState(rawValue: response.status) ?? .unknownWhat looks like a “small” backend decision becomes a huge deal when your state updates drive the entire UI.
Sync Conflicts Between Server State and Local State
Here’s another backend blind spot: data isn’t always in sync.
As a backend developer, you might assume the server is always the source of truth. But in SwiftUI, users can change data locally while offline, edit drafts, or modify preferences before syncing back. This means: Conflicts.
Last-write-wins isn’t always acceptable. APIs should provide timestamps, versioning, or conflict-resolution hints. I real life, I have seen teams using patches like API calls caching and favoring API call race.
Offline Mode as a State Problem
For backend engineers, offline mode feels like a networking problem. For SwiftUI developers, it’s a state management nightmare. Imagine you’re drafting a note in an app:
In backend world: “We’ll retry the API call when the network’s back.”
In app world: “The note still has to exist in state. The UI must show it. It must survive app restarts. And when we reconnect, the state must reconcile with the server.”
Offline-first thinking changes how you design APIs. Instead of assuming “always online,” you need:
— Delta updates (send only changes, not full payloads). — Conflict resolution strategies. — APIs that support “resume from checkpoint” semantics.
I have seen multiple request problem from low network areas and client was slapped with multiple transactions. We ended up fixing it at both the places, FE as well as BE. But this could have been avoided at FE itself. So more efforts are needed in designing a form or a button.
The lesson: State isn’t just a frontend problem. The way you design your backend directly shapes whether SwiftUI developers can manage state elegantly or wrestle with it endlessly. Backend devs don’t just send data — they decide how well the app can breathe.
5. Performance Optimization for Devices
It is very easy for a backend developer. When we are struggling with an optimization problem in the real world, the shortest thing a team can come up with is, do a infra level fix. We think for a horizontal and vertical scale of an app/web service.
Also, I remember we were sending huge responses to the App team when they asked for 4 fields. We used to think, Why can’t they just extract the fields they need and leave out the rest? The lesson after I started SwiftUI development, Don’t ship 2MB JSON when 5 fields will do.
For App developers, they need to think about the bound constraints if a device. The app should seamlessly run on a 4GB RAM device and a 1GB RAM device too. They need to manage battery drain, animations at 60 FPS, network calls that don’t freeze UI. Lessons for an App developer, remember the Pre-fetch vs lazy-load tradeoffs, Local caching vs live queries.
6. Cross-Platform vs Native Decisions
As backend developers, we’re wired to love abstraction. We see duplication and immediately think: “There must be a better way!” One codebase, one logic layer, one solution that works everywhere.
But when you step into the app world, you quickly realize: abstraction isn’t free.
SwiftUI vs Flutter/React Native
SwiftUI gives you deep integration with the Apple ecosystem — smooth animations, direct access to native APIs, and a design language that feels right at home on iOS. The trade-off? You’re locked into Apple’s ecosystem. No Android, no Windows, no Linux.
On the other hand, frameworks like Flutter or React Native promise cross-platform reach. Build once, deploy everywhere. Sounds great… until you hit the edges:
Performance quirks (especially on older devices).
Limited access to native features without plugins.
UI that feels “almost native” but not quite.
This is where backend empathy comes in: the choice isn’t always about “the best technology.” It’s about the best trade-off for the business.
Time-to-Market vs Pure Performance
This is debatable. Every developer loves to choose the tech-stack they work on. But sometimes the decision is not to build better but build fast. A backend developer might say:
“Why not just build native? It’s cleaner, faster, and more reliable.”
But app developers (and some product managers) live with reality:
Startups need to ship fast, not perfect. Competition is everywhere.
Budgets rarely allow two fully separate teams for iOS and Android.
Sometimes, 90% performance with 2x reach is a smarter business call.
It’s not about being lazy or choosing a “less optimal” solution. It’s about balancing engineering purity with business reality.
Backend developers should respect that technology choices are often trade-offs, not absolutes. Just like we choose between SQL and NoSQL depending on context, app teams choose between native and cross-platform depending on deadlines, budgets, and user needs.
7. Security and Privacy on the Client Side
For backend, we have a single bottleneck for security breach, the gateway, if we are on the cloud. Other machines and products are not exposed to public. We’re secure if the DB is encrypted. We are secure if credentials are stored in Secret Managers.
On the other hand, devices is hostile territory. The token is to be stored in the devices used by general public. People sometimes acts careless when the topic is security. The decisions like Secure storage (Keychain vs plain storage) needs to be taken care. If multiple people use same devices, security is hampered rightaway.
We both need to take care of the data minimization techniques. Only send what’s needed (GDPR, privacy laws) instead of bulk responses in order to save backend effort.
8. Error Handling = UI Design
This is a nightmare if we are designing thinking of a particular device in mind. For backend, the responses are never device dependents. A JSON response with same query parameters will always look same for a particular request (Unless you change the data at the persistence layer 😛 )
One missing field from an OK-Success 200 response and app starts seeing a blank screen, right?
App teams are platform and device dependent. A screen on a 5.5in device with iOS 12 might look different from a 6.7in device with iOS 18. The testing needs to be rigorous. One cannot develop a UI View for a specific device in mind. The screens should be responsive enough to work on any size and any future OS.
Backend logs are never enough, as they only capture the API failures. One needs in-app crash reporting (Firebase, Sentry) and User click events (CleverTap) to find out what’s wrong.
OS version also needs to be considered as some feature for OS version might not be backward compatible for the older devices.
9. Deployment, Updates, and App Store Realities
This is where the empathy really started. I submitted the app on the App store and it got rejected after 5 days. Reason, I made a mistake in the description mentioning “testing” and they asked me to release it internally for Test Flight. It was a release and one small mistake screwed me.
Backend deployments were never like these. With CI/CD in place, one PR merge will take our features to production instantly. If we are improving on a feature with same API calls, all users will get the update right away. No wait, no updates needed.
For App teams, they wait for the Store teams (Play store/App Store) to approve their changes, and then wait for the users to update the apps, it takes forever (At least it feels like forever 😃 ).
10. Mindset Shift: From Logic to Empathy
I just wanted to end this with an apology for thinking that App development is just moving fields and buttons here and there. If the UI is clean, their work is done. It takes a village right?
We need collaborations of everyone in the team and one incompetence can break everything every one ever worked for.
Backend = logic, efficiency, correctness.
Apps = empathy, timing, psychology, “how does this feel in the user’s hand?”
Devops = cost saving, speed, security and resilience.
For all backend developers, write an app once. You’ll never design an API the same way again. The performance will improve drastically.




Comments