<?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: Brian Ting</title>
    <description>The latest articles on DEV Community by Brian Ting (@tyu1996).</description>
    <link>https://dev.to/tyu1996</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F65073%2F7fffdfcf-a700-4581-929b-157dec623774.jpg</url>
      <title>DEV Community: Brian Ting</title>
      <link>https://dev.to/tyu1996</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tyu1996"/>
    <language>en</language>
    <item>
      <title>Software Engineering in 2026: A View From the Server Room</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Thu, 01 Jan 2026 04:55:36 +0000</pubDate>
      <link>https://dev.to/tyu1996/software-engineering-in-2026-a-view-from-the-server-room-3kag</link>
      <guid>https://dev.to/tyu1996/software-engineering-in-2026-a-view-from-the-server-room-3kag</guid>
      <description>&lt;p&gt;I read Ben Congdon's article &lt;a href="https://benjamincongdon.me/blog/2025/12/29/Software-Engineering-in-2026/" rel="noopener noreferrer"&gt;"Software Engineering in 2026"&lt;/a&gt; and found myself nodding along to many of his points. But I also noticed something: the conversation around AI and software engineering often feels like it's happening in a different world from mine.&lt;/p&gt;

&lt;p&gt;I'm a Full-Stack Engineer managing distributed systems across 15+ production sites in Malaysia. My daily work isn't only about building shiny new features, but also about keeping things running, handling database migrations at 2 AM, and making sure our 99%+ uptime stays that way. I am basically wearing multiple hats: writing specs, developing products, code review, deliver products, and ensure everything works without issue.&lt;/p&gt;

&lt;p&gt;Ben's article got me thinking: What does the AI revolution in software engineering look like from the server room?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I Agree: AI Has Changed the Game
&lt;/h2&gt;

&lt;p&gt;Let me be clear first. AI tools have genuinely changed how I work. The "marginal cost of producing high quality code has gone down," as Ben puts it. This is real.&lt;/p&gt;

&lt;p&gt;Here's where I've seen the biggest impact in my daily work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing boilerplate code.&lt;/strong&gt; Setting up a new FastAPI endpoint with proper validation, error handling, and documentation? What used to take 30 minutes now takes 5. AI handles the repetitive parts while I focus on the business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code reviews for patterns.&lt;/strong&gt; When reviewing AI-generated code, I've found that AI is surprisingly good at following established patterns. It rarely invents weird solutions when you give it clear examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation.&lt;/strong&gt; Writing docstrings, API documentation, and README files used to feel like a chore. Now it's almost automatic. I review and edit, but the heavy lifting is done.&lt;/p&gt;

&lt;p&gt;So yes, the productivity gains are real. But here's where my experience starts to differ from the mainstream narrative.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part Nobody Talks About: Operating Systems
&lt;/h2&gt;

&lt;p&gt;Ben makes an important observation that I wish more people would pay attention to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Operating" systems, from what I've seen, has for now been least impacted by LLMs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This matches my experience exactly. And I'd argue this is the most important part of software engineering that gets overlooked in AI discussions.&lt;/p&gt;

&lt;p&gt;When you manage 15+ production sites, you learn quickly that writing code is just the beginning. The real challenge is what comes after. Deployment. Monitoring. Debugging production issues at scale. Handling that one edge case that only appears when three specific conditions align during peak hours.&lt;/p&gt;

&lt;p&gt;AI can help me write a database migration script. But can it tell me whether I should run that migration during lunch hour or after midnight? Can it predict how the migration will affect query performance across sites with different data distributions? Can it handle the rollback if something goes wrong?&lt;/p&gt;

&lt;p&gt;Not yet. Maybe not for a while.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Production Experience Teaches You
&lt;/h2&gt;

&lt;p&gt;There's a kind of knowledge you only get from keeping systems alive. Let me share some examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database decisions compound over time.&lt;/strong&gt; Last year, I made a choice about how to structure a particular table. It seemed like a small decision then. Few months later, that decision affected query performance when the product scales up. AI can suggest schema designs, but it doesn't understand your specific data access patterns, growth projections, or the quirks of your production workload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network reality differs from theory.&lt;/strong&gt; I work in Sarawak, where network conditions can be... interesting. Our systems need to handle unstable connections, high latency, and occasional outages. This isn't in any training data. You learn it by debugging failed requests at 3 AM and building systems that gracefully degrade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uptime requires human judgment.&lt;/strong&gt; When something breaks in production, the first question isn't "what's the fix?" It's "how bad is this?" You need to decide: Do we roll back immediately? Can we apply a quick patch? Should we wake up other team members? These decisions require understanding the business impact, not just the technical problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Backend Work Feels Different
&lt;/h2&gt;

&lt;p&gt;Ben mentions that "LLMs seem to grok frontend particularly well." I've noticed this too, and I have a theory about why.&lt;/p&gt;

&lt;p&gt;Frontend work often has immediate, visible feedback. You change the code, you see the result. This makes it easier to iterate with AI assistance. You can quickly verify if the AI's suggestion works.&lt;/p&gt;

&lt;p&gt;Backend work is different. The consequences of your decisions often don't show up immediately. A poorly designed API might work fine today but cause scaling problems in six months. A database index choice might seem irrelevant until you have 10 million rows. A caching strategy might work in development but fail under production load.&lt;/p&gt;

&lt;p&gt;This delayed feedback loop makes AI assistance trickier. By the time you realize the AI's suggestion was suboptimal, you've already built a lot on top of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Skills That Matter More Now
&lt;/h2&gt;

&lt;p&gt;So what should backend engineers focus on in 2026? Based on my experience, here's what I'm investing in:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System design and architecture.&lt;/strong&gt; Ben talks about "crisp human-guided abstractions," and I think this is exactly right. The ability to design systems that are maintainable, scalable, and clear becomes more valuable when code is cheap. &lt;strong&gt;Anyone can generate code. Not everyone can design systems that work well over time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational excellence.&lt;/strong&gt; Understanding monitoring, observability, incident response, and debugging in production. These skills are hard to automate because they require deep context about your specific systems and business needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding trade-offs.&lt;/strong&gt; Every technical decision involves trade-offs. Consistency vs. availability. Performance vs. maintainability. Speed vs. reliability. AI can list options, but understanding which trade-off is right for your situation requires experience and judgment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD and deployment practices.&lt;/strong&gt; Ben emphasizes this too, and I agree completely. When AI is generating more code, your ability to test, validate, and safely deploy that code becomes critical. Investing in solid CI/CD infrastructure pays off even more now.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Build vs. Operate" Gap
&lt;/h2&gt;

&lt;p&gt;Here's something I think about a lot. Ben asks whether falling code costs will shift the "build vs. buy" calculation. He notes that operating costs haven't fallen the way development costs have.&lt;/p&gt;

&lt;p&gt;This creates an interesting situation. It's easier than ever to build something. It's not any easier to run it reliably in production. This gap will only grow.&lt;/p&gt;

&lt;p&gt;I expect this means operational expertise becomes more valuable, not less. Companies can spin up new systems faster, but they still need people who can keep those systems running. If you're a backend engineer, this is good news. The skills you've built around production reliability aren't being automated away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Forward
&lt;/h2&gt;

&lt;p&gt;I don't want to sound like I'm against AI tools. I use them daily. They've made me more productive. But I think we need a more balanced conversation about where AI helps and where human expertise still matters.&lt;/p&gt;

&lt;p&gt;Software engineering has always been about more than writing code. It's about understanding problems, making trade-offs, and building systems that work in the real world. AI is changing how we write code, but it hasn't changed those fundamentals.&lt;/p&gt;

&lt;p&gt;For those of us working in backend and infrastructure, the message I take from 2025 going into 2026 is this: Keep building your operational skills. Keep learning about system design. Keep gaining production experience. These skills are becoming more valuable, not less.&lt;/p&gt;

&lt;p&gt;And if you're managing distributed systems across multiple sites while AI handles some of your boilerplate code? You're in a pretty good position for whatever comes next.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your experience with AI tools in backend or infrastructure work? I'd love to hear from others who work in operations-heavy roles. Drop a comment below.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>ai</category>
      <category>backend</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Flutter State Management Made Simple: Mastering Riverpod in Practice (Part 2)</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Wed, 22 Jan 2025 02:06:08 +0000</pubDate>
      <link>https://dev.to/tyu1996/flutter-state-management-made-simple-mastering-riverpod-in-practice-part-2-1dpb</link>
      <guid>https://dev.to/tyu1996/flutter-state-management-made-simple-mastering-riverpod-in-practice-part-2-1dpb</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Implementation Deep Dive&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Riverpod’s true power shines when you start implementing it in real-world scenarios. Let’s move beyond theory and explore how to wield this framework effectively—from basic setups to advanced patterns.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Basic Implementation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;The Gateway: ProviderScope&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Every Riverpod-powered app starts with &lt;code&gt;ProviderScope&lt;/code&gt;, a widget that injects the state container into your app. Wrap your root widget with it:&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;ProviderScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MyApp&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;This acts as the backbone for all providers in your app. Providers are declarative, reusable objects that manage and provide state or dependencies across a Flutter application, allowing efficient and clean state management. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three Pillars of Providers&lt;/strong&gt;  &lt;/p&gt;

&lt;h5&gt;
  
  
  1. &lt;strong&gt;&lt;code&gt;StateProvider&lt;/code&gt;&lt;/strong&gt;: Ideal for ephemeral state (e.g., counters, switches).
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;counterProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateProvider&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="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Why this works&lt;/em&gt;: Exposes a simple &lt;code&gt;state&lt;/code&gt; getter/setter.  &lt;/p&gt;

&lt;h5&gt;
  
  
  2. &lt;strong&gt;&lt;code&gt;StateNotifierProvider&lt;/code&gt;&lt;/strong&gt;: Manages complex business logic with immutable state.
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;   &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StateNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
     &lt;span class="n"&gt;TodoNotifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;  
     &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&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;todoProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TodoNotifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&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;TodoNotifier&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Why this works&lt;/em&gt;: Decouples logic from UI, enabling testability.  &lt;/p&gt;

&lt;h5&gt;
  
  
  3. &lt;strong&gt;&lt;code&gt;FutureProvider&lt;/code&gt;&lt;/strong&gt;: Handles async operations like API calls.
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;weatherProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FutureProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Weather&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locationProvider&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;WeatherAPI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&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;&lt;em&gt;Why this works&lt;/em&gt;: Automatically manages loading/error states.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: From &lt;code&gt;setState&lt;/code&gt; to Riverpod—A Paradigm Shift&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Compare a counter implementation:&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;// Traditional setState  &lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nd"&gt;@override&lt;/span&gt;  
  &lt;span class="n"&gt;_CounterPageState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&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;_CounterPageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="c1"&gt;// Riverpod approach  &lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nd"&gt;@override&lt;/span&gt;  
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
      &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&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;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;,&lt;/span&gt;  
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;$count&lt;/span&gt;&lt;span class="s"&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;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Riverpod eliminates the need for &lt;code&gt;StatefulWidget&lt;/code&gt; by managing state outside the widget tree. State becomes globally accessible through &lt;code&gt;WidgetRef&lt;/code&gt;, making it easier to access and modify from anywhere in your app while maintaining clean architecture. This approach reduces boilerplate code and separates state management concerns from your UI logic.  &lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;2. Advanced Scenarios&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Dependency Injection Made Simple&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Think of providers as containers for your services. Here's how to manage API calls cleanly:&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;// Define your API client provider - a single source of truth&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;apiClientProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&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;ApiClient&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Use it to fetch user data&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FutureProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiClientProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Usage in a widget&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;loading:&lt;/span&gt; &lt;span class="p"&gt;()&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;CircularProgressIndicator&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nl"&gt;error:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&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;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Error: &lt;/span&gt;&lt;span class="si"&gt;$error&lt;/span&gt;&lt;span class="s"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Key takeaway&lt;/em&gt;: Providers create a clean dependency injection system that makes testing straightforward - simply override providers with mocks without changing your production code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State Persistence&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Save app settings automatically across restarts by pairing &lt;code&gt;StateNotifierProvider&lt;/code&gt; with &lt;code&gt;HydratedMixin&lt;/code&gt; for automatic serialization, requiring minimal additional code:&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;// Define your settings state&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Settings&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;ThemeMode&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;()&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;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;Settings&lt;/span&gt; &lt;span class="n"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;})&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;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&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;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'theme'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'theme'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Create a persistent provider&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;settingsProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SettingsNotifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&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;SettingsNotifier&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SettingsNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StateNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;HydratedMixin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;SettingsNotifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;updateTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ThemeMode&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Settings&lt;/span&gt; &lt;span class="n"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&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;Settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&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;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage in a widget&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThemeToggle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&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;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settingsProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;value:&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;onChanged:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDark&lt;/span&gt;&lt;span class="p"&gt;)&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;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settingsProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDark&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dark&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;light&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;&lt;strong&gt;Combining Providers&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Calculate values based on multiple states:&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;// Shopping cart example&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cartItemsProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CartNotifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CartItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(...);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;discountProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0&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;cartTotalProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&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;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cartItemsProvider&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;discount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discountProvider&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;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&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="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;discount&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;&lt;em&gt;Key takeaway&lt;/em&gt;: Create reactive computed states that automatically update when their dependencies change - perfect for derived values like totals, filtered lists, or complex calculations.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameterized Providers with &lt;code&gt;Family&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Fetch different data instances using the same provider:&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;productProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FutureProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;((&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productId&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiClientProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Usage in a widget&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductTile&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ConsumerWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WidgetRef&lt;/span&gt; &lt;span class="n"&gt;ref&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;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;ListTile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nl"&gt;loading:&lt;/span&gt; &lt;span class="p"&gt;()&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;Shimmer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nl"&gt;error:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&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;ErrorTile&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;&lt;em&gt;When to use&lt;/em&gt;: Perfect for scenarios where you need multiple instances of similar data, like fetching different products by ID or managing user-specific states.&lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;3. Common Pitfalls &amp;amp; Best Practices&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Reactivity Traps&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don’t&lt;/strong&gt;: Overuse &lt;code&gt;ref.read&lt;/code&gt; in builders—it breaks reactivity.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// 🚫 Avoid  &lt;/span&gt;
  &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;;&lt;/span&gt;  

  &lt;span class="c1"&gt;// ✅ Prefer  &lt;/span&gt;
  &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counterProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Do&lt;/strong&gt;: Use &lt;code&gt;autoDispose&lt;/code&gt; to avoid memory leaks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;tempDataProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StateProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;autoDispose&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="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Optimize Rebuilds with &lt;code&gt;select&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Prevent unnecessary widget rebuilds by listening to specific properties:&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="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&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;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only rebuilds when &lt;code&gt;user.name&lt;/code&gt; changes, not the entire &lt;code&gt;user&lt;/code&gt; object.  &lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;4. Testing&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Building on our earlier discussion of dependency injection, here's how to put provider overrides into practice:&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;testWidgets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Displays mocked user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tester&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;await&lt;/span&gt; &lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pumpWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;ProviderScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
      &lt;span class="nl"&gt;overrides:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="n"&gt;userProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;overrideWithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
          &lt;span class="n"&gt;AsyncValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="s"&gt;'Test User'&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="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MyApp&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="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Test User'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;findsOneWidget&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;No complex mocking setup—swap dependencies at the provider level.  &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Riverpod isn't just about managing state—it's about architecting scalable, testable, and maintainable apps. By embracing providers, families, and reactive patterns, you'll unlock a toolkit that grows with your app's complexity. &lt;/p&gt;

&lt;p&gt;As you continue your Flutter development journey, remember that solid state management isn't just a technical choice—it's an investment in your app's future growth and your team's productivity. I hope these articles have equipped you with the knowledge and confidence to build more robust Flutter applications with Riverpod.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Flutter State Management Made Simple: Why Riverpod Should Be Your Next Choice (Part 1)</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Wed, 22 Jan 2025 02:05:58 +0000</pubDate>
      <link>https://dev.to/tyu1996/flutter-state-management-made-simple-why-riverpod-should-be-your-next-choice-part-1-193n</link>
      <guid>https://dev.to/tyu1996/flutter-state-management-made-simple-why-riverpod-should-be-your-next-choice-part-1-193n</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Understanding Riverpod and Its Value&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;State management in Flutter has always been a polarizing topic. From &lt;code&gt;setState&lt;/code&gt; to complex architectures like BLoC, developers juggle trade-offs between simplicity, scalability, and maintainability. Enter &lt;strong&gt;Riverpod&lt;/strong&gt;—a framework that reimagines state management as a holistic solution for reactivity, caching, and dependency injection. Let’s unpack why it’s becoming the go-to choice for Flutter developers.  &lt;/p&gt;




&lt;h4&gt;
  
  
  &lt;strong&gt;1. What is Riverpod? The Swiss Army Knife of Flutter State Management&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://riverpod.dev/" rel="noopener noreferrer"&gt;Riverpod&lt;/a&gt; is a &lt;strong&gt;reactive caching and state-management framework&lt;/strong&gt; designed to solve the shortcomings of its predecessor, &lt;code&gt;Provider&lt;/code&gt;, while introducing a robust set of tools for modern app development. Unlike traditional state management libraries, Riverpod operates independently of Flutter’s widget tree, making it usable in pure Dart projects.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compile-Safe by Design&lt;/strong&gt;: Say goodbye to runtime exceptions caused by missing providers. Riverpod’s compile-time checks ensure your code is validated before it runs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative Reactivity&lt;/strong&gt;: State changes propagate automatically through a unidirectional data flow, reducing side effects.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Provider Ecosystem&lt;/strong&gt;: From &lt;code&gt;StateProvider&lt;/code&gt; for simple counters to &lt;code&gt;FutureProvider&lt;/code&gt; for async operations, Riverpod offers tailored solutions for diverse use cases.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context-Free&lt;/strong&gt;: No reliance on Flutter’s &lt;code&gt;BuildContext&lt;/code&gt;, enabling cleaner logic separation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Created by &lt;a href="https://github.com/rrousselgit" rel="noopener noreferrer"&gt;Remi Rousselet&lt;/a&gt; (the mind behind &lt;code&gt;Provider&lt;/code&gt;), Riverpod is its spiritual successor—addressing legacy pain points while introducing powerful new paradigms.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Why Riverpod?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Imagine building a house. You could use nails and a hammer, but a pneumatic nail gun would save time, reduce errors, and scale for larger projects. Riverpod is that nail gun for Flutter apps.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Riverpod shines in large apps. Its decoupled architecture lets you manage state globally without tangling it into the widget hierarchy—ideal for enterprise apps or long-term projects.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Override dependencies effortlessly. Swap a live API client with a mock during testing, all without touching the widget tree.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture Agnostic&lt;/strong&gt;: Whether you follow MVVM, Clean Architecture, or something custom, Riverpod adapts to &lt;em&gt;your&lt;/em&gt; structure.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling&lt;/strong&gt;: Integrated with Riverpod DevTools, debugging becomes a visual, intuitive process.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Comparison with Provider&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
While &lt;code&gt;Provider&lt;/code&gt; revolutionized state management, it relied on &lt;code&gt;BuildContext&lt;/code&gt; and occasionally threw runtime errors. Riverpod eliminates these issues, offering a safer, more flexible foundation.  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Riverpod vs. Alternatives: A Pragmatic Choice&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;How does Riverpod stack up against popular alternatives? Let’s break it down:  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Riverpod&lt;/th&gt;
&lt;th&gt;BLoC&lt;/th&gt;
&lt;th&gt;GetX&lt;/th&gt;
&lt;th&gt;Redux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compile Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boilerplate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context-Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BLoC/Cubit&lt;/strong&gt;: Powerful but requires boilerplate (events, states, blocs). Riverpod simplifies reactivity with fewer layers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GetX&lt;/strong&gt;: While easy to use, it lacks compile-time checks, risking subtle bugs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redux&lt;/strong&gt;: Predictable but verbose. Riverpod’s granular reactivity reduces unnecessary rebuilds.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;InheritedWidget&lt;/strong&gt;: Scalability nightmare. Riverpod provides global access without coupling to widgets.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. When &lt;em&gt;NOT&lt;/em&gt; to Use Riverpod?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Riverpod isn’t a silver bullet. Consider skipping it if:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your app is trivial&lt;/strong&gt;: A single-screen demo with minimal state might not justify the setup.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your team is already proficient&lt;/strong&gt;: If your squad masters BLoC or GetX, switching mid-project could hinder productivity.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping-up
&lt;/h2&gt;

&lt;p&gt;Part 1 balances theory with actionable insights, preparing you to evaluate Riverpod’s role in your next project. Whether you’re rebuilding an enterprise app or starting fresh, Riverpod’s blend of safety and flexibility makes it a compelling choice.&lt;/p&gt;

&lt;p&gt;In Part 2, we’ll explore hands-on implementations—from basic counters to advanced dependency injection and state persistence. You’ll learn how to harness &lt;code&gt;StateNotifierProvider&lt;/code&gt;, mock dependencies in tests, and avoid common pitfalls.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>riverpod</category>
      <category>state</category>
      <category>reactive</category>
    </item>
    <item>
      <title>Deploying Flutter Web App on Live Server</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Thu, 08 Feb 2024 01:48:31 +0000</pubDate>
      <link>https://dev.to/tyu1996/deploying-flutter-web-app-on-live-server-5c5</link>
      <guid>https://dev.to/tyu1996/deploying-flutter-web-app-on-live-server-5c5</guid>
      <description>&lt;p&gt;So you have your very first Flutter web app developed, tested and everything works just like what your customer wanted. It's time to bring your newly-developed app to live. Here's how to do it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The following steps will be carried using Windows 11. Some of the steps may differ on older Windows/Linux/MacOS but ultimately it should work as well. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the breakdown of the article:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build Your App&lt;/li&gt;
&lt;li&gt;Install Necessary Software&lt;/li&gt;
&lt;li&gt;[Optional] Serve Your Web App using Express&lt;/li&gt;
&lt;li&gt;Configure Firewall and Port Forwarding&lt;/li&gt;
&lt;li&gt;[Optional] Configure Backend for CORS&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Build Your App
&lt;/h2&gt;

&lt;p&gt;First thing first, our app need to be built for production. Fire up your Terminal/PowerShell in your project directory, and enter the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;flutter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flutter will use &lt;em&gt;dart2js&lt;/em&gt; compiler to compile your project into a web project. The compiled program will be inside &lt;em&gt;your_project_directory/build/web/&lt;/em&gt;. This directory can be copied to your live server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Necessary Software
&lt;/h2&gt;

&lt;p&gt;A web server is needed to serve the web app. You can use whatever web server of your choice. However in this example, I will use Express to serve the web app. Based on &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;their website&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use Express, Node.js is needed. Download and install Node.js &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After Node.js is installed, use &lt;em&gt;npm&lt;/em&gt; to install Express. Open up &lt;strong&gt;new Terminal/PowerShell window&lt;/strong&gt; and enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  [Optional] Serve Your Web App using Express
&lt;/h2&gt;

&lt;p&gt;You can skip this step if you use your own web server of choice. If you followed my steps above, you can keep reading. &lt;/p&gt;

&lt;p&gt;To serve the web app using Express, you need to write a script to tell Node.js which framework to use, where to host, and some network parameters. In your compiled web app directory, create a JavaScript file and write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define the variables&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Serve static files from the project directory&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Listen to the network&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running on port http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;I will explain a bit on this file: in this case we use port 60000 for our web app, and host '0.0.0.0' means it allows all types of connections to access to this web server. The Express will use current directory to serve static files.&lt;/p&gt;

&lt;p&gt;This is the minimal script that just enough to make it works. Save this file as 'server.js' then open up Terminal/PowerShell again in current directory and enter the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\server.js&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure Firewall and Port Forwarding
&lt;/h2&gt;

&lt;p&gt;We have one more step to bring the web app online, which requires us to configure firewall and port forwarding so the outside connection can access the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Up a Port
&lt;/h3&gt;

&lt;p&gt;Open up your Windows Defender Firewall from Start, then go to &lt;strong&gt;Advanced Settings&lt;/strong&gt; (Highlighted).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqauynnuhz2t1ilb9jxzh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqauynnuhz2t1ilb9jxzh.png" alt="Windows Defender Firewall" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It should pop up a new window. In the left pane, select &lt;strong&gt;Inbound Rules&lt;/strong&gt;, and then create a &lt;strong&gt;new rule&lt;/strong&gt; (Highlighted).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl9y8bsswkc5365x9vhr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl9y8bsswkc5365x9vhr.png" alt="New Inbound Rule" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our rule type should be &lt;strong&gt;Port&lt;/strong&gt;, then apply to &lt;strong&gt;TCP&lt;/strong&gt;, then points to port 60000 (depends on your configuration for the web server).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8txyfdy2zzwq0o7w20ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8txyfdy2zzwq0o7w20ss.png" alt="Rule Type" width="714" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs6gbh0znhr3v3ie6uk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhs6gbh0znhr3v3ie6uk1.png" alt="Protocol and Ports" width="714" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next step, allow the connection, set up your rule name and save it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Port Forwarding
&lt;/h3&gt;

&lt;p&gt;Access to your router setting and create a port forwarding rule to point to your web server's port (same as your newly-created firewall rule). It should roughly looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z3kbnnwu74ljds4buc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z3kbnnwu74ljds4buc7.png" alt="Port Forwarding" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Local IP&lt;/em&gt; should be your live server's local IP.&lt;/p&gt;

&lt;p&gt;Voila! Your server that runs Flutter Web App is now live to the public!&lt;/p&gt;

&lt;h2&gt;
  
  
  [Optional] Configure Backend for CORS
&lt;/h2&gt;

&lt;p&gt;It important to know that Flutter Web App requires to have CORS (Cross-Origin Resource Sharing) support, as modern web browsers are enforcing CORS as a part of modern web standards. &lt;/p&gt;

&lt;p&gt;If your web app is not connecting with cloud services like Firebase but with your own API backend, you should make sure your backend has implemented CORS support, else it will not work (as web browser will refuse to establish connection with backend).&lt;/p&gt;

&lt;p&gt;I will use FastAPI as example, it must have the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;


&lt;span class="c1"&gt;# Create a FastAPI instance
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="c1"&gt;# CORS Origins
# Put your own URL/Dynamic DNS addresses
&lt;/span&gt;&lt;span class="n"&gt;origins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:60000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://mydyndns.ddns.net:60000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://mydyndns.ddns.net:60000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Configure CORS
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;origins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_credentials&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&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;Restart FastAPI, and it will only accept any connection from the specified URL and port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks for Reading ;)
&lt;/h2&gt;

&lt;p&gt;Hope this serves as a useful guideline for anyone who wanted to bring their first Flutter Web App online.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Communicate with Microsoft SQL Server that works on Flutter app compiled for multiple platforms</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Wed, 20 Dec 2023 01:49:59 +0000</pubDate>
      <link>https://dev.to/tyu1996/communicate-with-microsoft-sql-server-that-works-on-flutter-app-compiled-for-multiple-platforms-d9k</link>
      <guid>https://dev.to/tyu1996/communicate-with-microsoft-sql-server-that-works-on-flutter-app-compiled-for-multiple-platforms-d9k</guid>
      <description>&lt;p&gt;Suppose you envision that Flutter is the future, especially its capability to be compiled for many platforms through one codebase, which may greatly save up the cost of development for your own good. You have existing customers, and customers will also eventually move on to adapt new technology, that means you also have to keep up the market trend to satisfy your customers' needs.&lt;/p&gt;

&lt;p&gt;Even though you wanted to deliver a revamped app to your customers, but in reality you have to face one important problem: &lt;strong&gt;customers may love to use your new app, but customers most likely do not want to pay a high price to change their database.&lt;/strong&gt; In their perspective, their existing database just works for many years, there is no reason to 'upgrade' their database if it does not break. Here I mean, they are using SQL Server, and most likely they are using the Microsoft one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I have spent an extended amount of time to search for compatible plugins for Flutter that is able to communicate with Microsoft SQL Server. Sadly, though Flutter has a trusty &lt;a href="https://pub.dev/packages/sqflite" rel="noopener noreferrer"&gt;&lt;em&gt;sqflite&lt;/em&gt;&lt;/a&gt; plugins, and the same author has also wrote &lt;a href="https://pub.dev/packages/drift" rel="noopener noreferrer"&gt;&lt;em&gt;drift&lt;/em&gt;&lt;/a&gt; plugins (they're both great, I have used them), but dealing with SQL server is still a lacking part in Flutter ecosystem. Although &lt;em&gt;drift&lt;/em&gt; does has remote library to deploy a remote SQL server, but it requires the other end to have &lt;em&gt;drift&lt;/em&gt; installed too (correct me if I'm wrong). I don't think I would spend much time to setup &lt;em&gt;drift&lt;/em&gt; for an existing, well-configured SQL server.&lt;/p&gt;

&lt;p&gt;In the time of writing, there is one working plugin for Flutter that able communicate with MSSQL protocol, which is &lt;a href="https://pub.dev/packages/sql_conn" rel="noopener noreferrer"&gt;&lt;em&gt;sql_conn&lt;/em&gt;&lt;/a&gt;. I thought I found a saviour, until I saw this:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kuaxlepsznlqbqudyrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kuaxlepsznlqbqudyrb.png" alt="sql_conn plugin for Flutter" width="800" height="552"&gt;&lt;/a&gt;&lt;br&gt;
I was like, whaaaat? Android only, other platforms are out of luck. I thought of forking the project on GitHub and add support to other platforms as well, but it is not as easy as I thought.&lt;/p&gt;
&lt;h2&gt;
  
  
  What To Do?
&lt;/h2&gt;

&lt;p&gt;If there is no way I can find the off-the-shelf plugin to achieve this, shall I abandon my visionary Flutter project? After a serious consideration, I do not think I will opt for other frameworks. So, I thought of another approach: writing my own API backend as middleware.&lt;/p&gt;
&lt;h2&gt;
  
  
  Middleware -- FastAPI + SQLAlchemy
&lt;/h2&gt;

&lt;p&gt;I am familiar with Python myself, so choosing to write a middleware in Python is a no-brainer for me. I stumbled upon something called "&lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;&lt;em&gt;FastAPI&lt;/em&gt;&lt;/a&gt;" thingy which claimed to be a verrryyyyy fast API server, and good-olde &lt;a href="https://www.sqlalchemy.org/" rel="noopener noreferrer"&gt;&lt;em&gt;SQLAlchemy&lt;/em&gt;&lt;/a&gt; with &lt;a href="https://github.com/mkleehammer/pyodbc" rel="noopener noreferrer"&gt;&lt;em&gt;pyodbc&lt;/em&gt;&lt;/a&gt; that provides the protocol to communicate with MSSQL.&lt;/p&gt;

&lt;p&gt;So, shall we?&lt;/p&gt;
&lt;h2&gt;
  
  
  Starting The Project
&lt;/h2&gt;

&lt;p&gt;First thing first, fire up your terminal and install the required libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;fastapi sqlalchemy pyodbc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we may create a python file, and write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqldbIP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.16.99&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqldbPort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1433&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqldbDB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RMS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqldbUserId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqldbPass&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MachineId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Start of program, connecting to DB
&lt;/span&gt;&lt;span class="n"&gt;conn_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mssql+pyodbc://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqldbUserId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqldbPass&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqldbIP&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqldbPort&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqldbDB&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;?driver=ODBC+Driver+17+for+SQL+Server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code tells the Python to import the necessary libraries, then we write a dictionary called &lt;code&gt;config&lt;/code&gt; that defines where the &lt;em&gt;SQLAlchemy&lt;/em&gt; should connect to.&lt;/p&gt;

&lt;p&gt;We initialise the FastAPI app by calling &lt;code&gt;app = FastAPI()&lt;/code&gt;, then define the connection string &lt;code&gt;conn_string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First we need to pass the &lt;em&gt;pyodbc&lt;/em&gt; driver &lt;code&gt;mssql+pyodbc&lt;/code&gt; so it can communicate with MSSQL, then follow the connection format, and lastly pass the custom driver &lt;code&gt;driver=ODBC+Driver+17+for+SQL+Server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We may need to create an engine and also session for us to execute SQL queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queries
&lt;/h2&gt;

&lt;p&gt;Now, we are going to write some pure SQL queries to interact with SQL Server. I would suggest you to create a file specifically for querying and not mix with the main Python file, so you can maintain the code more easily in the future when the project scales up.&lt;/p&gt;

&lt;p&gt;Let's start with the most basic query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the SQL Server to show all records available in that particular table. Let's turn it into Python script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Import necessary libraries
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_data_from_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM employee_table&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;employee_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;employee_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;employee_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;employee_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;json_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;employee_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;employee_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json_data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I defined a function specifically to retrieve the data from a table, and everything is pretty much a hard-code to make sure it works.&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;text&lt;/code&gt; method from &lt;code&gt;sqlalchemy&lt;/code&gt; library to write the query, because this method can produce a well-formatted query for sqlalchemy to interact with the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cursor&lt;/code&gt; will store the data fetched from the database after calling &lt;code&gt;execute&lt;/code&gt; method from the database session, then I used a &lt;code&gt;for&lt;/code&gt; loop to populate the data into &lt;code&gt;result&lt;/code&gt; list, lastly store the result into &lt;code&gt;json_data&lt;/code&gt; dictionary. This should can be directly being used to output the API calls.&lt;/p&gt;

&lt;p&gt;Lastly, before return the json output, don't forget to close the connection.&lt;/p&gt;

&lt;p&gt;So you can imagine, whatever queries that MSSQL supports, you can just throw them into the &lt;code&gt;text()&lt;/code&gt; method, execute it and make sure to insert the results into your Python dictionaries. You can structure your Python dictionary as you please, in the end it will return the dictionary as json to your client-end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paths
&lt;/h2&gt;

&lt;p&gt;We need to have paths for our client side to communicate with the backend. Defining path is very simple in FastAPI. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;retrieve_data_from_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to use the decorator &lt;code&gt;@app.get("/")&lt;/code&gt;, which &lt;code&gt;app&lt;/code&gt; is the FastAPI instance, and tell the FastAPI that this path should use &lt;strong&gt;HTTP GET&lt;/strong&gt; operation. Then, we define an asynchronous function (since of FastAPI's nature) &lt;code&gt;home()&lt;/code&gt;, and call the query function &lt;code&gt;retrieve_data_from_table(session)&lt;/code&gt; to retrieve our data from SQL server. The output of this path when being accessed by client-side Flutter app will be &lt;code&gt;json_data&lt;/code&gt; we defined in the query function.&lt;/p&gt;

&lt;p&gt;If you have query parameters, you can give the parameters to the async function like how you give parameters in normal functions, and then pass the parameters in your function call. &lt;/p&gt;

&lt;p&gt;Additionally, if you want to perform &lt;strong&gt;HTTP POST&lt;/strong&gt; operation (when Flutter user submit a data), you can use the &lt;code&gt;post&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Import necessary libraries
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/submit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data_json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;submit_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that I use &lt;code&gt;post&lt;/code&gt; instead of &lt;code&gt;get&lt;/code&gt; on the decorator this time. The &lt;code&gt;request&lt;/code&gt; parameter is needed so the FastAPI can decode the data and send to the &lt;code&gt;submit_order&lt;/code&gt; function that performs either &lt;em&gt;CREATE, UPDATE, DELETE&lt;/em&gt; SQL queries as you define it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Flutter's Side
&lt;/h2&gt;

&lt;p&gt;We're settled on backend side (Python), now we're going to our client side (Flutter).&lt;/p&gt;

&lt;p&gt;Create an empty Dart file, and put some code into it:&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="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:http/http.dart'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:convert'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"apiUrl"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"10.0.2.2:8000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// Connect to localhost for Android emulator&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;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchEmployeeData&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="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"apiUrl"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the server returns a 200 OK response, parse the JSON.&lt;/span&gt;
    &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;employeeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyBytes&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;employeeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the server returns an error response, throw an exception.&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Failed to load employee data.'&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;Make sure the &lt;code&gt;http&lt;/code&gt; package is added into &lt;em&gt;pubspec.yaml&lt;/em&gt; to make things work. I added some comments in the code so you can understand how it works. Basically, &lt;code&gt;apiUrl&lt;/code&gt; is defined so Flutter app can connect to the FastAPI server using &lt;code&gt;http.get(url)&lt;/code&gt; method. When the response status code is 200 (meaning OK), the app will decode the json (it's Python dictionary we defined as &lt;code&gt;json_data&lt;/code&gt; before) as Dart's &lt;code&gt;Map&lt;/code&gt; variable &lt;code&gt;employeeData&lt;/code&gt;. Finally, you use this &lt;code&gt;employeeData&lt;/code&gt; to display your data.&lt;/p&gt;

&lt;p&gt;If you have query parameters, I encourage you can take a short read on &lt;code&gt;Uri.http&lt;/code&gt; reference about how to pass the query parameters.&lt;/p&gt;

&lt;p&gt;Additionally, if you want to submit the user input to the server (which is &lt;strong&gt;POST&lt;/strong&gt; instead of &lt;strong&gt;GET&lt;/strong&gt;), it should be like this:&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;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&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="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"apiUrl"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/submit'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Content-Type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'application/json'&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="s"&gt;'data'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&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;submitStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;submitStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Submission Failed: &lt;/span&gt;&lt;span class="si"&gt;${response.reasonPhrase}&lt;/span&gt;&lt;span class="s"&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;For this time, notice that there is required parameters in the function &lt;code&gt;submit()&lt;/code&gt;, which contains the data to submit to the server, and a &lt;code&gt;headers&lt;/code&gt; is needed for &lt;strong&gt;POST&lt;/strong&gt; operation, and in the end we use the &lt;code&gt;http.post&lt;/code&gt; method to perform &lt;strong&gt;POST&lt;/strong&gt; operation.&lt;/p&gt;

&lt;p&gt;In this case, I return a boolean variable &lt;code&gt;submitStatus&lt;/code&gt; to tell the app whether the &lt;strong&gt;POST&lt;/strong&gt; operation is successful, but you can modify the function yourself that suits your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start the Server
&lt;/h2&gt;

&lt;p&gt;After everything is setup, fire up your FastAPI server. FastAPI uses &lt;a href="https://www.uvicorn.org/" rel="noopener noreferrer"&gt;&lt;em&gt;uvicorn&lt;/em&gt;&lt;/a&gt; as their default development server, and you can run this command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn main:app &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells &lt;em&gt;uvicorn&lt;/em&gt; to run the &lt;code&gt;app&lt;/code&gt; instance, and able to reload the server every time the code changes. The default port is &lt;code&gt;8000&lt;/code&gt;, but you can specify the &lt;em&gt;uvicorn&lt;/em&gt; to use which port you desire by passing &lt;code&gt;--port &amp;lt;integer&amp;gt;&lt;/code&gt;, and you also need to change the target port in Flutter's code in that case.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;Phew! It's a long article, but through this your Flutter app can communicate with SQL Server no matter the app is compiled to which platform of choice. It's platform-agnostic.&lt;/p&gt;

&lt;p&gt;If you found a better solution, do leave a comment and let me know too! Thank you.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>flutter</category>
      <category>python</category>
      <category>api</category>
    </item>
    <item>
      <title>Some Code Refactor Tips for Junior Developers</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Wed, 10 Feb 2021 05:22:30 +0000</pubDate>
      <link>https://dev.to/tyu1996/some-code-refactor-tips-for-junior-developers-4da6</link>
      <guid>https://dev.to/tyu1996/some-code-refactor-tips-for-junior-developers-4da6</guid>
      <description>&lt;p&gt;When starting the first career of being a software developer, apart from the knowledge gained from university or college, there is some more things needed to be aware of. &lt;/p&gt;

&lt;p&gt;There was no requirement to write a good, maintainable code during the course works, we all only wanted to get the things done and pass the course. However, being in a career often means you will work in a team, and the project being worked on often needs to consider the project maintainability. One of it is to know how to refactor the code.&lt;/p&gt;

&lt;p&gt;Here, I will give few examples in Python-like syntax and elaborate them. This is not representing any web framework, just for the ease of read.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tip 1: Functions
&lt;/h1&gt;

&lt;p&gt;Suppose you have a web app, and to write a feature that lets users to generate a table of data, let's say the staffs who attended the company annual dinner, and at the same time it counts the number of people who got the lucky draw.&lt;/p&gt;

&lt;p&gt;Instead of having this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generateTable&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="c1"&gt;# Get data from a database named 'staffDB', 
&lt;/span&gt;  &lt;span class="c1"&gt;# and get the records who attended annual dinner
&lt;/span&gt;  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;staffDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalStaffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attended_annual_dinner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Write a formatted table and dump data in
&lt;/span&gt;  &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TableObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;header1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;header2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Got Lucky Draw?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lucky_draw&lt;/span&gt;

  &lt;span class="c1"&gt;# Count the total number who got lucky draw
&lt;/span&gt;  &lt;span class="n"&gt;lucky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lucky_draw&lt;/span&gt;
  &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;got_lucky_draw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lucky&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="c1"&gt;# Ultimately, pass every data here to the webpage
&lt;/span&gt;  &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;annual_dinner.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lucky_counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see, a function that carries three tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get data from database&lt;/li&gt;
&lt;li&gt;Generate a table&lt;/li&gt;
&lt;li&gt;Count who got lucky draw&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although it does not seems complicated here, but in real world project this kind of writing style always ends up hundreds line of code.&lt;/p&gt;

&lt;p&gt;It can be done in much simpler form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getAttendingStaffs&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="c1"&gt;# Get data from a database named 'staffDB', 
&lt;/span&gt;  &lt;span class="c1"&gt;# and get the records who attended annual dinner
&lt;/span&gt;  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;staffDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;totalStaffs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attended_annual_dinner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lucky_draw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLuckyCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lucky_draw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;annual_dinner.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lucky_counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generateTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lucky_draw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# Write a formatted table and dump data in
&lt;/span&gt;  &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TableObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;header1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;header2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Got Lucky Draw?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lucky_draw&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getLuckyCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lucky_draw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# Count the total number who got lucky draw
&lt;/span&gt;  &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;got_lucky_draw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lucky_draw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;who_got_lucky_draw&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one splits into three functions, each one performs single task. Only when the &lt;code&gt;getAttendingStaffs()&lt;/code&gt; function is called, it will also call two other functions and pass the required parameters in. &lt;/p&gt;

&lt;p&gt;Although this results more line of code in total, but it surely make the code tidier, and easier to navigate when you need to modify the function.&lt;/p&gt;

&lt;p&gt;Take an example in real world project, there is a bug in generating the table. The former style makes you search through a long line of code that wraps everything into a function, and the code looks messier in overall; the later style you can only focus on that particular function, better focus.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tip 2: Source files based on purpose
&lt;/h1&gt;

&lt;p&gt;The idea of this one is similar to the one above, but make it in the file-level.&lt;/p&gt;

&lt;p&gt;In other words, create source files based on its scope of job. Instead of one source file performing few jobs, separate the jobs into few source files.&lt;/p&gt;

&lt;p&gt;For example, you have a blog website, and users can have account to write their blog posts. In this case, you can create a few source files, where one stores all the global constants, one does the job of handling user account information, one does the job of handling posts. Lastly, you have a main source file (as entry point) referring those files and they work together.&lt;/p&gt;

&lt;p&gt;Doing so keeps the logic away from a single file. So, in future maintenance, perhaps you want to have a new feature that allows users to upload an image to a post, just mess with that source file, the others are unaffected.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tip 3: Negation IF
&lt;/h1&gt;

&lt;p&gt;Often we need to write a conditional statement to control how an application behaves. If you are writing a simple conditional statement, using negation statement is often recommended.&lt;/p&gt;

&lt;p&gt;Well, this does not really make the code significantly less cluttered, but apart from what textbook taught (a conventional if-else style), we can make the code looks a little bit cooler.&lt;/p&gt;

&lt;p&gt;Instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;somethingPositive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Do this
&lt;/span&gt;    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Do that
&lt;/span&gt;    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otherValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;somethingNegative&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Negation IF
&lt;/span&gt;    &lt;span class="c1"&gt;# Do this
&lt;/span&gt;    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Proceed to do desired tasks
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perhaps an example is easier to understand, we have a boolean variable called &lt;code&gt;status&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;doActionByStatus&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Perform tasks if status is false
&lt;/span&gt;    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The system is not functioning properly.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Perform tasks if status is true
&lt;/span&gt;  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All systems are performing well&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="nf"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry about the function will proceed when &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt; and the tasks inside are executed. After the function reaches the first &lt;code&gt;return()&lt;/code&gt; within &lt;code&gt;if&lt;/code&gt; statement, it will exit. Else, the function will just do the tasks after &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Alright, hope this article can help junior developers and freshgrads in their careers. There are a lot of writing practices that helps writing better, cleaner and more maintainable code.&lt;/p&gt;

&lt;p&gt;If you can do these as a habit, when your next juniors come and work with you, they will thank you.&lt;/p&gt;

</description>
      <category>code</category>
      <category>practices</category>
      <category>refactor</category>
      <category>tips</category>
    </item>
    <item>
      <title>Flasker - Definitely Minimal Flask Boilerplate</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Mon, 30 Nov 2020 03:05:46 +0000</pubDate>
      <link>https://dev.to/tyu1996/flasker-definitely-minimal-flask-boilerplate-37j</link>
      <guid>https://dev.to/tyu1996/flasker-definitely-minimal-flask-boilerplate-37j</guid>
      <description>&lt;p&gt;I created a minimal Flask boilerplate for developers who want to create a Flask-based web apps from scratch, quickly.&lt;/p&gt;

&lt;p&gt;The boilerplate repo: &lt;a href="https://github.com/tyu1996/flasker" rel="noopener noreferrer"&gt;https://github.com/tyu1996/flasker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxs4yg7hj14v01younh5g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxs4yg7hj14v01younh5g.gif" alt="Flasker GIF" width="960" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is minimal enough that devs are given flexibility and no need to spend too much time trying to understand the codebase. With some experience with Flask, you can start to develop right away.&lt;/p&gt;

&lt;p&gt;This boilerplate has complete set of what minimal web app should have: webpages, routes, forms, and models. It comes with a sample template so you can check around the web app first by running the &lt;em&gt;run.sh&lt;/em&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Automate Stuffs with GitHub Actions on Publishing AppImage</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Fri, 17 Apr 2020 07:48:41 +0000</pubDate>
      <link>https://dev.to/tyu1996/automate-stuffs-with-github-actions-on-publishing-appimage-4pl1</link>
      <guid>https://dev.to/tyu1996/automate-stuffs-with-github-actions-on-publishing-appimage-4pl1</guid>
      <description>&lt;p&gt;I was using travis-ci for buidling and releasing AppImage, until I discovered GitHub Actions recent these days. Since the repos are hosted on GitHub, why not take a try on its own CI/CD for my simple jobs?&lt;/p&gt;

&lt;p&gt;This article discusses about using GitHub Actions for automating the AppImage build process and release it for users.&lt;/p&gt;

&lt;p&gt;What is AppImage you ask, &lt;a href="https://appimage.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt; provides great explanation and samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions
&lt;/h2&gt;

&lt;p&gt;FYI, CI/CD stands for "Continuous Integration and Continuous Delivery". In short, CI/CD automates the building and delivering processes to make developers' life easier.&lt;/p&gt;

&lt;p&gt;GitHub introduced its own CI/CD named &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;. By using GitHub Actions, just push your code to the repo, it builds, test, and upload to release automatically for you. But first, a defined workflow is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actions in action
&lt;/h2&gt;

&lt;p&gt;In Actions, there is a concept of workflows and actions. You can say a workflow contains many actions, and each action performs different set of tasks to achieve a particular job. A GitHub repo will have a workflow, but has different actions, which the tasks are written in yaml files.&lt;/p&gt;

&lt;p&gt;Take an example, I have a repo contains AppImage building configurations for Opera. A build.sh in root directory tells a Linux machine to build an AppImage package from deb file.&lt;/p&gt;

&lt;p&gt;In the repo, I created a directory .github/workflows. Actions will look for this directory, and take actions from all yaml files within. In this case, one yaml file is enough.&lt;/p&gt;

&lt;p&gt;I recommend people to take a look on the &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to familiarise with the syntaxes. Inside the workflows directory, a build.yml file was created. Now, let's go through the flow one-by-one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;.github/workflows/build.yml&lt;/em&gt;&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AppImage Build&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the most basic syntaxes for Actions to perform CI/CD. The syntax is very straightforward: define the action name, when the action starts, and the jobs will be carried out. In this case, the action will start while GitHub senses a push to the repo. Let's continue.&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 

  &lt;span class="c1"&gt;# This workflow contains a single job called "build"&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-16.04&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;

    &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within jobs, first thing is to give a job named "build", and specify which operating system to do the job. GitHub offers two LTS versions of Ubuntu, Windows Server 2019 and macOS 10.15. The rest of the tasks will be performed under "steps". We have to clarify which branch in our repo is used for building process, the code above checks out the master branch. Let's continue.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;# Runs a single command using the runners shell&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install required dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sudo apt-get install desktop-file-utils zsync&lt;/span&gt;

    &lt;span class="c1"&gt;# Runs a set of commands using the runners shell&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download building tools &amp;amp; executing AppImage build&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;wget -nv -c https://github.com/AppImage/pkg2appimage/releases/download/continuous/pkg2appimage-continuous-x86_64.AppImage&lt;/span&gt;
        &lt;span class="s"&gt;wget -nv -c https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage&lt;/span&gt;
        &lt;span class="s"&gt;./build.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each task, a "name" and either "uses" or "run" tags are required, and only can be used once. First task installs all required dependencies for building AppImage with single command; second task downloads and executes AppImage build, which GitHub allows multi-line commands by putting a pipe | after "run:"&lt;/p&gt;

&lt;p&gt;At this moment, an AppImage has been built. So, the artifact(s) should be uploaded to Release page for users to download. Let's continue.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create Release&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ncipollo/release-action@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;allowUpdates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
        &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;continuous&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Continuous build&lt;/span&gt;
        &lt;span class="na"&gt;prerelease&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
        &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out/*"&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luckily, we have someone created a &lt;a href="https://github.com/ncipollo/release-action" rel="noopener noreferrer"&gt;useful Action&lt;/a&gt; for handling the task. The Action helps create a release tag and upload the artifact(s). Specify the repo in "uses" tag, and feed in the parameters under "with" tag. More optional parameters is being explained in the repo, do take a look.&lt;/p&gt;

&lt;p&gt;One thing to take note is the "allowUpdates" parameter. Some AppImage package contributors tend to upload the latest version under the pre-release tag, replacing the old version. In default, GitHub Actions will cry out loud for existing release tag and refuses to upload the artifact(s). Set "allowUpdates" to True to replace the old version in the same release tag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commit change and see
&lt;/h2&gt;

&lt;p&gt;Now, try to commit this change and push to the repo. When GitHub senses the presence of .github/workflows directory in the repo, it will trigger the CI/CD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Femghr7ocizw6wvut8vrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Femghr7ocizw6wvut8vrz.png" alt="Alt Text" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's it! My first transition from travis-ci to GitHub Actions was a success. In my opinion, GitHub Actions is a more convenient choice for building and publishing AppImage packages on my repos. &lt;/p&gt;

&lt;p&gt;Through this article, I hope more AppImage package contributors can take advantages of CI/CD to publish their packages faster and easily. And for those who are interested on building AppImage packages, you are always welcomed to the community ;)&lt;/p&gt;

</description>
      <category>ci</category>
      <category>cd</category>
      <category>appimage</category>
    </item>
    <item>
      <title>[Question] UI/UX learning materials for developers</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Sat, 20 Oct 2018 09:33:54 +0000</pubDate>
      <link>https://dev.to/tyu1996/uiux-learning-materials-for-developers-3bi8</link>
      <guid>https://dev.to/tyu1996/uiux-learning-materials-for-developers-3bi8</guid>
      <description>&lt;p&gt;I am experienced in Python programming, and recently I learnt a bit of Angular(TS) and Tkinter.&lt;/p&gt;

&lt;p&gt;I think I had enough time to do purely coding. I wish to learn how to think and make a program that gives good user experience. Do you guys have any recommendation like books, or online learning materials about UI/UX?&lt;/p&gt;

&lt;p&gt;Edit: Seems I misunderstood the co-existence of UI and UX (strictly said they both cannot be considered as a same thing). Should be clear is that I wanted to learn UI stuffs.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ui</category>
      <category>ux</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How I get to my goals</title>
      <dc:creator>Brian Ting</dc:creator>
      <pubDate>Thu, 28 Jun 2018 14:28:52 +0000</pubDate>
      <link>https://dev.to/tyu1996/how-i-get-to-my-goals-4n7</link>
      <guid>https://dev.to/tyu1996/how-i-get-to-my-goals-4n7</guid>
      <description>&lt;p&gt;Hello to this brilliant community. This is my first post and I am not an English speaker, sorry for any grammatical problems.&lt;/p&gt;

&lt;p&gt;I would like to share how I begin my journey to computer science.&lt;/p&gt;

&lt;h1&gt;
  
  
  Programming owned my heart
&lt;/h1&gt;

&lt;p&gt;I was drawn to programming stuffs when I was around 14-15 years old. I don't remember what actually drove me to get into software development that time, but every time I think about softwares, I believe that I could also make one. &lt;/p&gt;

&lt;p&gt;My first programming language was C, which learned from a very old textbook I borrowed from my middle school teacher. When I compiled my very first program &lt;em&gt;Hello World&lt;/em&gt;, I thought I was like a god. I can create anything that works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Programming owned my heart&lt;/strong&gt;. I was a lazy student in class that I can almost failed on any subjects, but my teacher told me that I should get a good grade on science-stream subjects especially maths so I can enter Computer Science in university. That was the first time I truly try to change myself, I studied hard on maths. The only goal was: I want to study Computer Science.&lt;/p&gt;

&lt;h1&gt;
  
  
  As a university student now
&lt;/h1&gt;

&lt;p&gt;I achieved my first goal and is a Computer Science student. I found I have limited amount of time everyday besides study/homework time. I asked myself: How can I keep pursuing knowledge aside of school things?&lt;/p&gt;

&lt;p&gt;I learnt to manage my time, set my daily/weekly tasks and control my time spending. This does hugely improve the efficiency of doing anything so that I won't be able to waste too much time on something that won't do any benefits.&lt;/p&gt;

&lt;p&gt;Studying in university has widened my knowledge view that we are not only to code, but learnt there is many things to consider and to drive you to code. Studying is not for grades, but for how you smart use the knowledge to solve current issues. This is the most valuable thing you can get in university.&lt;/p&gt;

&lt;p&gt;If you are also a student like me, I encourage you to treasure your every second on pursuing what you like. What got you here, where do you want to go, this would be your life direction. Grasp it, it is your golden age in your lifetime.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is my current plan?
&lt;/h1&gt;

&lt;p&gt;I am currently interested on Deep Neural Network and Stochastic Computing, and just started to study them. Hope one day I can use them for something useful.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
