<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Irfan Yas on Medium]]></title>
        <description><![CDATA[Stories by Irfan Yas on Medium]]></description>
        <link>https://medium.com/@irfnyas?source=rss-bb557aa4ea02------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*v3vB7a7BbJUX4P_sOwi9FA.jpeg</url>
            <title>Stories by Irfan Yas on Medium</title>
            <link>https://medium.com/@irfnyas?source=rss-bb557aa4ea02------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 18:54:10 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@irfnyas/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[From Dune to DONE]]></title>
            <link>https://irfnyas.medium.com/from-dune-to-done-3bb255cf6971?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/3bb255cf6971</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[ollama]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Tue, 12 May 2026 06:43:57 GMT</pubDate>
            <atom:updated>2026-05-12T12:04:12.529Z</atom:updated>
            <content:encoded><![CDATA[<h4>“I want Dune” - “We have Dune at home”. Dune at home:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*WYRgdcvFE74Zg6qd" /><figcaption>Photo by <a href="https://unsplash.com/@kanhaiyasharma?utm_source=medium&amp;utm_medium=referral">Kanhaiya Sharma</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>While scrolling through Product Hunt, I came across something interesting called <strong>Dune</strong>:</p><p><em>“Dune is a Context-aware Keypad for Mac that sits next to your keyboard and changes what its three keys do in real time based on the app running in the foreground.” </em><a href="https://www.producthunt.com/products/dune-4"><em>Source</em></a><em>.</em></p><p>In essence, it’s a minimalist <a href="https://www.makeuseof.com/what-is-a-macro-pad/">Macro Pad</a> with just three keys designed to boost productivity. Despite its simplicity, Dune climbed to <strong>#1 Product of the Week </strong>on Product Hunt and sold out its very first pre‑order batch.</p><p>Clearly, people are drawn to this kind of device. <a href="https://www.accio.com/t-v2/business/trend-of-stream-deck">The demand for macro pads is real</a>.</p><p>Take the <strong>Stream Deck</strong> as another example. The best‑selling model on Amazon has moved over <strong>9.9K units</strong>, with more than <strong>1K purchases in the past month alone</strong>. For a gadget that only sells buttons — which priced on par with a smartphone — that’s impressive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3IoUNaDLe_2mFROsEsWC3A.png" /><figcaption><a href="https://www.amazon.com/s?k=stream+deck&amp;s=exact-aware-popularity-rank&amp;ds=v1%3AqdW9pSpUUar2BP1RcBADsr49TgJf0Av5FGHNfq34w3M&amp;crid=12R4ZBJGMHBOD&amp;qid=1778555471&amp;sprefix=stream+deck%2Caps%2C343&amp;ref=sr_st_exact-aware-popularity-rank">Amazon Source.</a></figcaption></figure><h3>Macro Technology</h3><p>These are amazing things. Yet, from a technical perspective, the concept isn’t groundbreaking; it’s essentially a shortcut system, something that has been around <a href="https://en.wikipedia.org/wiki/Macro_(computer_science)">since the 1980s</a>. But what makes <strong>Dune</strong> stand out isn’t the hardware, it’s the <strong>software</strong>.</p><p>Unlike traditional macro pads that rely on manual configuration and static profiles, Dune is <strong>context‑aware</strong>: its three keys automatically adapt to whichever app is active in the foreground. Instead of the user having to pre‑program every scenario, the device anticipates context and updates itself in real time.</p><p>This approach elevates the macro pad from a passive tool into something closer to an <strong>intelligent workflow assistant</strong>. In a way, Dune is redefining what a “macro pad” can be: not just extra buttons, but a dynamic extension of your digital environment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RNwQQceupwBbxkpx" /><figcaption><a href="https://www.projectmirage.ai/">Project Mirage.</a></figcaption></figure><h3>Dune without Deck</h3><p>I’ve already built <a href="https://medium.com/@irfnyas/vibecoded-my-own-virtual-gamepad-7ef61598101e">my own macro pad</a> before. But, can we push it further into dynamic key functions? The goal was simple:</p><ol><li><strong>Desktop Overlay</strong>: Minimalist UI on macOS that suggests shortcuts.</li><li><strong>Mobile Remote</strong>: App on my phone that mirrors those shortcuts as touchable buttons, replacing the need for Dune’s physical hardware.</li><li><strong>AI Agent</strong>: A lightweight agent that analyzes the active window and intelligently suggests the most relevant actions in real time.</li></ol><h4>The Stacks</h4><p>I decide to spin up a new repository and build <strong>DONE</strong> — O’s for Open Source and Ollama Powered. The tech stack:</p><ol><li><strong>Python for the desktop orchestrator:</strong><br>Python gives me direct access to macOS through AppleScript, while PyQt6 powers a sleek “glassmorphism” overlay that feels native to the OS.</li><li><strong>Flutter for the mobile remote:<br></strong>A grid of action buttons turns my phone into a dynamic extension of whatever app is active on my Mac, making shortcuts portable.</li><li><strong>Ollama for AI Agent:<br></strong>Fully local and free. Users can swap between models of their choice.</li></ol><h4>The Challenges</h4><p>Building an app like this came with unique challenges:</p><p><strong>1. The “Boomerang Focus”<br></strong>When you tap a button on your phone, the Mac needs to execute that shortcut. The problem: if the overlay has focus, the keystroke lands there instead of the target app. The workaround:</p><p>1. Tap on phone → signal sent to Mac.<br>2. Mac identifies the target app (e.g., Chrome).<br>3. Mac momentarily switches focus to Chrome.<br>4. Fires the keystroke (e.g., <em>Cmd+T</em>).<br>5. Snaps focus back to your previous state.</p><p>It’s so fast you don’t even see the flicker.</p><p><strong>2. URL Normalization<br></strong>LLMs can be expensive in compute, and I didn’t want the agent to regenerate shortcuts every time I switched YouTube videos. By stripping query parameters, the system recognizes that youtube.com/watch?v=123 and youtube.com/watch?v=456 are the same context. This enables aggressive caching and instant UI updates without wasted cycles.</p><p>3. <strong>The “Permission Fortress”<br></strong>Building DONE taught me that macOS is a fortress when it comes to permission. Handling Accessibility access — or at least guiding the user through them — was a challenge itself.</p><p>But the result? When I open Youtube, my phone shows play/pause and skip. When I open IDE, it shows “Run Tests” and “Format Document.” The workspace feels <em>alive</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ku0pb4B83ufNcrQ6ZuaQyw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vfGvhZOiyWwwa6nfMhN4Aw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mzlqxfSu8c3xrI9tD4_iig.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iccv2wTinKoek1fzJREmZg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OWik5WbQ-zZcNNgUU8IVvA.png" /></figure><p><a href="https://github.com/irfnyas/done">GitHub - irfnyas/done: DONE is a minimalist, context-aware macOS productivity overlay that monitors your active application and uses local AI (via Ollama) to suggest relevant shortcuts and actions.</a></p><p>If you’re interested in the code, check out the <a href="https://github.com/irfnyas/done">repository here</a>. Desktop and mobile app also <a href="https://github.com/irfnyas/done/releases">available here</a>, currently for MacOS and Android.</p><h3>The Job isn’t Done</h3><p>This project showed me that even small innovations (like context‑aware shortcuts) can spark bigger ideas about the next wave of human and computer interaction. I believe the future of productivity isn’t about “more apps”, but a thinner layer between our thoughts and our tools.</p><p>DONE is just the beginning, and the job isn’t done. Thank you for reading, happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3bb255cf6971" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Vibecoded My Own Virtual Gamepad]]></title>
            <link>https://irfnyas.medium.com/vibecoded-my-own-virtual-gamepad-7ef61598101e?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/7ef61598101e</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[flet]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Thu, 12 Feb 2026 03:43:50 GMT</pubDate>
            <atom:updated>2026-02-12T03:43:50.835Z</atom:updated>
            <content:encoded><![CDATA[<h4>Why does the Python cross the bridge? To draw its face.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4ClaZ3TLB54yC-Df" /><figcaption>Photo by <a href="https://unsplash.com/@ravipalwe?utm_source=medium&amp;utm_medium=referral">Ravi Palwe</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>It all started with a simple curiosity:<br><strong>Can I simulate keyboard input on my PC using my phone?</strong></p><p>So, I did what any modern dev does: I asked the AI.<br>The reply was instant: <em>“It is absolutely possible.”<br></em>That was all the spark I needed.</p><h3><strong>I Have No Money, But I Have AI</strong></h3><p>I looked into existing solutions like <a href="https://www.monect.com/subscription">Monect</a>. It’s a great app, but it has ads unless I go premium. So let’s vibecode it — I’m getting bored anyway.</p><p>The AI sketched out a simple two‑part architecture:<br>1. <strong>Desktop: </strong>A Python script acting as a bridge.<br>2. <strong>Phone: </strong>A Flutter app.</p><p>It initially suggested emulating an Xbox controller instead of a keyboard, since my original intent was gaming. At first, it sounded cool, until I realized it required extra <a href="https://github.com/ViGEm/ViGEmBus">third-party drivers</a>. I wanted this to be plug-and-play, so I stuck with keyboard emulation. Later I discovered that by sticking to it, I unlocked something even better: <strong>total customizability</strong>.</p><p>I wasn’t just building a gamepad. I was building a tool that could work for gaming, productivity apps, or even a DIY Stream Deck.</p><p>What surprised me most was how little code it took to get the MVP running. The Python script needed just one package (`pynput`) and less than 80 lines of code. The Flutter side didn’t even need extra dependencies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IUpf6cUPz9WG0YQeG6bwaw.png" /><figcaption>The python script (connected)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RpJPJIU9AeWXijpGF7CCcw.jpeg" /><figcaption>The flutter app (connected)</figcaption></figure><h3><strong>Beyond the “F” Key: Customization &amp; Emojis</strong></h3><p>Once the connection worked, I started iterating. The best part? The ability to <strong>customize layouts</strong>.</p><p>By customizing it, I improve the <strong>visual language.</strong> Instead of a button labeled “F,” I could label it “👊.” Instead of “M” for mute, I could use “🔇.” It makes the digital experience feel tailored and modern. You aren’t just hitting keys; you’re interacting with a custom dashboard.</p><p>The dashboard now felt alive, but I wanted to take it further. To push the limits of customizability, I moved beyond hardcoded configurations and built a <strong>JSON‑based layout engine</strong>.</p><p>This transformed the app into a modular platform. Every button is defined through a structured JSON schema, making layouts infinitely extensible. One day it’s a classic NES pad, the next it’s a control deck for video editing, all swappable in an instant.</p><p>Even more exciting, this architecture paves the way for a community‑driven ecosystem where users can share their perfectly tuned configurations as JSON files in the future.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ICUehMYRpuBPqTBJp7KsVg.jpeg" /><figcaption>Customizing the layout</figcaption></figure><h3><strong>From Terminal to GUI</strong></h3><p>I was happy with the mobile side, but the desktop side was still just a terminal window. What I really wanted was a proper desktop app. So I asked the AI for a way to turn my Python script into a GUI, and it suddenly vibecoded the script with <a href="https://flet.dev/"><strong>Flet</strong></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GhB5JaMs8pj00nLvK20iMQ.png" /><figcaption><a href="https://flet.dev/">Flet Landing Page</a></figcaption></figure><p><strong>Flet</strong> is a framework that lets you build multi-platform apps in Python, driven by the Flutter engine. It gave me a way to keep my Python logic intact while wrapping it in a real interface. Exactly what I needed.</p><p>Unfortunately, my first experience with Flet was rough. The UI looked fine with its Material theme sure, but the app only worked in debug mode, not in release mode. <em>(feeling a little bit deja vu here)</em></p><p>The artifacts were built, yet every time I tried to run them, the app crashed. This is where I learn another thing about prompting: <strong>Persistence.</strong></p><p>It became a loop that felt almost recurring:<br>1. <strong>I test.<br></strong>2. <strong>It crashes.<br></strong>3. <strong>I copy-paste the crash report to the AI.<br></strong>4. <strong>The AI tries to fix the logic.</strong></p><p>I was the tester, and Gemini was the engineer tackling edge cases. Eventually we cracked it, <em>like a team</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N27_B8U7SuZiZeK9EdoB9Q.png" /><figcaption>The snake has shown its face.</figcaption></figure><h3>From Curiosity to Community</h3><p>Since I built it using vibecode, I might as well give back to the community and make the project open source. It’s only barely working for now, but it’s a start. I’ve uploaded the Android <em>.apk</em> and macOS <em>.app</em> to the <a href="https://github.com/irfnyas/vgamepad/releases">repository</a> if you’d like to try them out.</p><p>Thanks for reading, happy coding.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/576/1*KE1aLpdDDKIHKpPGJICBlw.gif" /><figcaption>Chill.</figcaption></figure><p><a href="https://github.com/irfnyas/vgamepad">GitHub - irfnyas/vgamepad: Flutter gamepad with python sever</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7ef61598101e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Staying Agile in Super App]]></title>
            <link>https://irfnyas.medium.com/staying-agile-in-super-app-4ebce1c6bebd?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/4ebce1c6bebd</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Fri, 26 Dec 2025 12:26:51 GMT</pubDate>
            <atom:updated>2025-12-26T14:59:54.684Z</atom:updated>
            <content:encoded><![CDATA[<h4>Avoiding deadlines pressure and adapting to sudden changes with micro-frontend architecture</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*w7mNpIa8tfwUTakX" /><figcaption>Photo by <a href="https://unsplash.com/@randyfath?utm_source=medium&amp;utm_medium=referral">Randy Fath</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In my previous post last year, I explored the concept of micro-frontend architecture. This time, I want to move beyond theory and discuss a technical approach that’s been validated in production. But first, let’s briefly revisit what micro-frontend architecture is.</p><p><a href="https://irfnyas.medium.com/reimagining-super-app-frontend-architecture-235dc8c88869"><em>See more: Reimagining Super App Frontend Architecture | Medium</em></a></p><h3>Micro-frontend architecture</h3><p>Micro-Frontend Architecture is an architectural style where independently deliverable frontend applications are composed into a greater whole.</p><p>If you’re already using a WebView inside your mobile app, you’re essentially on the path toward adopting this style. It’s important to note that micro‑frontends differ from modular architecture, which I discussed in my <a href="https://irfnyas.medium.com/reimagining-super-app-frontend-architecture-235dc8c88869">previous post</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BqSev3J08dQTBakh1bx_MQ.png" /><figcaption><a href="https://martinfowler.com/articles/micro-frontends.html"><em>https://martinfowler.com/articles/micro-frontends.html</em></a></figcaption></figure><p>Some of the key benefits that we’ve seen from micro-frontends are:</p><ul><li>smaller, more cohesive and maintainable codebases</li><li>more scalable organisations with decoupled, autonomous teams</li><li>the ability to upgrade, update, or even rewrite parts of the frontend in a more incremental fashion than was previously possible</li></ul><p>In the context of mobile app development, this translates to:</p><ul><li>A single app serving as the backbone for multiple frontend services delivered via WebView</li><li>Ability to update individual services without rebuilding the entire app</li><li>Freedom to deploy changes instantly through the WebView, without waiting for store reviews</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bcWOnO9bQ2KJ8GFJwdAxhg.png" /><figcaption>A single app serving as the backbone for multiple frontend services delivered via WebView</figcaption></figure><h3>Why do we even need this?</h3><p>Super app means multiple services live inside one app. The problem is that even minor changes to a single service will force a rebuild of the entire app. And when external partners or third parties are involved, sudden changes are inevitable, and we need to be prepared. <em>Trust me, it happens.</em></p><p>This architecture will help in two critical cases:</p><ol><li><strong>Launching complex new services:</strong> <em>services with rich menus and advanced functions evolve quickly. Micro‑frontends let them flourish independently, with faster iteration and deployment than the super app itself.</em></li><li><strong>Displaying services through WebView with secure access:</strong> <em>Sometimes a new service needs to be displayed through a WebView, but direct access isn’t possible because the web requires a specific token. By handling the bridging outside the super app, we enable seamless and secure integration.</em></li></ol><h3>How it works</h3><p>Since my app are built with Flutter, I’ll illustrate this approach using two repositories:<strong> the super app </strong>and a <strong>flutter web app</strong>. The super app uses <a href="https://pub.dev/packages/flutter_inappwebview">flutter_inappwebview</a> for embedding webviews, while flutter web app leverages <a href="https://dart.dev/interop/js-interop">js_interop</a> for JavaScript communication.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ygi1d9mtpuGz-mwXINYRog.png" /></figure><h4>Why Flutter Web Instead of Native JS?</h4><ul><li><strong>Ownership</strong>: Because the service falls under the responsibility of mobile engineers, it’s better to use tools they’re already familiar with.</li><li><strong>Exit strategy: </strong>easier to refactor back into the super app if needed.</li></ul><h4>Example: Auth Token Management in Webview</h4><p>Here’s a practical example of how authentication tokens are managed when connecting the WebView and synchronized between the super app and the WebView:</p><ol><li>Super app sends access_token and refresh_token into web session storage.</li><li>When access_token is needed but found to be <strong>expired or null</strong>, the system checks refresh_token.</li><li>If refresh_token <strong>valid</strong>: frontend calls userRefreshToken. This triggers GET /profile in the app, refreshing both tokens. Updated tokens are sent back to session storage.</li><li>If refresh_token <strong>expired or null:</strong> the frontend calls userSignIn to open the app&#39;s login screen over the WebView. On successful login, new tokens are issued and stored. On failure, the user stays logged out.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZGRMEVoXIt9oGvq3estong.png" /></figure><h3>Implementation Guide</h3><h4>1. Super app: Add JS handler in inAppWebviewController</h4><pre>inAppWebViewController.addJavaScriptHandler(<br>  handlerName: &#39;myHandlerKey&#39;,<br>  callback: (args) async =&gt; doSomething(args),<br>);</pre><h4>2. Web: add JS handler in js.dart, index.html, and index.js</h4><pre>/* lib/js.dart */<br><br>/// Needed to call JS function from dart<br>/// Note: function name&#39;s needs to be the same as the function on index.js<br>@JS()<br>external JSPromise? runJs(String key, JSAny? args);<br>/// Call this when we need to perform transaction with super app.<br>/// key: handler name&#39;s which we defined in inAppWebViewController<br>/// args: only dart primitives, iterables, typed lists, and maps are supported<br>Future&lt;dynamic&gt; runJsToDart(String key, dynamic args) async {<br>  try {<br>    JSAny? argsJs;<br>    if (args is List) argsJs = args.jsify();<br>    if (args is Map) argsJs = [args].jsify();<br>    if (args is String) argsJs = [args.toJS].toJS;<br>    if (args is num) argsJs = [args.toJS].toJS;<br>    if (args is bool) argsJs = [args.toJS].toJS;<br>    return await runJs(key, argsJs)?.toDart;<br>  } catch (e) {<br>    return null;<br>  }<br>}<br>/* web/index.html */<br>&lt;body&gt;<br>  ...<br>  &lt;script defer src=&quot;index.js&quot;&gt;&lt;/script&gt;<br>&lt;/body&gt;<br><br>/* web/index.js */<br><br>// make sure that window is ready to call handler<br>var isFlutterReady = false;<br>window.addEventListener(&quot;flutterInAppWebViewPlatformReady&quot;, function (_) {<br>  isFlutterReady = true;<br>});<br>// run this function to communicate with super app<br>// Note: function name&#39;s needs to be the same as the function on js.dart<br>async function runJs(key, args) {<br>  if (!isFlutterReady) return;<br>  return await window.flutter_inappwebview.callHandler(key, ...(args ?? []));<br>}</pre><p><strong>3. Web: Deploy your flutter web</strong></p><p>I chose Netlify for no other reason than covid plan.<br><a href="https://medium.com/stackademic/when-mobile-developer-meets-netlify-f66da9767445"><em>See more: When Mobile Developer meets Netlify | Stackademic</em></a></p><p><strong>4. Super app: Show your flutter web via WebView</strong></p><pre>final webUrl = &#39;my_flutter_web_url&#39;;<br><br>InAppWebView(initialUrlRequest: URLRequest(url: WebUri(webUrl));</pre><p><strong>Pro tips:<br></strong>Add a splash screen to your flutter web so it doesn’t display a blank space while loading inside the super app. I use <a href="http://flutter_native_splash/">Flutter Native Splash</a>.</p><h3>Performance comparison</h3><p>Using <a href="https://flashlight.dev/">Flashlight</a>, I tested performance with a ListView containing 1.000 items. The benchmark involved scrolling all the way to the bottom. The longer the scroll duration, the greater the scroll offset, which provided a consistent way to evaluate FPS, CPU, and RAM usage under load.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FglOLoJmnL9s%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fshorts%2FglOLoJmnL9s%3Ffeature%3Dshare&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FglOLoJmnL9s%2Fhq2.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/fc8596678d5931a6f5a85a4486d7a857/href">https://medium.com/media/fc8596678d5931a6f5a85a4486d7a857/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JixgXrvpQbhqJORsT0ztzw.png" /><figcaption>Left: Native — Right: WebView. Native shows lower avg FPS and higher CPU usage because it renders heavy animations directly. In contrast, WebView consumes more RAM due to the overhead of the WebView container.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9Y47Vyicbc2MmWKMAo57Nw.png" /><figcaption>Native experiences FPS drops, especially in the middle of heavy drawing operations. In contrast, WebView maintains more stable FPS since rendering happens inside the WebView container, with the only drop occurring at the start due to the heavy resources required to build the container. To obtain exact FPS measurements for the web itself, we would need to use Chrome DevTools; but that’s beyond the scope here, as my focus is on measuring the app’s FPS.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*unZ6zBaaV8gRxyxoWEMxTw.png" /><figcaption>Native starts with low CPU usage, but it grows heavier in the middle of complex animations, even exceeding 90% during the most demanding sequences. In contrast, WebView shows high CPU usage at the beginning due to the overhead of building the container, but remains stable afterward since most of the processing happens inside the web environment.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lvvWm-Uoa2ja4RiUVS6mIA.png" /><figcaption>Native starts with low RAM usage, but memory consumption increases once animations begin. In contrast, WebView requires higher RAM from the start due to the overhead of the container.</figcaption></figure><p>Both native and WebView approaches have their pros and cons. While writing code in native Dart generally delivers better performance, WebView remains a viable alternative especially when flexibility and faster deployment matter. You can explore the <a href="https://github.com/irfnyas/micro-fe-arch">test repository here</a><em>.</em></p><p><a href="https://github.com/irfnyas/micro-fe-arch">GitHub - irfnyas/micro-fe-arch: Performance test between native dart and web</a></p><h3>Exploring Related Implementations</h3><p>I’m looking for additional references on this mobile development architecture. The closest example I’ve found is Grab’s “JavaScript to Native Bridge Communication.” However, their approach isn’t quite the same as what we’re aiming for, since Grab’s implementation focuses on one-way communication: fetching data from the mobile side to be consumed within the WebView, cmiiw.</p><p><a href="https://github.com/grab/superapp-sdk">GitHub - grab/superapp-sdk: SDK for Grab SuperApp WebView.</a></p><h3>Closing Thoughts</h3><p>Managing two repositories (one for the super app and one for the flutter web) can feel like extra effort. But in my experience, the workload isn’t that heavy once the initial setup is complete. With only a small performance trade‑off, this approach solves one of the most frustrating challenges for mobile engineers:<strong> ability to deploy anytime without waiting for store reviews</strong>.</p><p>If you’re exploring more complex architectures and this approach seems right for your project, I encourage you to give it a try. It has saved me countless headaches when deadlines are tight and sudden changes arise. And if you have questions about this architecture or mobile development in general, feel free to reach out. I’d be glad to discuss further.</p><p>Thank you for reading and happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4ebce1c6bebd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Developer Experience from Mobile Engineering Perspective]]></title>
            <link>https://irfnyas.medium.com/developer-experience-from-mobile-engineering-perspective-27a14fffadde?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/27a14fffadde</guid>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Sun, 07 Sep 2025 11:42:35 GMT</pubDate>
            <atom:updated>2025-09-18T23:56:55.130Z</atom:updated>
            <content:encoded><![CDATA[<h4>Everybody always asks where’s UX, but never “How’s DX?”</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ev0UR4mj4kPha2_4" /><figcaption>Photo by <a href="https://unsplash.com/@neom?utm_source=medium&amp;utm_medium=referral">NEOM</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>A little while ago, I came across a tech talk titled <strong>“</strong><a href="https://www.instagram.com/p/DNhdRHzTVgS?img_index=2"><em>DX is New UX</em></a><strong>”.</strong> It immediately sparked my curiosity —DX, or Developer Experience, what exactly does that mean?</p><p>Looking closer, I realized DX isn’t really a new idea after all. It’s still about experience and productivity (as other ideas are), just not in the way we usually think.</p><p>When people talk about “experience”, the focus almost always lands on User Experience (UX). That makes sense, since UX ties directly to measurable outcomes like task success rates and, ultimately, profit.</p><p>Then, when it comes to “productivity”, they often reduce it to a simple equation: <em>“How many developers (X) do we need in Y months to finish module Z?”</em> But that mindset misses something crucial: the experience of the developers themselves.</p><p>Developers do care about their experience. That’s why we rely on IDEs, CI/CD pipelines, and countless other tools that make our work smoother. We just rarely take the time to stop and really think about it.</p><h4>So, what is <strong>Developer Experience (DX)</strong>?</h4><p>DX is the overall journey developers go through while building software. The goal is to make that journey as positive as possible.</p><p>When DX is poor, delivery slows, bugs pile up, and frustration grows. This hurts productivity, drives turnover, and makes it harder to attract new talent, ultimately dragging projects and lowering software quality.</p><p>In contrast, a strong DX allows developers to move faster, build better software, and stay motivated. It creates an environment where engineers are engaged, take pride in their work, and enjoy the process of building.</p><p>Importantly, DX isn’t about office perks or fancy amenities. It’s about removing barriers in the work itself, empowering developers to do what they do best: <strong>solve problems and create great software</strong>.</p><h3>The Core Dimensions: Feedback Loops, Cognitive Load, and Flow State in Mobile Engineering</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QWl-U1zRsG1N9Orx.png" /><figcaption><a href="https://newsletter.getdx.com/p/applying-the-devex-framework?utm_campaign=post&amp;utm_medium=web">Applying the DevEx framework</a></figcaption></figure><p>When we talk about developer experience, three dimensions always come up: feedback loops, cognitive load, and flow state. Mobile devs face the same dimensions, just with a different “flavor”.</p><h4>1. Feedback Loops</h4><p>Think of feedback loops as the heartbeat of development; the faster it beats, the quicker you can learn and improve. For mobile devs, this happens on two levels.</p><p>The <strong>inner loop</strong> is the immediate cycle: write some code, compile it, and see what happens on a screen. Unlike web, where you can just refresh the browser, mobile means dealing with heavy IDEs like Android Studio or Xcode, plus running apps on emulators or real devices with different screen sizes. When builds are slow or emulators laggy, that inner loop disrupts momentum. This is why features like Flutter’s hot reload are celebrated, they shorten the loop and keep developers in the zone.</p><p>Then there’s the <strong>outer loop: </strong>code reviews, testing, and deployment. On mobile, this is notoriously slow, with one extra hurdle: store reviews. Google Play or App Store review can take hours, even days. That delay stretches the time between writing code and getting it into user’s hands, adding friction that web or backend devs rarely have to face.</p><h4>2. Cognitive Load</h4><p>If feedback loops are about speed, cognitive load is about mental weight. Mobile devs carry a heavy backpack. Even if you’re focused on just Android or iOS, you can’t ignore the other platform if you want to keep features consistent. That means different design guidelines (Material Design vs. Human Interface Guidelines), different APIs, different languages (Swift vs. Kotlin), and tricky challenges like state or memory management.</p><p>Any tool that adds complexity, like a clunky cross-platform framework that doesn’t fully cover native APIs, or a CI/CD pipeline that behaves differently across platforms, just makes the backpack heavier. But tools that reduce complexity can feel like a breath of fresh air. For example, a solid CI/CD setup like Codemagic can help abstract away repetitive release tasks, easing the mental load.</p><h4>3. Flow State</h4><p>Flow is the pinnacle of developer productivity, that moment when everything clicks and you’re completely absorbed in the work. But for mobile devs, flow is fragile. Switching between IDEs, languages, docs, and the very different mental models of Android and iOS makes it harder to stay in the zone. Add in long builds, emulator slowdowns, or frequent context switching between tasks, and flow shatters fast.</p><p>This is why practices like unified design systems (to reduce platform context switching), and feature flagging tools (to test features without app store delays) are so valuable. They help protect flow and keep engineers focused on solving problems instead of fighting their environment.</p><h4>These Dimensions Are Foundational</h4><p>Together, these three dimensions shape the daily reality of mobile devs:</p><ul><li>Shorter feedback loops → more creativity.</li><li>Lower cognitive load → clearer thinking.</li><li>Stronger flow → deeper focus and better quality.</li></ul><p>Improving mobile DX starts with getting these foundations right. Of course, once you start talking about mobile, one question always comes up…</p><h4>What about cross-platform?</h4><p>Cross-platform frameworks promise to make life easier, and to some extent they do. By reducing context switching, developers can focus on a single codebase instead of juggling both Android and iOS. But the trade-offs are real:</p><ul><li>You’ll likely need to learn a new language (Dart for Flutter, JS for React Native).</li><li>Native skills never fully disappear. You still need Kotlin or Swift when bridging to platform-specific APIs.</li><li>Yes, you can use lighter editors like VS Code, but you still have to run apps on emulators or real devices, with all the same slowdowns.</li><li>And at the end of the day, the app store rules don’t go away. You’ll still face Google Play and App Store reviews just like native developers.</li></ul><p>Cross-platform makes some things easier, but not everything. It smooths out some pain points, especially around maintaining two codebases, but many of the core challenges of mobile DX (slow feedback loops, high cognitive load, fragile flow) are still very much there.</p><h4>Surely AI will helps?</h4><p>AI is already making their mark on software development. Companies like Google and Microsoft report that nearly a third of their new code is AI-generated, with some teams seeing productivity boosts of 50% or more.</p><p>But speed isn’t the whole story. Alongside the gains, studies show AI can also introduce deeper issues like architectural flaws, privilege problems, and hidden vulnerabilities that often slip past reviews.</p><p>In mobile engineering, things get even trickier. For AI to truly become a game-changer in mobile DX, it needs to be useful in a few key areas:</p><ul><li><strong>Complex build setups:</strong> Mobile build systems are known for slowing developers down. If AI could reliably manage Gradle, Android Manifest, Info.plist, and Xcode configs, it could dramatically shorten the cycle from “write code” to “see it running” making iteration smoother and faster.</li><li><strong>Architectural context:</strong> Mobile projects are more than just isolated files. AI has the potential to reduce the mental overhead by understanding the bigger picture: state management, navigation flows, native bridges, and generating code that naturally fits into existing architectures.</li><li><strong>UI and UX nuance:</strong> If AI learns to handle responsive layouts, state-driven UIs, and platform-specific design guidelines, it could free developers from tedious layout fixes and let them focus on the creative side of building.</li></ul><p>The future of AI in mobile engineering goes beyond just writing code. When AI can support smoother feedback loops, lighten cognitive load, and protect flow, it won’t just make us faster — it will make the experience itself better.</p><h3>Environment, Career, and the DX Holding It Together</h3><p>Being a mobile devs comes with some very specific quirks. If you’re building for iOS, you’re locked into macOS hardware, no way around it. That’s a big constraint (and cost) for both engineers and organizations. On top of that, the IDEs we use are powerful but heavy. They demand high-performance machines, and even then, builds can feel painfully slow.</p><p>The industry is pushing toward cloud-based development environments like GitHub Codespaces and Firebase Studio to make setup easier and onboarding smoother. But for mobile, those tools aren’t quite there yet, at least for me.</p><p>Beyond the technical environment, there’s also the question of career trajectory. Many mobile specialists run into what’s often called the <em>frontend ceiling</em>. The idea is that engineers who go deep into mobile (or frontend in general) can find it harder to reach top technical leadership roles like CTO. Why? Because their work is often perceived as being “far from the core”: things like scalability, architecture, and systems design, which are seen as central to running large-scale tech organizations.</p><p>That perception creates a long-term DX challenge: how do you keep senior mobile devs motivated when the path to the very top seems narrower? Some move into management, others expand into full-stack, but many struggle with this ceiling.</p><p>This is where DX shows its true value: it’s more than just a productivity boost. A well-designed DX can make the day-to-day work feel meaningful, keeping senior specialists motivated. In the end, great DX transforms mobile engineering from a frustrating grind into a craft worth sticking with.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6Yers2UZHFEKsqSU" /><figcaption><a href="https://frontendatscale.com/issues/39">Breaking the Frontend Ceiling</a></figcaption></figure><h3><strong>Measuring and Diagnosing Mobile DX Friction using Hybrid Measurement Framework</strong></h3><p>The best way to understand DX is through a<strong> </strong>hybrid framework: a mix of quantitative data and real feedback from developers about their everyday experience.</p><p>Why both? Because numbers can lie. A CI system might proudly report a “fast” 10-minute build, but if developers perceive it as painfully slow, then <em>it is painfully slow</em>. On the flip side, if you only rely on surveys, you risk chasing complaints without understanding the technical root causes.</p><h4>DORA Metrics for Quantitative Analysis</h4><p>The DevOps Research and Assessment (DORA) metrics are the industry standard for measuring software delivery performance. They show how well teams balance speed and stability through four key metrics:</p><ul><li>Deployment Frequency (DF): how often code reaches production.</li><li>Lead Time for Changes (LTFC): how long a commit takes to go live.</li><li>Change Failure Rate (CFR): how often releases cause issues.</li><li>Mean Time to Restore (MTTR): how quickly you recover from a failure.</li></ul><p>They’re super useful, but here’s the thing: mobile is different.</p><ul><li>Deployment Frequency: Frontend (web) and backend can deploy to production anytime they want. Mobile? You’re gated by store reviews. Instead of counting daily production pushes, it makes more sense to track how often you ship builds to testers and how frequently you release to the app stores.</li><li>Lead Time for Changes: On mobile, LTFC is messy. A single commit must go through code review, CI builds, distribution to testers, and then store review, adding hours or even days.</li><li>CFR &amp; MTTR: Still relevant, but cycle times are longer on mobile, so interpretation needs extra care.</li></ul><p>And remember: DORA metrics are lagging indicators. They tell you there’s a problem, but not <em>why</em>. If LTFC is high, the real issue is usually friction in the inner loop: the cycle of coding, building, testing. That’s where you need more mobile-specific metrics, like:</p><ul><li>Local Build &amp; Compilation Time: clean vs. incremental build times.</li><li>Test Suite Execution Time: how long it takes to run unit/UI tests locally.</li><li>Emulator/Simulator Boot Time: a frequent task that can break a developer’s flow.</li><li>App Performance Metrics: key user-facing measures like startup time (TTID) and rendering smoothness (dropped frames/jank).</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VL4GZkxCBcAZSZH8" /><figcaption><a href="https://platformengineering.org/talks-library/track-dora-devops-metrics-with-logilica-and-humanitec">How to track DORA metrics with Logilica &amp; Humanitec</a></figcaption></figure><h4>The Voice of the Developers as Qualitative Insights</h4><p>Metrics tell you what’s happening. Developers tell you why. Structured surveys, if done right, can map feedback directly to DX dimensions:</p><ul><li>Feedback loops: “How quickly can you test local changes?”</li><li>Cognitive load: “How confident are you making changes to the codebase?”</li><li>Flow state: “How easy is it to get uninterrupted focus time?”</li></ul><p>Other sentiment checks include:</p><ul><li>Developer Satisfaction (DevSat): Overall satisfaction with tools and processes.</li><li>Employee Net Promoter Score (eNPS): Would you recommend this place to a friend?</li><li>Retention rates: The slowest but clearest signal. If people keep leaving, DX is failing.</li></ul><p>Averages hide pain. The problems of a senior mobile are very different from those of a senior backend. That’s why qualitative data must be segmented by team, platform, and seniority. Otherwise, you risk missing hotspots where DX is quietly draining morale.</p><p>A healthy DX program isn’t about one-off surveys or dashboards, it’s about building a sustainable loop of measurement and dialogue. A solid program usually includes:</p><ul><li>Establishing a baseline for key metrics.</li><li>Running quarterly surveys to track sentiment.</li><li>Continuously monitoring system data.</li><li>Setting up real-time feedback channels (Slack, forums, 1:1, etc).</li></ul><p>This program keeps DX visible and gives engineers a voice in shaping it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*wAW72-8PnDJWjKmV" /><figcaption><a href="https://getdx.com/blog/developer-experience-survey">Choosing what to measure in your developer experience survey</a></figcaption></figure><h3>Why DX Matters</h3><p>Mobile engineering will always come with unique constraints: from store reviews to heavy toolchains and platform quirks. But those constraints don’t have to define the developer experience. The real opportunity is in reducing friction, protecting flow, and listening to the people who build. If we want better apps, we need to start with better DX. Because great developer experience is the foundation of great software.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1iUM53fxAnUzzzdJ.jpg" /><figcaption><a href="https://unionvk.com/tpost/xollnh4nk1-developer-experience-poisk-schastya-dlya">Developer Experience: Finding Happiness for the Technical Team</a></figcaption></figure><p>Thanks for reading, happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=27a14fffadde" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Become a Proper Mobile Engineer]]></title>
            <link>https://irfnyas.medium.com/how-to-become-a-proper-mobile-engineer-efc678fc6331?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/efc678fc6331</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[reflections]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Wed, 07 May 2025 17:40:07 GMT</pubDate>
            <atom:updated>2025-05-08T02:32:41.782Z</atom:updated>
            <content:encoded><![CDATA[<h4>Refleksi diri tentang apa yang membuat seseorang layak disebut kompeten dalam Mobile Engineering</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*huCwt0w18F_qXKyb" /><figcaption>Photo by <a href="https://unsplash.com/@jplenio?utm_source=medium&amp;utm_medium=referral">Johannes Plenio</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Selama lebih dari lima tahun berkarier, saya beruntung memiliki pengalaman membantu rekan-rekan yang baru memulai perjalanan di dunia engineering.</p><p>Dalam satu kesempatan, saya menjadi mentor bagi seorang intern. Di kesempatan lain, saya dipercaya membimbing sesama engineer agar lebih mandiri dalam mengambil keputusan teknis. Meski konteksnya berbeda, tujuannya sama: mendukung mereka menjadi mobile engineer yang kompeten.</p><p>Tapi, seperti apa kompetensi itu terlihat dalam keseharian? Setelah banyak berdiskusi, membaca literasi, dan mengamati para engineers yang saya anggap kompeten, muncul sebuah pola — hal yang saya perhatikan saat menilai kemampuan seorang mobile engineer.</p><h4>1. Environment Setup</h4><p>Yang pertama adalah cara dia melakukan <strong>Environment</strong> setup. IDE apa yang digunakan, bagaimana version controlnya, dan tech stack apa yang dipilih.</p><ul><li>Tidak ada IDE yang sempurna, tetapi seorang engineer yang kompeten punya alasan kuat dalam memilih alat yang digunakan.</li><li>Pemahaman mendalam tentang konsep versioning, terutama Git, adalah mutlak. Ini bukan hanya tentang kolaborasi, tetapi juga narasi yang ingin seseorang bawa dalam proses menulis baris kode hingga menjadi sebuah aplikasi.</li><li>Mencoba berbagai stack adalah hal yang diharuskan, tetapi kita perlu memiliki alasan dari pilihan yang digunakan.</li></ul><h4>2. Development Process</h4><p>Yang kedua adalah proses <strong>Development</strong>. Mulai dari arsitektur kode, strategi debugging &amp; testing, hingga pendekatan terhadap git branching.</p><ul><li>Arsitektur mempengaruhi seberapa fleksibel kode yang ditulis saat dibenturkan dengan perubahan. “Satu-satunya yang konstan adalah perubahan”.</li><li>Debug &amp; Test Strategy yang matang mencerminkan seberapa dalam pemahaman seseorang terhadap kode yang ditulis serta seberapa percaya diri terhadap hasil kerjanya.</li><li>Git branching strategy juga perlu diperhatikan. Jika memang bekerja sendiri dan butuh iterasi cepat, apa membuat banyak branch masih relevan?</li></ul><h4>3. Deployment Strategy</h4><p>Yang terakhir adalah strategi <strong>Deployment</strong>. Meliputi penerapan CI/CD, proses publikasi aplikasi ke store, serta pemanfaatan tools monitoring.</p><ul><li>Memasang CI/CD memang lumrah, tapi terkadang build manual dan kirim Google Drive lebih murah. Prinsip idealis seseorang akan diuji saat dipertemukan limit bulanan.</li><li>Belum lengkap ilmu seorang mobile engineer jika belum pernah melewati proses rilis aplikasi ke store.</li><li>Pengembangan tidak berhenti setelah rilis. Tools monitoring dibutuhkan untuk memahami bagaimana user berinteraksi dengan aplikasi dan apa yang bisa diimprovisasi.</li></ul><p>Jika dalam ketiga aspek ini seseorang bisa menjelaskan pilihannya tanpa ragu, maka dirinya layak disebut sebagai mobile engineer yang kompeten.</p><p><strong>Dan jika kamu sedang dalam proses menuju ke sana — teruslah berjalan. Kompetensi tidak dibangun dalam sehari, ia tumbuh dari keputusan-keputusan kecil yang konsisten.</strong></p><p>Thanks for reading, happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=efc678fc6331" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reimagining Super App Frontend Architecture]]></title>
            <link>https://irfnyas.medium.com/reimagining-super-app-frontend-architecture-235dc8c88869?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/235dc8c88869</guid>
            <category><![CDATA[super-app-development]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[frontend-architecture]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Mon, 25 Nov 2024 07:24:02 GMT</pubDate>
            <atom:updated>2024-12-05T02:09:05.330Z</atom:updated>
            <content:encoded><![CDATA[<h4>Mobile, web, and everything in between</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YaLwmNZb-3sHNMlz" /><figcaption>Photo by <a href="https://unsplash.com/@franciscomoreno?utm_source=medium&amp;utm_medium=referral">Francisco Moreno</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>What is a Super App?</h3><p>A super app is a single platform that integrates a variety of services, allowing users to complete multiple, diverse tasks without switching between separate applications. Each feature within a super app is modular and could function independently as a standalone application.</p><p>One example of a super app is <a href="https://jabarprov.go.id/sapawarga">Sapawarga</a>, a government-backed app launched by the West Java provincial government in Indonesia. Users can access public services, file taxes, report issues, find local job listings, order tickets for gallery visits, and more — all within a single app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r3XeEkwsWKPP-5lcHoa3-w.png" /><figcaption>While each of these services could exist as separate apps, Sapawarga seamlessly brings them together</figcaption></figure><h3>How will you build a super app?</h3><p>Building a super app requires “super” thought. Imagine this: we’re tasked with building a new <strong>Super App</strong> — a single application that offers multiple services, combining everything our users need into one seamless experience. This means:</p><ul><li>The app will serve as a hub for <strong>multiple services</strong>.</li><li>Users will only need to install <strong>this app</strong> to access all our services.</li><li>It must accommodate both <strong>internally developed services</strong> and those created by <strong>external partners</strong>.</li></ul><p>As engineers, the default approach to building an app is using <strong>monolith architecture</strong>. In the context of a super app, this usually translates to creating a new folder within the codebase every time a new service is introduced.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*QjLJ96_B90x2fEXdJf4keg.png" /><figcaption>Imagining Sapawarga in Monolith Architecture</figcaption></figure><p>Sure, we can develop this way. However, as the app grows in complexity, this approach starts to reveal significant drawbacks:</p><ol><li><strong>Slower Updates for Individual Services</strong><br>When all services live in a single codebase, releasing updates often involves bundling changes for multiple services together. This bulk update strategy may minimize the overhead of App Store rollouts, but it comes at the cost of being agile. A small update for one service is delayed because it’s tied to unrelated changes in other services.</li><li><strong>Delays in Delivering Features or Hotfixes</strong><br>When updates are slow, so is the delivery of new features or critical hotfixes. This delay can frustrate users who expect fast responses to issues or new functionality. Over time, the inability to address issues quickly erodes user trust and satisfaction.</li><li><strong>Negative Impact on User Experience and Public Perception</strong><br>Poor user experience caused by delays in updates reflects directly on the perception of our app — and by extension, our company. Users may view us as unresponsive or outdated, which could lead to disengagement and loss of market share in a competitive landscape.</li></ol><p>Now, we think, <em>“Alright, let’s adopt a </em><strong><em>modular architecture</em></strong><em>.”</em></p><p>We will refactor the service folders into independent modules, treating each as its own package and importing them as dependencies into the main codebase. It feels like a cleaner, more scalable solution. We publish the app, confident that we’ve addressed the challenges.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*Ng1Dh0SLT0z7aGMYuuXH3w.png" /><figcaption>Imagining Sapawarga in Modular Architecture</figcaption></figure><p>But then, when it’s time to update just one service, we find ourselves facing the same limitations. Despite the modular structure, the core bottlenecks remain unchanged. The result? We’re back at square one, wondering if there’s a better way forward.</p><h3>How about Microservices, but for Frontend?</h3><p>When it comes to backend development, one term often stands out: <strong>microservices</strong>. While the concept is similar to modular architecture, the key difference is that each service in a microservices model runs independently.</p><p>In the context of frontend development, we can draw a parallel to <strong>micro frontends architecture. </strong>While the concept is the same — breaking down large, monolithic apps into smaller, independent pieces — the difference lies in how these smaller pieces are integrated into the frontend.</p><p>If you have already developed an app that uses a webview to support a service, chances are you’ve already implemented micro frontends in some capacity. This approach allows services to be updated on demand, without rebuilding the entire app. It would be as if the tourism service operated as its own standalone app, allowing updates to be deployed without building the entire app codebase.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xZjqM3WaWh_2ouo0.png" /><figcaption><a href="https://martinfowler.com/articles/micro-frontends.html">Micro Frontends by Martin Fowler</a></figcaption></figure><p>However, this doesn’t mean all services should rely on webviews. While webviews enable faster updates, they lack the seamless performance of native apps. Features like GPS, push notifications, and other mobile functionalities often require native coding to work effectively. Moreover, an app overloaded with webviews may face rejection from App Store.</p><p>The key is mastering the balance: knowing when to build a service natively for performance and functionality, and when to use a modular or webview-based approach for flexibility. Consider building a service modular if it meets these criteria:</p><ol><li>The service is unlikely to require native mobile features.</li><li>The service is heavily reliant on external partners.</li><li>The service has a higher priority, requiring faster updates or independent scalability.</li></ol><p>If a service checks all these three points, then it’s an excellent candidate for the next modular implementation.</p><h3>Exploring the Technical Challenges Ahead</h3><p>As we adopt a micro frontends architecture to handle the increasing complexity of a Super App, two key challenges often arise: <strong>consistency</strong> and <strong>communication</strong>.</p><h4>1. Consistency Across Services</h4><p>To deliver a seamless user experience, all services must follow<strong> consistent design principles</strong> across the Super App. This involves not only ensuring a unified look and feel but also maintaining visual and functional consistency, regardless of the underlying technology.</p><p><strong>Performance consistency </strong>is equally critical. While modules using webviews may experience reduced performance, it’s important to ensure that the difference remains minimal. The goal is to create an experience where performance fluctuations are almost imperceptible to the user, ensuring smooth interaction across all modules.</p><p><strong>State consistency</strong> is another essential element. For instance, if a user has signed in through the main app, all modular services should recognize and reflect this signed-in state. This sync goes beyond design and performance — it extends to how information flows between services, which brings us to the next challenge: <strong>communication</strong>.</p><h4>2. Communication Between Modules</h4><p>Consider a Super App where the main app is built using Flutter Mobile, while its modules use various frameworks like Flutter Web and VueJS. These modules must communicate and share state with the main app seamlessly, despite being built with different technologies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XK_8g8RbXM7_6Se2pr03YQ.png" /></figure><p>For modules presented through webviews, communication between the Super App and individual modules can be tricky. One strategy we can use is to create a communication bridge using JavaScript to pass data between the app and the module. In this case:</p><ul><li>The Super App sends data to the module via JavaScript handler, which is intercepted by a listener in the module.</li><li>The module then sends data back to the Super App, which is handled by a handler in the main app.</li></ul><p>This process creates a bidirectional communication flow, ensuring that the main app and its modules stay in sync. The data flow might look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CvVpFNqfdSwxh6ICNrdMlQ.png" /></figure><p>By addressing consistency and communication challenges effectively, we can ensure a smooth, unified experience across all modules, making the Super App not only functional but also capable of delivering high-quality user experiences.</p><h3>The Takeaway</h3><blockquote>To build a scalable Super App, adopting a <strong>micro frontends architecture</strong> can provide significant benefits. By ensuring that each module operates independently while maintaining frontend consistency, performance, and seamless communication, you can create an app that evolves quickly and continues to deliver high-quality user experiences, even as you add more services.</blockquote><p>Thank you for reading and happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=235dc8c88869" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[When Mobile Developer meets Netlify]]></title>
            <link>https://blog.stackademic.com/when-mobile-developer-meets-netlify-f66da9767445?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/f66da9767445</guid>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[netlify]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Tue, 12 Nov 2024 17:49:24 GMT</pubDate>
            <atom:updated>2024-11-14T02:21:43.684Z</atom:updated>
            <content:encoded><![CDATA[<h4>Building Flutter Android with Netlify: because why not?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UcwzilJvCv3261QrpZIYQw.png" /></figure><h3>Backstory</h3><p>Have you ever been in these situations?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/612/1*cVfXEe9AuRLSIBmTXPJ2rw.png" /><figcaption>Codemagic near limit</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/506/1*yc-I2nZZEGRM1x5z3XP2Dg.jpeg" /><figcaption>Github Actions also near limit</figcaption></figure><p>You wander over to the domain of your frontend colleague, take a peek at their Netlify setup, and see this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*aAzGQsbiE8pZr-xH-06how.png" /><figcaption>Cheat Mode: <a href="https://www.netlify.com/blog/2020/03/22/coronavirus/covid-19-support/">Coronavirus/COVID-19 Support</a></figcaption></figure><p>Why do they get all the free perks while we squeeze every last minute to build an artifact?</p><h3>The Netlify Plugin</h3><p>Netlify already supports Flutter Web using this <a href="https://www.netlify.com/integrations/community-built/flutter-sdk-build-plugin/">plugin</a>, but how can we extend it to support Flutter Android? If we check out the <a href="https://www.npmjs.com/package/netlify-plugin-flutter?activeTab=code">plugin’s code</a>, we can see it’s cloning the Flutter SDK and adding the flutter command to the PATH:</p><pre>...<br>console.log(&#39;⚡️ Downloading Flutter Stable SDK&#39;)<br>await run(&#39;git&#39;, [<br>  &#39;clone&#39;,<br>  &#39;https://github.com/flutter/flutter.git&#39;,<br>  &#39;-b&#39;,<br>  targetChannel,<br>  process.env[&#39;HOME&#39;] + &#39;/flutter&#39;,<br>])<br>console.log(&#39;✅ Flutter SDK downloaded&#39;)<br><br>console.log(&#39;🪄 Adding Flutter to PATH&#39;)<br>process.env[&#39;PATH&#39;] = process.env[&#39;PATH&#39;] + &#39;:&#39; + flutterBinPath<br>...</pre><p>Since we already have the Flutter SDK, what we need to add for building an Android artifact are Java and the Android SDK. So, let’s download both and add them to the PATH:</p><pre>...<br>/*<br>  Install Java<br>*/<br>console.log(&#39;☕️ Installing Java&#39;)<br>await run(&#39;wget&#39;, [javaDownloadUrl, &#39;-O&#39;, &#39;jdk.tar.gz&#39;])<br>await run(&#39;mkdir&#39;, [&#39;-p&#39;, javaPath])<br>await run(&#39;tar&#39;, [&#39;-xzf&#39;, &#39;jdk.tar.gz&#39;, &#39;-C&#39;, javaPath, &#39;--strip-components=1&#39;])<br>process.env[&#39;JAVA_HOME&#39;] = javaPath<br>process.env[&#39;PATH&#39;] = process.env[&#39;PATH&#39;] + &#39;:&#39; + javaPath + &#39;/bin&#39;<br>console.log(&#39;✅ Java installed&#39;)<br><br>/*<br>  Install Android SDK<br>*/<br>console.log(&#39;📥 Fetching latest Android cmd-line tools URL&#39;);<br>let androidSdkDownloadUrl;<br>try {<br>  androidSdkDownloadUrl = await getAndroidSdkDownloadUrl();<br>} catch (error) {<br>  console.error(&#39;Failed to get the tools download URL:&#39;, error);<br>  return build.failBuild(&#39;Could not fetch the Android SDK command-line tools URL&#39;);<br>}<br>console.log(&#39;✅ Latest URL:&#39;, androidSdkDownloadUrl);<br><br>console.log(&#39;📱 Installing Android SDK&#39;)<br>await run(&#39;mkdir&#39;, [&#39;-p&#39;, androidSdkPath])<br>await run(&#39;wget&#39;, [androidSdkDownloadUrl, &#39;-O&#39;, &#39;cmdline-tools.zip&#39;])<br>await run(&#39;mkdir&#39;, [&#39;-p&#39;, `${androidSdkPath}/cmdline-tools`])<br>await run(&#39;unzip&#39;, [&#39;cmdline-tools.zip&#39;, &#39;-d&#39;, `${androidSdkPath}/cmdline-tools`])<br>await run(&#39;mv&#39;, [<br>  `${androidSdkPath}/cmdline-tools/cmdline-tools`,<br>  `${androidSdkPath}/cmdline-tools/latest`,<br>])<br>process.env[&#39;ANDROID_HOME&#39;] = androidSdkPath<br>const env = {<br>  ANDROID_HOME: androidSdkPath,<br>  PATH: `${androidSdkPath}/cmdline-tools/latest/bin:${androidSdkPath}/platform-tools:${process.env[&#39;PATH&#39;]}`<br>}<br>await run(`${androidSdkPath}/cmdline-tools/latest/bin/sdkmanager`, [<br>  &#39;platform-tools&#39;,<br>  &#39;platforms;android-34&#39;,<br>  &#39;build-tools;34.0.0&#39;,<br>], { input: &#39;y\n&#39;, env })<br>console.log(&#39;✅ Android SDK installed&#39;)<br><br>/*<br>  Install Flutter<br>*/<br>console.log(&#39;⚡️ Installing Flutter SDK&#39;)<br>const targetChannel = &#39;stable&#39;<br>await run(&#39;git&#39;, [<br>  &#39;clone&#39;,<br>  &#39;https://github.com/flutter/flutter.git&#39;,<br>  &#39;-b&#39;,<br>  targetChannel,<br>  process.env[&#39;HOME&#39;] + &#39;/flutter&#39;,<br>])<br>process.env[&#39;PATH&#39;] = process.env[&#39;PATH&#39;] + &#39;:&#39; + flutterBinPath<br>console.log(&#39;✅ Flutter SDK installed&#39;)<br>...</pre><p>For easier use, I created a new Netlify plugin called <a href="https://www.npmjs.com/package/netlify-plugin-android">netlify-plugin-android</a>. You can check out the full code at the link provided.</p><h3>Installing the Plugin</h3><p><em>Keep in mind that this approach may only work with a newly created Flutter Android template, as the goal here is to demonstrate a proof of concept.</em></p><p>Please install this plugin from the Netlify app.</p><ol><li>Add the following to netlify.toml:</li></ol><pre>[[plugins]]<br>  package = &quot;/plugins/netlify-plugin-android&quot;<br>[build]<br>  command = &quot;flutter build apk &amp;&amp; flutter build web&quot;<br>  publish = &quot;build/web&quot;</pre><p>2. Add the following package files to plugins/netlify-plugin-android:</p><pre>plugins<br>  |__ netlify-plugin-android<br>      |__ src<br>      |   |__ index.js<br>      |<br>      |__ manifest.yml<br>      |__ package.json</pre><p>3. Add the following to app/build.gradle for building APK:</p><pre>android.applicationVariants.all { variant -&gt;<br>    variant.assemble.doLast {<br>        def outputFile = variant.outputs.first().outputFile<br>        copy {<br>            from outputFile.parent<br>            into file(&quot;${rootDir.parent}/build/web&quot;)<br>            include outputFile.name<br>        }<br>    }<br>}</pre><p>4. Trigger a new deploy. Your new artifact will be available at <a href="https://saparupa.netlify.app/app-release.apk">https://*.netlify.app/app-release.apk</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7Y35vXTkx5H_tbK4CkZkUw.png" /></figure><h3>My Take on Building with Netlify</h3><ul><li><strong>The build speed is comparable to Codemagic</strong>. My project’s build time on Netlify was 3m 52s, while on Codemagic it was 3m 46s.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/708/1*YWG74LS6rCDGx2phGtxz7A.png" /></figure><ul><li>While you’re at it, <strong>consider building the Flutter Web version too</strong>, and add a homepage (at least a splash screen) so it doesn’t show a 404 page.</li><li><strong>Codemagic remains a better option</strong> if you can afford the premium plan or rarely hit its build time limit.</li></ul><p>Feel free to ask questions or discuss on Github at <a href="https://github.com/irfnyas/netlify-plugin-android">irfnyas/netlify-plugin-android</a>. Thank you for reading and happy coding.</p><h3>Stackademic 🎓</h3><p>Thank you for reading until the end. Before you go:</p><ul><li>Please consider <strong>clapping</strong> and <strong>following</strong> the writer! 👏</li><li>Follow us <a href="https://twitter.com/stackademichq"><strong>X</strong></a> | <a href="https://www.linkedin.com/company/stackademic"><strong>LinkedIn</strong></a> | <a href="https://www.youtube.com/c/stackademic"><strong>YouTube</strong></a> | <a href="https://discord.gg/in-plain-english-709094664682340443"><strong>Discord</strong></a> | <a href="https://newsletter.plainenglish.io/"><strong>Newsletter</strong></a> | <a href="https://open.spotify.com/show/7qxylRWKhvZwMz2WuEoua0"><strong>Podcast</strong></a></li><li><a href="https://differ.blog/"><strong>Create a free AI-powered blog on Differ.</strong></a></li><li>More content at <a href="https://stackademic.com/"><strong>Stackademic.com</strong></a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f66da9767445" width="1" height="1" alt=""><hr><p><a href="https://blog.stackademic.com/when-mobile-developer-meets-netlify-f66da9767445">When Mobile Developer meets Netlify</a> was originally published in <a href="https://blog.stackademic.com/">Stackademic</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Summary on “5 Communication Skills You Need as an Engineering Manager”]]></title>
            <link>https://irfnyas.medium.com/summary-on-5-communication-skills-you-need-as-an-engineering-manager-18a03337024a?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/18a03337024a</guid>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[communication]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Wed, 30 Oct 2024 00:41:58 GMT</pubDate>
            <atom:updated>2024-10-30T00:43:39.823Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://medium.com/engineering-managers-journal/5-communication-skills-you-need-as-an-engineering-manager-8dd7e5ac05ea">5 Communication Skills You Need As An Engineering Manager | by Alex Ponomarev | Engineering Manager’s Journal | Oct, 2024 | Medium</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fmS3QWgwXaZjl6eS" /><figcaption>Photo by <a href="https://unsplash.com/@lunarts?utm_source=medium&amp;utm_medium=referral">Volodymyr Hryshchenko</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4><strong>1. Translating for upper management</strong></h4><p>Keep communication non-technical and easy-to-understand. They’re very busy people. So, all the information they need is:</p><ul><li>Project length</li><li>Project cost</li><li>Potential problems</li><li>The pros and cons of different approaches</li><li>And so on</li></ul><p>Sometimes, you’ll also make a decision yourself and then need to sell your solution to upper management. This requires explaining:</p><ul><li>What needs to be done</li><li>In what way</li><li>And why it’s the best option</li></ul><h4>2. <strong>Communicating precisely and concisely</strong></h4><p>This is the information your peers need to decide how they want to proceed an issue:</p><ul><li>What’s happening</li><li>Why it happened</li><li>How to stop it as soon as possible</li><li>The benefits and risks of possible solutions</li></ul><p>Just like upper management, your team members and peer managers don’t have time to waste. You have to communicate the essentials, which means:</p><ul><li>Saying what you need quickly and accurately</li><li>Making sure the other person or people understands you</li><li>Asking something clearly so the other person or people know how to accurately respond</li></ul><p>Also, make it a habit to minimize unhelpful conversations and keep meetings on point.</p><h4>3. <strong>Speaking to people in their own language</strong></h4><p>For example, project managers (PMs) won’t know technical speak, but engineers prefer technical precision. So, you have to adjust your language depending on which one you’re talking to.</p><p>Use things they care about to help get aligned on what needs doing. If I’m talking to someone who loves video games, I use games to describe what I want them to do.</p><h4>4. <strong>Helping people understand each other</strong></h4><p>This is especially necessary when the team members come from completely different worlds, like designers, engineers, and PMs. This isn’t easy, but it’s worth doing, and it requires:</p><ul><li>Understanding everyone’s perspectives</li><li>Learning everyone’s languages</li><li>Explaining both sides</li><li>And confirming everyone’s on the same page</li></ul><h4>5. <strong>Regulating emotions during conflict</strong></h4><p>People get emotional. You have to bring their emotions back to normal first, so they’ll be ready to listen to anyone. We do this in these ways:</p><ol><li><strong>Let them talk,</strong> they will have a grievance to share, and you won’t get anything in until they’ve run out of steam</li><li><strong>Ask them questions, </strong>to confirm that you’ve understood their grievance properly</li><li><strong>Add your own perspective,</strong> or add the perspective of the other person, doing both after they see that you’ve taken the time to understand them</li></ol><p>After these steps, you can model skills like apologizing or accepting apologies with grace.</p><p>The key is remembering that you have to address conflicts early before they make the team an unpleasant place to be and cause good people to leave.</p><blockquote>“Talking well takes work, but the results are worth the effort”</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=18a03337024a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Semua Package akan ‘deprecated’ pada Waktunya]]></title>
            <link>https://medium.com/jds-engineering/semua-package-akan-deprecated-pada-waktunya-c78e6f423df5?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/c78e6f423df5</guid>
            <category><![CDATA[package]]></category>
            <category><![CDATA[issues]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[mobile]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Wed, 22 Feb 2023 06:33:39 GMT</pubDate>
            <atom:updated>2023-03-13T02:24:30.681Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*IEAE-xOrSYJrVaje" /><figcaption>Photo by <a href="https://unsplash.com/@jiaweizhao?utm_source=medium&amp;utm_medium=referral">Jiawei Zhao</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Sebagai seorang flutter developer, tentu kamu tidak asing dengan <a href="https://pub.dev/">pub.dev</a> dan segala lika-likunya. Menggunakan <em>package</em> memang menyenangkan, tapi kadang kala tidak seindah kenyataan. Beberapa masalah yang umum kita temukan:</p><ul><li><em>Package</em> sudah deprecated</li><li><em>Package</em> belum memiliki fitur yang dibutuhkan</li><li><em>Package</em> tidak memiliki dokumentasi yang lengkap</li><li>Tidak ada <em>package</em>-nya 😅</li></ul><p>Tetap tenang, ada beberapa solusi yang bisa kamu coba untuk memperbaiki situasi ini.</p><h3>1. Buat issue baru (Level: Beginner)</h3><p>Langkah pertama yang bisa dilakukan adalah masuk ke halaman repository-nya dan membuat <em>issue</em> baru.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ws2voOePTjF8wLSN0_B4wg.png" /><figcaption>Klik link ‘Repository’ untuk lanjut</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wJ6bWp01L3DbUBJXfSatbw.png" /><figcaption>Setelah masuk ke halaman repository, cari halaman ‘Issues’ dan buatlah issue baru</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Cg3t4fHGmZ5g1n-q9sAqjg.png" /><figcaption>Tulis issue yang kamu miliki. Klik ‘submit’ dan tunggu hingga issue kamu direspon. Secara default, seharusnya kamu menerima email ketika issue kamu memiliki respon baru.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8RrQA9_TAMnGCjITiqOn-Q.png" /><figcaption>Jika kamu beruntung, owner repository akan langsung merespon issue-mu dan memperbaikinya dalam beberapa hari ke depan 😁</figcaption></figure><p>Bagaimana kalau kita tidak ada waktu untuk menunggu fix dari owner repository? Jika kamu yakin dengan kemampuan coding-mu, kita bisa mencoba solusi yang kedua.</p><h3>2. Fork Repository (level: intermediate)</h3><p>Kita akan melakukan fork repository dan memperbaiki packagenya sendiri. Solusi ini relatif lebih mudah ketimbang membuat package dari awal, tapi umumnya hanya dilakukan sebagai temporary fix.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vTU_np3dG3dwIcYqpDq5EA.png" /><figcaption>Masuk ke halaman utama repository dan klik ‘Fork’</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hUS0fZNiATT0AzL1n7natg.png" /><figcaption>Setelah fork sukses, clone repository dan buka dengan code editor</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3kpBiCNN_2mjVyIL-S0imA.png" /><figcaption>Lakukan perubahan yang dibutuhkan</figcaption></figure><p>Jika sudah beres melakukan perubahan, push kembali ke repository. Langkah berikutnya adalah menambahkan spesifik git pada dependency di <strong>pubspec.yaml</strong> project yang menggunakan <em>package</em> ini. Misal, hasil forked package <strong>focus_detector</strong> saya ada di branch utama <a href="https://github.com/irfnyas/focus_detector.git">https://github.com/irfnyas/focus_detector.git</a>, maka penulisannya nanti akan menjadi:</p><pre>dependencies:<br>  focus_detector:<br>    git: https://github.com/irfnyas/focus_detector.git</pre><p>Info lebih lengkap bisa baca di <a href="https://dart.dev/tools/pub/dependencies#git-packages">sini</a>.</p><p>Nah, sekarang bagaimana kalau ternyata kamu tidak menemukan <em>package</em> yang dibutuhkan? Jika tertarik, kamu bisa membuat package sendiri.</p><h3>3. Membuat package sendiri (level: advanced)</h3><p>Membuat package tidak sesulit kelihatannya. Untuk proses publikasi sebenarnya mudah, yang sulit adalah kompleksitas dari package itu sendiri.</p><p>Pertama kamu perlu membuat package project-nya. Kamu bisa melakukan ini menggunakan Flutter Wizard di Android Studio atau menggunakan command:</p><pre>flutter create --template=package {package name}</pre><p>Setelah project dibuat, tulis kode fungsi dalam folder <strong>lib</strong>. Lebih direkomendasikan jika kamu bisa menambahkan flutter test dan example project. Kamu bisa membuat example project dengan menggunakan command:</p><pre>flutter create example</pre><p>Jangan lupa meng-update <strong>CHANGELOG.md</strong>, <strong>LICENSE.md</strong>, dan <strong>README.md</strong>. Beberapa web yang bisa membantu kamu untuk hal ini:</p><ul><li><a href="https://keepachangelog.com/en/1.0.0/">keepachangelog.com</a>: Rekomendasi cara menulis changelog yang baik.</li><li><a href="https://choosealicense.com/">choosealicense.com</a>: Jika tidak yakin mau menggunakan license mana.</li><li><a href="https://pandao.github.io/editor.md/en.html">pandao.github.io</a>: Membantumu melihat preview readme.</li></ul><p>Sekarang <em>package</em> siap untuk publish. Kamu bisa menjalankan command flutter pub publish langsung, tapi lebih baik menggunakan --dry-run dahulu untuk memastikan package bebas dari warnings dan errors. Jadi, command yang perlu dimasukkan:</p><pre>flutter pub publish --dry-run<br>flutter pub publish</pre><p><strong>Selamat, package-mu akan segera muncul di </strong><a href="https://pub.dev/"><strong>pub.dev</strong></a><strong> 🎉</strong></p><p>Jangan puas dulu, artikel ini hanya membahas langkah minimal untuk mempublikasikan package. Masih ada cara untuk membuat package-mu lebih baik yang akan kita bahas di kesempatan lain.</p><p>Silakan isi kolom komen jika ada pendapat atau pertanyaan. Thanks for reading and happy coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c78e6f423df5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/jds-engineering/semua-package-akan-deprecated-pada-waktunya-c78e6f423df5">Semua Package akan ‘deprecated’ pada Waktunya</a> was originally published in <a href="https://medium.com/jds-engineering">JDS Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Screenshot Camera Preview in Flutter]]></title>
            <link>https://irfnyas.medium.com/how-to-screenshot-camera-preview-in-flutter-a30b71a2bf26?source=rss-bb557aa4ea02------2</link>
            <guid isPermaLink="false">https://medium.com/p/a30b71a2bf26</guid>
            <category><![CDATA[cameras]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Irfan Yas]]></dc:creator>
            <pubDate>Mon, 02 Jan 2023 16:51:35 GMT</pubDate>
            <atom:updated>2023-04-27T04:35:51.768Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*meIisrH9VP9u5om-" /><figcaption>Photo by <a href="https://unsplash.com/@ninjason?utm_source=medium&amp;utm_medium=referral">Jason Leung</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>This year, I got myself homework at the year-end holiday from my senior. Really, how thoughtful of him. Anyway, the tasks are to find any design inspiration, create an app with flutter from it, and write its story as a portfolio.</p><p>Because I’m also a thoughtful person just like him, my first idea is to create an app which shows quotes. While searching for a design, I saw this. It catches my attention by its minimalistic yet full of emotion because of the colour filter and the photo as the background.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*z_qN9Mkjjk6C5eoU" /><figcaption><a href="https://dribbble.com/shots/9174284-Motivational-Quotes-Mobile-App">Motivational Quotes Mobile App by SPEC INDIA on Dribbble</a></figcaption></figure><p>My Senior loves to take a photo with his phone, so my final idea is to create a camera app where it shows a colour filter and a randomised/editable quote in the centre of the screen.</p><p>The development went as smoothly as it could. It shows the camera preview, colour filter, and quote. Now is the time for the screenshot functionality. I wrote the code, and then this happened:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lDo07vaR1e340tJ4zGSxjg.png" /></figure><p>The camera preview is not in the screenshot. Don’t worry, <em>tetap tenang (</em>keep calm<em>)</em>. Someone or the guy who create the <a href="https://github.com/SachinGanesh/screenshot/issues/113">screenshot dependencies</a> might know the workaround:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ey2cmYKoDGq0rUwVLwmCmw.png" /><figcaption>Oh no.</figcaption></figure><p>Fine, I’ll do it myself.</p><pre>/*<br>  assuming you are using dependencies<br>  camera: ^0.10.1<br>  screenshot: ^1.3.0<br>*/<br><br>// 1. You need to take the picture of camera preview and save it as File<br>await cameraController<br>        .takePicture()<br>        .then((value) =&gt; cameraFile = File(value.path));<br><br>// 2. Show the taken picture in Image.file()<br>Image.file(cameraFile),<br><br>// 3. do screenshot<br>await screenshotController.capture();<br><br>// Note: If the camera preview still not showing in screenshot,<br>// try to add a delay around 1 sec between <br>// cameraController.takePicture() and screenshotController.capture()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3a7vSOQXRSYiSFS0vehs5w.png" /></figure><p>If you have any questions, please don’t hesitate to contact me or create an issue in the GitHub repository. Thank you for reading, happy coding.</p><p><a href="https://github.com/irfnyas/qshot">GitHub - irfnyas/qshot: Shot your moment with quotes. Powered by Flutter.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a30b71a2bf26" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>