<?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: Alona Fadieieva</title>
    <description>The latest articles on DEV Community by Alona Fadieieva (@fadieiev_a).</description>
    <link>https://dev.to/fadieiev_a</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%2F4073337%2F103e48f2-a6f5-4f00-abaa-b0539974b3e7.png</url>
      <title>DEV Community: Alona Fadieieva</title>
      <link>https://dev.to/fadieiev_a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fadieiev_a"/>
    <language>en</language>
    <item>
      <title>Seven Technical Checks Before You Hire a Flutter Team</title>
      <dc:creator>Alona Fadieieva</dc:creator>
      <pubDate>Tue, 11 Aug 2026 15:16:51 +0000</pubDate>
      <link>https://dev.to/fadieiev_a/seven-technical-checks-before-you-hire-a-flutter-team-55bo</link>
      <guid>https://dev.to/fadieiev_a/seven-technical-checks-before-you-hire-a-flutter-team-55bo</guid>
      <description>&lt;p&gt;Most "how to pick a dev agency" advice is unfalsifiable. Check their portfolio. Look at reviews. Make sure communication is good. None of it distinguishes a team that has shipped hard Flutter work from a team that finished a course.&lt;/p&gt;

&lt;p&gt;The checks below are technical and they have wrong answers. They come out of running a Flutter-only shop since 2019 — the longer, buyer-oriented version of this lives on &lt;a href="https://hotshotslabs.com/best-flutter-app-development-companies-europe/" rel="noopener noreferrer"&gt;our blog&lt;/a&gt;, including a breakdown of European Flutter companies. This post is the engineering half: what to actually ask, and what a weak answer sounds like.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. How do they cross the platform boundary?
&lt;/h2&gt;

&lt;p&gt;This is where cross-platform projects fail, and it's the fastest way to find the bottom of someone's Flutter knowledge. Anything touching platform APIs — Bluetooth, camera hardware, background execution, biometrics, health data — leaves Dart.&lt;/p&gt;

&lt;p&gt;A team that's done this will talk about &lt;code&gt;MethodChannel&lt;/code&gt; and &lt;code&gt;EventChannel&lt;/code&gt; fluently, and will usually tell you they've moved to Pigeon for anything non-trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The raw approach — fine for one or two calls&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BatteryService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;_channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'com.example.app/battery'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getBatteryLevel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invokeMethod&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;'getBatteryLevel'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;on&lt;/span&gt; &lt;span class="n"&gt;PlatformException&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Battery channel failed: &lt;/span&gt;&lt;span class="si"&gt;${e.code}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;error:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to listen for. First, does the error path exist? &lt;code&gt;PlatformException&lt;/code&gt; is not optional — a channel call fails differently on each platform, and a team that hasn't hit that hasn't shipped. Second, at what point do they stop hand-writing channels?&lt;/p&gt;

&lt;p&gt;The answer should be Pigeon. Hand-rolled &lt;code&gt;invokeMethod&lt;/code&gt; calls are stringly-typed on both sides of the boundary: rename a method in Kotlin and Dart finds out at runtime, in production. Pigeon generates typed bindings from a Dart schema, so the mismatch becomes a compile error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pigeons/battery_api.dart&lt;/span&gt;
&lt;span class="nd"&gt;@HostApi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BatteryApi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;getBatteryLevel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isCharging&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For continuous native data — sensor streams, BLE characteristic notifications — the equivalent question is &lt;code&gt;EventChannel&lt;/code&gt; and how they handle the subscription lifecycle. Streams that don't get cancelled on dispose are a common source of leaks in apps that talk to hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak answer:&lt;/strong&gt; "Flutter handles the native side." It doesn't. It gives you a well-designed way to write the native side yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What's their SDK version policy?
&lt;/h2&gt;

&lt;p&gt;Google ships four Flutter and four Dart releases a year. A team several versions behind is accumulating migration debt that transfers to you at handover, and the cost isn't linear — skipping four releases is worse than four times skipping one, because breaking changes compound and the migration guides assume you're stepping through.&lt;/p&gt;

&lt;p&gt;Ask to see a &lt;code&gt;pubspec.yaml&lt;/code&gt; from a current project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.12.0&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=3.44.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask how they decide when to upgrade. Good answers involve a stated cadence and a regression suite. Bad answers involve "when a client asks" or "when something breaks."&lt;/p&gt;

&lt;p&gt;The related question is dependency hygiene. Running this on a real project tells you more in ten seconds than an hour of discussion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub outdated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A long tail of abandoned packages pinned to old constraints is how projects become unupgradeable. Ask what their policy is on adding a dependency — teams with judgment have one, usually some version of "if it's under 200 lines, we write it."&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Impeller, and whether they know why it matters
&lt;/h2&gt;

&lt;p&gt;Impeller replaced Skia as the renderer, became the Android default during 2025, and completed its rollout with Flutter 3.44 in 2026. The reason it exists is shader compilation jank: Skia compiled shaders at runtime, so the first time an animation ran you'd drop frames. Impeller precompiles.&lt;/p&gt;

&lt;p&gt;Why this is a useful question: it's a topic where surface knowledge and real knowledge sound different. A team that's debugged jank will talk about specific profiling work — &lt;code&gt;flutter run --profile&lt;/code&gt;, the timeline view in DevTools, raster thread vs UI thread. A team that read the release notes will say Impeller made things faster.&lt;/p&gt;

&lt;p&gt;Follow-up worth asking: what do they do when the raster thread is the bottleneck versus the UI thread? These have completely different fixes, and conflating them is the single most common performance mistake in Flutter.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. State management — and whether they're dogmatic about it
&lt;/h2&gt;

&lt;p&gt;There's no correct answer to "Riverpod or Bloc or signals." There is a wrong answer, which is a team that can only work in one and will architect your product around that constraint regardless of fit.&lt;/p&gt;

&lt;p&gt;What you want to hear is reasoning about scope: what's ephemeral widget state that belongs in a &lt;code&gt;StatefulWidget&lt;/code&gt;, what's shared application state, and where the boundary sits between state management and the data layer. A team that reaches for a global store to hold a text field's contents is telling you something.&lt;/p&gt;

&lt;p&gt;The more revealing question is testing. Ask what proportion of their state logic is testable without a widget tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'cart total recalculates on quantity change'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CartNotifier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;priceCents:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nl"&gt;quantity:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totalCents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If business logic can only be tested by pumping widgets, it's in the wrong layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Release engineering
&lt;/h2&gt;

&lt;p&gt;Flutter's build story has more moving parts than it looks: flavors, signing, per-platform entitlements, and now Swift Package Manager as the iOS default rather than CocoaPods. Ask what happens between "merged to main" and "on a device."&lt;/p&gt;

&lt;p&gt;Concrete things to probe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flavors.&lt;/strong&gt; Dev, staging, and production as real build configurations, not a &lt;code&gt;const bool isProd&lt;/code&gt; in a Dart file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI.&lt;/strong&gt; Are builds reproducible on a clean machine, or does the release depend on one developer's laptop?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing and provisioning.&lt;/strong&gt; Who holds the keys, and what happens when the person who set it up is on holiday?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store submission.&lt;/strong&gt; Ask about the last rejection they got and how they resolved it. Everyone gets rejected; teams that ship a lot have specific stories.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obfuscation is worth asking about too, both for binary size and because it forces the question of whether symbolicated crash reporting is wired up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter build appbundle &lt;span class="nt"&gt;--obfuscate&lt;/span&gt; &lt;span class="nt"&gt;--split-debug-info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;build/symbols
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An obfuscated release without uploaded symbol files means every production crash is unreadable.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Where the data goes — as an architecture question
&lt;/h2&gt;

&lt;p&gt;This usually gets filed under legal, but it's an engineering constraint that shapes the app.&lt;/p&gt;

&lt;p&gt;Under GDPR Chapter V, transfers of personal data outside the EEA need safeguards, and a US cloud provider's "EU region" doesn't remove US jurisdiction under the CLOUD Act. The part that catches Flutter teams specifically: if your app calls a non-EU model endpoint, each call is processing, even when nothing persists server-side. Storing locally doesn't make the inference call disappear.&lt;/p&gt;

&lt;p&gt;The architectural consequences are real. On-device inference means a bundled model, size budgets, and a different update story. EU-hosted infrastructure means picking providers before you write the data layer, not after. Ask a candidate team where user data sits while the app runs and where it's processed — they're different questions, and a team that treats them as one hasn't dealt with it.&lt;/p&gt;

&lt;p&gt;Worth noting for anyone planning around the EU AI Act: the high-risk obligations that were due August 2, 2026 were deferred by the Digital Omnibus to December 2, 2027 for Annex III systems and August 2, 2028 for Annex I. Article 50 transparency duties were &lt;strong&gt;not&lt;/strong&gt; deferred and are live now. If your app has a chatbot or generates synthetic media, those disclosure obligations already apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Where they draw the AI line
&lt;/h2&gt;

&lt;p&gt;Flutter 3.44 shipped Agentic Hot Reload — the Dart/Flutter MCP server can find a running app and trigger a reload when an agent applies a change — and GenUI, built on the open A2UI protocol, which lets an agent compose real widgets from your app's catalogue rather than returning markdown.&lt;/p&gt;

&lt;p&gt;Both are genuinely interesting and neither is settled. The &lt;code&gt;genui&lt;/code&gt; package was still alpha as of the mid-2026 docs, and a full prompt cycle can emit several thousand tokens per request, which is a real cost at scale.&lt;/p&gt;

&lt;p&gt;So the question isn't "do you use AI." It's where the line sits. The answer we give: agents are good at boilerplate, test scaffolding, and mechanical refactors, and bad at deciding what the architecture should be. Anything that's expensive to reverse — data model, module boundaries, auth flow, native integration surface — gets decided by a senior engineer who will still be there in six months.&lt;/p&gt;

&lt;p&gt;A team without a stated position on this is either not using the tools or not thinking about them. Both are worth knowing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;If you only ask two, ask about platform channels and about SDK upgrade policy. The first tells you whether they've shipped something hard. The second tells you what shape the codebase will be in when you inherit it.&lt;/p&gt;

&lt;p&gt;What would you add? I'm curious which of these people have actually used in a vendor call.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team at &lt;a href="https://hotshotslabs.com/" rel="noopener noreferrer"&gt;HotShots Labs&lt;/a&gt;, a Flutter-only development studio registered in Estonia and listed in Google's Flutter Consultant Directory. We build iOS, Android, web, and tablet apps from a single Dart codebase — project-based, dedicated team, or staff augmentation. The full guide this is adapted from, including a breakdown of European Flutter companies, is &lt;a href="https://hotshotslabs.com/best-flutter-app-development-companies-europe/" rel="noopener noreferrer"&gt;on our blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
