<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pankaj Batra</title>
    <description>The latest articles on DEV Community by Pankaj Batra (@pankaj_batra).</description>
    <link>https://dev.to/pankaj_batra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4026737%2F3c166e3d-7c37-4cbd-90f0-281ea0395598.gif</url>
      <title>DEV Community: Pankaj Batra</title>
      <link>https://dev.to/pankaj_batra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pankaj_batra"/>
    <language>en</language>
    <item>
      <title>Kafka for Engineers Who've Only Used REST: What Actually Changes</title>
      <dc:creator>Pankaj Batra</dc:creator>
      <pubDate>Sat, 01 Aug 2026 13:04:53 +0000</pubDate>
      <link>https://dev.to/pankaj_batra/kafka-for-engineers-whove-only-used-rest-what-actually-changes-32lb</link>
      <guid>https://dev.to/pankaj_batra/kafka-for-engineers-whove-only-used-rest-what-actually-changes-32lb</guid>
      <description>&lt;p&gt;When I first read that Kafka was a "distributed event streaming platform," I nodded, closed the tab, and went back to writing REST endpoints.&lt;/p&gt;

&lt;p&gt;It took me a while to realize the problem wasn't Kafka. It was that every explanation started with &lt;em&gt;what Kafka is&lt;/em&gt; and none of them started with &lt;em&gt;why it exists&lt;/em&gt;. If you already think about systems the way REST teaches you to, most Kafka tutorials feel like they're answering a question you didn't ask.&lt;/p&gt;

&lt;p&gt;This post is for engineers who've built REST APIs for years and want to understand Kafka the way it actually clicks — not the API, not the config, but the shift in what a system is supposed to be.&lt;/p&gt;

&lt;p&gt;The short version:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;REST is about asking. Kafka is about telling.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once that lands, everything else about Kafka stops feeling arbitrary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The REST mental model has a hidden assumption
&lt;/h2&gt;

&lt;p&gt;Every REST system assumes one thing that's so obvious it's almost invisible: &lt;strong&gt;the caller knows who to ask.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your mobile app knows to call the orders API. The orders API knows to call the payments API. The payments API knows to call the fraud service. Someone, somewhere, decided who talks to whom, and that decision is baked into the code.&lt;/p&gt;

&lt;p&gt;Consider an order being placed. In a typical REST setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The order service saves the order&lt;/li&gt;
&lt;li&gt;Then it calls the inventory service to decrement stock&lt;/li&gt;
&lt;li&gt;Then it calls the email service to send a confirmation&lt;/li&gt;
&lt;li&gt;Then it calls the analytics service to log the event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four services. Three couplings the order service has to know about. And when the business decides to add loyalty points on every order, you go back and edit the order service — again.&lt;/p&gt;

&lt;p&gt;You didn't do anything wrong. This is what REST tells you to do. But look at what's really happening: the order service is responsible for knowing every other service that cares about orders. That responsibility grows every time the business grows.&lt;/p&gt;

&lt;p&gt;That's the hidden assumption. In REST, &lt;em&gt;the sender is responsible for knowing all the receivers.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Kafka actually changes
&lt;/h2&gt;

&lt;p&gt;Kafka flips the direction.&lt;/p&gt;

&lt;p&gt;The order service no longer calls anyone. It writes a single fact to a log:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"order 1234 was placed."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then it's done.&lt;/p&gt;

&lt;p&gt;Inventory, email, analytics, loyalty — none of them are called. They read the log on their own schedule, notice a new order, and each one does whatever it does. The order service doesn't know they exist. It doesn't care.&lt;/p&gt;

&lt;p&gt;That's the whole idea.&lt;/p&gt;

&lt;p&gt;Everything else you'll ever read about Kafka — partitions, offsets, consumer groups, brokers, retention — exists to make that one shift work at scale.&lt;/p&gt;

&lt;p&gt;If you take nothing else from this post, take this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In REST, services &lt;strong&gt;call each other&lt;/strong&gt;. In Kafka, services &lt;strong&gt;publish facts and read facts&lt;/strong&gt;, and no one is called by name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Five things that stop feeling weird once the shift lands
&lt;/h2&gt;

&lt;p&gt;Once you accept the model, a bunch of things that look strange in Kafka tutorials suddenly make sense. Here are the five that tripped me up longest.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Kafka doesn't delete messages after they're read
&lt;/h3&gt;

&lt;p&gt;In a REST world, a response is consumed. Once your client got the JSON back, the server moves on. Message queues work similarly — pop a message off, process it, gone.&lt;/p&gt;

&lt;p&gt;Kafka doesn't do that. Messages sit in the log for as long as you tell it to keep them — days, weeks, forever if you want. The reason is baked into the model: a &lt;em&gt;fact&lt;/em&gt; doesn't stop being true just because one service noticed it.&lt;/p&gt;

&lt;p&gt;If analytics needs to reprocess the last week of orders, the events are still there. If you spin up a new service tomorrow that also cares about orders, it can read every order that ever happened.&lt;/p&gt;

&lt;p&gt;The log isn't a queue. It's a record of everything that occurred, and consumers get to decide when and how often they read from it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Consumers track their own position
&lt;/h3&gt;

&lt;p&gt;In REST, the server knows who called it. Requests are tracked, sessions exist, the server is the coordinator.&lt;/p&gt;

&lt;p&gt;In Kafka, the log has no idea who's reading. Each consumer is responsible for remembering where it is in the log — its &lt;em&gt;offset&lt;/em&gt;. If a consumer crashes and restarts, it reads its last saved offset and picks up from there. If you want a second copy of a service to also process every event, it just starts from offset zero and reads independently.&lt;/p&gt;

&lt;p&gt;This is why replay is trivial in Kafka and impossible in REST. Rewinding a REST call doesn't mean anything. Rewinding a Kafka offset means "read those events again."&lt;/p&gt;

&lt;h3&gt;
  
  
  3. You scale by adding partitions, not by adding servers per endpoint
&lt;/h3&gt;

&lt;p&gt;REST scales by putting a load balancer in front of your service and adding more instances behind it. Each request goes to whichever instance is free.&lt;/p&gt;

&lt;p&gt;Kafka scales by splitting the log itself. A topic isn't a single log — it's split into &lt;em&gt;partitions&lt;/em&gt;, and consumers coordinate to divide those partitions among themselves. If you have four partitions and four consumers in a group, each consumer handles one partition. Add a fifth consumer and one of them will sit idle, because a partition is only ever read by one consumer in a group at a time.&lt;/p&gt;

&lt;p&gt;This is a completely different scaling model, and it means the number of partitions you choose is a design decision that affects throughput for the life of the topic. It's not something you tune later without pain.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Order is only guaranteed within a partition
&lt;/h3&gt;

&lt;p&gt;REST doesn't really care about order. Each request is independent, and if you need ordering, you build it in the application layer.&lt;/p&gt;

&lt;p&gt;Kafka guarantees order — but only within a single partition. Across partitions, all bets are off. This means partitioning is a design choice you make based on what needs to stay ordered.&lt;/p&gt;

&lt;p&gt;If you partition orders by customer ID, all events for one customer stay in order. If you partition by timestamp or randomly, you'll see events for the same customer arrive out of sequence. The moment you choose a partition key, you've decided what "in order" means for that topic.&lt;/p&gt;

&lt;p&gt;Get this wrong and you'll ship a system where events arrive in an order that makes no sense to a human, and debugging it will feel like a nightmare until you notice what's happening.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. There's no "the server returned an error"
&lt;/h3&gt;

&lt;p&gt;In REST, errors have a shape. The server returns a 500, the client sees it, retries or gives up. Error handling lives in the request path.&lt;/p&gt;

&lt;p&gt;In Kafka, there's no server responding to your call. There's a log. If a consumer fails to process a message, the failure happens on the &lt;em&gt;consumer side&lt;/em&gt;, and the consumer has to decide what to do about it: retry, skip, log, or move the message to a dead-letter topic for someone to look at later.&lt;/p&gt;

&lt;p&gt;This moves error handling out of the request path entirely. You stop asking "what should I return when this fails?" and start asking "what should this consumer do when it can't process what it just read?" That's a different question, and it takes a while to get comfortable with.&lt;/p&gt;

&lt;h2&gt;
  
  
  When REST is still the right answer
&lt;/h2&gt;

&lt;p&gt;None of this makes REST obsolete. It's not supposed to.&lt;/p&gt;

&lt;p&gt;REST is still the right choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The caller needs an answer &lt;em&gt;now&lt;/em&gt; — an authorization check, a price lookup, a validation&lt;/li&gt;
&lt;li&gt;You're doing CRUD on a single resource&lt;/li&gt;
&lt;li&gt;The integration is between two systems, not many&lt;/li&gt;
&lt;li&gt;The caller genuinely does know who to ask, and that's not going to change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kafka is the right choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple systems care about the same event&lt;/li&gt;
&lt;li&gt;You want to be able to add new consumers later without touching the producer&lt;/li&gt;
&lt;li&gt;Events have value beyond the moment they happen — audit, replay, analytics, machine learning&lt;/li&gt;
&lt;li&gt;The coupling between services is starting to feel like the thing you spend most of your time maintaining&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most honest tell is this: &lt;strong&gt;if every new feature means adding another HTTP call from an existing service, you're probably ready for events.&lt;/strong&gt; That pattern doesn't scale — not technically, but organizationally. Every new integration means editing an old service, which means testing it, which means owning it.&lt;/p&gt;

&lt;p&gt;Events break that cycle. New consumer, no producer changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shift, restated
&lt;/h2&gt;

&lt;p&gt;Kafka doesn't replace REST. What it replaces is a specific habit — the habit of every service being responsible for knowing who to notify when something happens.&lt;/p&gt;

&lt;p&gt;Once producers only publish facts, and consumers only read what they care about, systems get easier to change. Not easier to build the first time — Kafka has real operational cost, and the mental model takes effort. But easier to &lt;em&gt;change&lt;/em&gt;, which is what actually matters after month three of any real system.&lt;/p&gt;

&lt;p&gt;The hardest part of learning Kafka isn't the API. It's letting go of the assumption that someone always has to be waiting for the answer.&lt;/p&gt;

&lt;p&gt;Once you accept that services can just publish facts into the world and stop caring who reads them, the rest of Kafka is just plumbing.&lt;/p&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;I'm &lt;strong&gt;Pankaj Batra&lt;/strong&gt;, a Software Engineer focused on Flutter, automation, and enterprise integrations.&lt;/p&gt;

&lt;p&gt;I write about practical engineering: mobile architecture, workflow automation, APIs, event-driven systems, and lessons from production systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portfolio: &lt;a href="https://pankajbatra.vercel.app" rel="noopener noreferrer"&gt;https://pankajbatra.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://linkedin.com/in/pankaj-batra-0a294a205" rel="noopener noreferrer"&gt;https://linkedin.com/in/pankaj-batra-0a294a205&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Pankaj0405" rel="noopener noreferrer"&gt;https://github.com/Pankaj0405&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, follow for more engineering notes.&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>architecture</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Server-Driven Survey Engine in Flutter Without a WebView</title>
      <dc:creator>Pankaj Batra</dc:creator>
      <pubDate>Tue, 21 Jul 2026 12:29:44 +0000</pubDate>
      <link>https://dev.to/pankaj_batra/building-a-server-driven-survey-engine-in-flutter-without-a-webview-4ch9</link>
      <guid>https://dev.to/pankaj_batra/building-a-server-driven-survey-engine-in-flutter-without-a-webview-4ch9</guid>
      <description>&lt;p&gt;This article was originally published on my Hashnode blog and is shared here for the Dev.to community.&lt;br&gt;
Enterprise apps often need forms that change without an app-store release.&lt;/p&gt;

&lt;p&gt;New questions appear. Visibility rules change. Validation logic evolves. Dropdown options come from remote services. Nested sections grow and shrink.&lt;/p&gt;

&lt;p&gt;If every one of those rules lives only in Flutter code, the mobile app becomes a second form engine — expensive to build and easy to drift from the web.&lt;/p&gt;

&lt;p&gt;This post is about a different approach: &lt;strong&gt;server-driven surveys rendered with native Flutter widgets&lt;/strong&gt;, while the &lt;strong&gt;form logic stays outside the UI layer&lt;/strong&gt; — and without wrapping everything in a WebView.&lt;/p&gt;

&lt;p&gt;I won’t walk through proprietary implementation details. I’ll share the &lt;strong&gt;design thinking&lt;/strong&gt;, the &lt;strong&gt;trade-offs&lt;/strong&gt;, and the &lt;strong&gt;lessons&lt;/strong&gt; that mattered most.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Challenge Isn’t UI
&lt;/h2&gt;

&lt;p&gt;Drawing text fields and dropdowns is the easy part.&lt;/p&gt;

&lt;p&gt;The hard part is keeping behavior consistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conditional visibility and enablement&lt;/li&gt;
&lt;li&gt;Validation and error messaging&lt;/li&gt;
&lt;li&gt;Calculated values and expressions&lt;/li&gt;
&lt;li&gt;Multi-step navigation&lt;/li&gt;
&lt;li&gt;Nested / repeating sections&lt;/li&gt;
&lt;li&gt;Remote option lists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the web, mature form libraries already solve much of this.&lt;/p&gt;

&lt;p&gt;On mobile, teams often choose one of three paths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rebuild the logic in Dart&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed a WebView&lt;/strong&gt; and reuse the web form
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid model&lt;/strong&gt; — native UI, shared logic engine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We chose the third.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Avoid a WebView?
&lt;/h2&gt;

&lt;p&gt;WebViews are fast to ship, but they come with costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavier memory and less “native” feel&lt;/li&gt;
&lt;li&gt;Awkward integration with camera, files, signatures, and platform UX&lt;/li&gt;
&lt;li&gt;Harder theming consistency with the rest of the app&lt;/li&gt;
&lt;li&gt;Debugging that feels like maintaining two apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For production mobile UX, native widgets are usually worth the extra design work.&lt;/p&gt;

&lt;p&gt;The constraint we accepted:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The UI can be Flutter-native.&lt;br&gt;&lt;br&gt;
The &lt;strong&gt;meaning&lt;/strong&gt; of the form (rules, state, validity) should not be reinvented in Flutter.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Design Principle That Unlocked Everything
&lt;/h2&gt;

&lt;p&gt;The most important decision was ownership:&lt;/p&gt;

&lt;h3&gt;
  
  
  One layer owns form logic. Flutter owns presentation and device I/O.
&lt;/h3&gt;

&lt;p&gt;That means Flutter should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render what the logic layer says is currently visible&lt;/li&gt;
&lt;li&gt;Capture user input&lt;/li&gt;
&lt;li&gt;Handle device features (files, camera, signature, etc.)&lt;/li&gt;
&lt;li&gt;Apply theming and accessibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flutter should &lt;strong&gt;not&lt;/strong&gt; become the place where business rules are reimplemented “just for mobile.”&lt;/p&gt;

&lt;p&gt;This single rule prevents a class of bugs where mobile and web disagree about whether a field should appear, whether a value is valid, or what an expression means.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server-Driven UI, Practically
&lt;/h2&gt;

&lt;p&gt;In this model, the app receives a form definition (JSON) from the backend.&lt;/p&gt;

&lt;p&gt;That definition describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure (pages, panels, questions)&lt;/li&gt;
&lt;li&gt;Behavior (conditions, validators, expressions)&lt;/li&gt;
&lt;li&gt;Presentation hints (titles, layout flags, locales)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mobile client’s job is to &lt;strong&gt;interpret and render&lt;/strong&gt;, not to hardcode each form.&lt;/p&gt;

&lt;p&gt;That’s what “server-driven” means here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product can iterate forms without waiting for a Flutter release for every schema change&lt;/li&gt;
&lt;li&gt;Mobile stays aligned with the same logic model used elsewhere&lt;/li&gt;
&lt;li&gt;Engineering effort shifts from “build every form” to “build a reliable renderer”&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Made This Hard (Without the Internals)
&lt;/h2&gt;

&lt;p&gt;Hybrid systems fail in the seams — the places where two runtimes meet.&lt;/p&gt;

&lt;p&gt;A few categories of problems showed up repeatedly:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Nested structures break naive assumptions
&lt;/h3&gt;

&lt;p&gt;Top-level questions behave differently from questions nested inside repeating or dynamic containers.&lt;/p&gt;

&lt;p&gt;If your mental model is “look up a field by name and update it,” nested forms will eventually surprise you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; design for ownership and context early, not after the first nested bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Presentation flags are easy to misread
&lt;/h3&gt;

&lt;p&gt;A flag that hides a &lt;strong&gt;panel title&lt;/strong&gt; is not the same as hiding every child title.&lt;/p&gt;

&lt;p&gt;Some question types also have different title semantics than ordinary inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; match the upstream form engine’s meaning before inventing mobile-only rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Expression language has a strict shape
&lt;/h3&gt;

&lt;p&gt;Operators and functions are not interchangeable.&lt;/p&gt;

&lt;p&gt;A valid expression can look “almost right” and still fail because the syntax is interpreted differently than expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; when logic “doesn’t work,” verify expression form before assuming the mobile layer is broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Performance is a product of strategy, not just widgets
&lt;/h3&gt;

&lt;p&gt;Large forms stress:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;startup cost&lt;/li&gt;
&lt;li&gt;communication between UI and logic layers&lt;/li&gt;
&lt;li&gt;remote option loading on mobile networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fetching everything up front can feel simple and then become slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; measure separately — init cost, interaction cost, and network cost are different problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trade-offs We Accepted
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What you gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Native Flutter UX&lt;/li&gt;
&lt;li&gt;Stronger parity with an existing form logic ecosystem&lt;/li&gt;
&lt;li&gt;Faster iteration on form content from the server&lt;/li&gt;
&lt;li&gt;Cleaner separation between UI and rules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What you pay
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bridge complexity between runtimes&lt;/li&gt;
&lt;li&gt;More careful debugging across layers&lt;/li&gt;
&lt;li&gt;Constraints around what the logic runtime can do directly (especially without browser APIs)&lt;/li&gt;
&lt;li&gt;Ongoing discipline so Flutter doesn’t quietly reabsorb business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture is not “simpler.”&lt;br&gt;&lt;br&gt;
It is &lt;strong&gt;clearer&lt;/strong&gt; — if the ownership boundaries stay honest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Principles I’d Reuse on the Next Project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose a source of truth for form logic and protect it.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer native rendering when UX quality matters.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat nested forms as a first-class design problem.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t optimize everything on day one — instrument first.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproduce edge cases in demos&lt;/strong&gt; (nested sections, remote options, expression rules).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document decisions, not just features&lt;/strong&gt; — future you will need the “why.”&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building a server-driven survey experience in Flutter is less about clever widgets and more about &lt;strong&gt;boundary design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If Flutter owns too much logic, you rebuild a form engine.&lt;br&gt;&lt;br&gt;
If you lean only on WebView, you sacrifice native quality.&lt;br&gt;&lt;br&gt;
If you split responsibilities cleanly, you get something harder to build — and much easier to evolve.&lt;/p&gt;

&lt;p&gt;The goal isn’t to expose every internal mechanism publicly.&lt;/p&gt;

&lt;p&gt;The goal is to ship forms that stay correct as the business changes — without turning every schema update into a mobile release.&lt;/p&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;I'm &lt;strong&gt;Pankaj Batra&lt;/strong&gt;, a Software Engineer focused on Flutter, automation, and enterprise integrations.&lt;/p&gt;

&lt;p&gt;I write about practical engineering: mobile architecture, workflow automation, APIs, and lessons from production systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Portfolio: &lt;a href="https://pankajbatra.vercel.app" rel="noopener noreferrer"&gt;https://pankajbatra.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://linkedin.com/in/pankaj-batra-0a294a205" rel="noopener noreferrer"&gt;https://linkedin.com/in/pankaj-batra-0a294a205&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Pankaj0405" rel="noopener noreferrer"&gt;https://github.com/Pankaj0405&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, follow for more engineering notes.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>architecture</category>
      <category>javascript</category>
    </item>
    <item>
      <title>5 Power Automate Design Mistakes That Slow Down Your Flows (And How to Fix Them)</title>
      <dc:creator>Pankaj Batra</dc:creator>
      <pubDate>Mon, 13 Jul 2026 08:53:27 +0000</pubDate>
      <link>https://dev.to/pankaj_batra/5-power-automate-design-mistakes-that-slow-down-your-flows-and-how-to-fix-them-292f</link>
      <guid>https://dev.to/pankaj_batra/5-power-automate-design-mistakes-that-slow-down-your-flows-and-how-to-fix-them-292f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was originally published on my Hashnode blog and is shared here for the Dev.to community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Power Automate makes it incredibly easy to automate business processes.&lt;/p&gt;

&lt;p&gt;With just a few actions, you can connect Microsoft Forms, SharePoint, Outlook, Teams, SQL Server, and hundreds of other services—often without writing a single line of code.&lt;/p&gt;

&lt;p&gt;But as workflows grow, something interesting happens.&lt;/p&gt;

&lt;p&gt;The automation still works...&lt;/p&gt;

&lt;p&gt;...yet it becomes slower, harder to debug, and increasingly difficult to maintain.&lt;/p&gt;

&lt;p&gt;In many cases, the issue isn't Power Automate itself.&lt;/p&gt;

&lt;p&gt;It's the workflow design.&lt;/p&gt;

&lt;p&gt;Over the past few months, while working on enterprise automation solutions, I've noticed the same design patterns appearing repeatedly. Individually they may seem harmless, but together they can significantly impact performance, readability, and long-term maintainability.&lt;/p&gt;

&lt;p&gt;In this article, I'll share five common Power Automate design mistakes and practical ways to avoid them.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Flow Design Matters
&lt;/h1&gt;

&lt;p&gt;Unlike traditional code, Power Automate workflows are visual.&lt;/p&gt;

&lt;p&gt;That makes them incredibly easy to build.&lt;/p&gt;

&lt;p&gt;Unfortunately, it also makes it easy to introduce unnecessary actions, nested loops, duplicated logic, and expensive operations without realizing their long-term impact.&lt;/p&gt;

&lt;p&gt;As workflows become more complex, these small design decisions compound.&lt;/p&gt;

&lt;p&gt;A well-designed workflow provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🚀 Faster execution&lt;/li&gt;
&lt;li&gt;🐞 Easier debugging&lt;/li&gt;
&lt;li&gt;📈 Better scalability&lt;/li&gt;
&lt;li&gt;🧹 Simpler maintenance&lt;/li&gt;
&lt;li&gt;👥 Easier collaboration with other developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at five common mistakes.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Using "Apply to each" When You Don't Need It
&lt;/h1&gt;

&lt;p&gt;One of the most common performance issues is unnecessary &lt;strong&gt;Apply to each&lt;/strong&gt; loops.&lt;/p&gt;

&lt;p&gt;Power Automate automatically creates these loops whenever an action returns an array, even when you're expecting only a single item.&lt;/p&gt;

&lt;p&gt;Many developers simply leave the loop in place.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Get Items

↓

Apply to each

↓

Condition

↓

Update Item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works, every additional loop adds unnecessary processing and makes the flow harder to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Approach
&lt;/h2&gt;

&lt;p&gt;If your logic expects a single record, retrieve the first result instead of iterating through the collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Get Items

↓

First()

↓

Condition

↓

Update Item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Less processing&lt;/li&gt;
&lt;li&gt;Cleaner workflows&lt;/li&gt;
&lt;li&gt;Faster execution&lt;/li&gt;
&lt;li&gt;Easier debugging&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  2. Retrieving More Data Than Necessary
&lt;/h1&gt;

&lt;p&gt;Another common mistake is retrieving an entire SharePoint list and filtering the results afterward.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Get Items

↓

5000 Records

↓

Filter Array

↓

Find One Record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although functional, this forces Power Automate to process far more data than necessary.&lt;/p&gt;

&lt;p&gt;Instead, use &lt;strong&gt;OData Filter Queries&lt;/strong&gt; whenever possible.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Status eq 'Pending'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title eq 'Vendor A'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows SharePoint to perform the filtering before returning the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Less data transferred&lt;/li&gt;
&lt;li&gt;Faster execution&lt;/li&gt;
&lt;li&gt;Better scalability&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  3. Performing Duplicate Checks After Creating Records
&lt;/h1&gt;

&lt;p&gt;Another design pattern I occasionally see looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create Item

↓

Search for Duplicate

↓

Delete Duplicate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although functional, it performs unnecessary work.&lt;/p&gt;

&lt;p&gt;A cleaner approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search Existing Record

↓

Exists?

↓

Yes → Skip

↓

No → Create Item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prevents duplicate records&lt;/li&gt;
&lt;li&gt;Reduces unnecessary writes&lt;/li&gt;
&lt;li&gt;Improves performance&lt;/li&gt;
&lt;li&gt;Keeps data clean&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  4. Writing Extremely Complex Expressions
&lt;/h1&gt;

&lt;p&gt;Power Automate expressions are incredibly powerful.&lt;/p&gt;

&lt;p&gt;Functions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;split()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;concat()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coalesce()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;allow sophisticated transformations.&lt;/p&gt;

&lt;p&gt;The mistake is combining everything into one huge expression.&lt;/p&gt;

&lt;p&gt;Instead of writing something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;concat(
 split(...),
 if(...),
 body(...)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Break the logic into multiple &lt;strong&gt;Compose&lt;/strong&gt; actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compose – Format Date

↓

Compose – Customer Name

↓

Compose – Final Output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach makes workflows significantly easier to understand, debug, and maintain.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Never Looking at Flow History
&lt;/h1&gt;

&lt;p&gt;Many developers only check whether the flow succeeded.&lt;/p&gt;

&lt;p&gt;Flow History provides much more valuable information.&lt;/p&gt;

&lt;p&gt;It can help identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slow-running actions&lt;/li&gt;
&lt;li&gt;Retry attempts&lt;/li&gt;
&lt;li&gt;Connector latency&lt;/li&gt;
&lt;li&gt;Failed expressions&lt;/li&gt;
&lt;li&gt;Workflow bottlenecks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reviewing Flow History regularly often reveals optimization opportunities that aren't obvious while building the workflow.&lt;/p&gt;




&lt;h1&gt;
  
  
  Best Practices I Follow
&lt;/h1&gt;

&lt;p&gt;Whenever I build a Power Automate workflow, I try to follow a few simple principles.&lt;/p&gt;

&lt;p&gt;✅ Keep workflows as linear as possible.&lt;/p&gt;

&lt;p&gt;✅ Filter data before retrieving it.&lt;/p&gt;

&lt;p&gt;✅ Avoid unnecessary loops.&lt;/p&gt;

&lt;p&gt;✅ Break complex logic into smaller Compose actions.&lt;/p&gt;

&lt;p&gt;✅ Prevent duplicate records before writing data.&lt;/p&gt;

&lt;p&gt;✅ Review Flow History regularly.&lt;/p&gt;

&lt;p&gt;Small improvements made early can dramatically improve maintainability as workflows evolve.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;Power Automate makes automation accessible to everyone.&lt;/p&gt;

&lt;p&gt;Designing workflows that remain clean, scalable, and performant as they grow is a different skill.&lt;/p&gt;

&lt;p&gt;Most performance improvements don't come from changing connectors.&lt;/p&gt;

&lt;p&gt;They come from making better design decisions.&lt;/p&gt;

&lt;p&gt;A well-structured workflow is easier to understand, easier to debug, and much more reliable as business requirements evolve.&lt;/p&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Hi, I'm &lt;strong&gt;Pankaj Batra&lt;/strong&gt;, a Software Engineer focused on building scalable software, automation solutions, and enterprise integrations.&lt;/p&gt;

&lt;p&gt;I regularly write about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Power Automate &amp;amp; Workflow Automation&lt;/li&gt;
&lt;li&gt;📱 Flutter &amp;amp; Mobile Development&lt;/li&gt;
&lt;li&gt;🐍 Python &amp;amp; Backend Development&lt;/li&gt;
&lt;li&gt;🔗 REST APIs &amp;amp; System Integrations&lt;/li&gt;
&lt;li&gt;🏗️ Software Architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connect with me
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🌐 Portfolio: &lt;a href="https://pankajbatra.vercel.app" rel="noopener noreferrer"&gt;https://pankajbatra.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💼 LinkedIn: &lt;a href="https://linkedin.com/in/pankaj-batra-0a294a205" rel="noopener noreferrer"&gt;https://linkedin.com/in/pankaj-batra-0a294a205&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 GitHub: &lt;a href="https://github.com/Pankaj0405" rel="noopener noreferrer"&gt;https://github.com/Pankaj0405&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found this article helpful, consider following me for more practical software engineering content.&lt;/p&gt;

</description>
      <category>powerautomate</category>
      <category>sharepoint</category>
      <category>automation</category>
      <category>microsoft</category>
    </item>
  </channel>
</rss>
