<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blog on Proper Bits</title><link>https://properbits.com/blog/</link><description>Technical writing by Alexander Kirsch on Flutter, Dart, iOS and mobile CI.</description><generator>Hugo</generator><language>en-GB</language><atom:link href="https://properbits.com/blog/feed.xml" rel="self" type="application/rss+xml"/><item><title>macOS CI on a budget</title><link>https://properbits.com/blog/macos-ci-on-a-budget/</link><pubDate>Mon, 05 Jul 2021 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/macos-ci-on-a-budget/</guid><description>&lt;p&gt;As developers, we all love to observe the glow of green indicators and mesmerising dance of technology that builds and tests our apps. Unfortunately, in the iOS world, reality doesn&amp;rsquo;t look so good. CI services are &lt;a href="https://www.bitrise.io/pricing"&gt;unaffordable&lt;/a&gt; for our pet projects, and hiring a dedicated build machine is even &lt;a href="https://www.macstadium.com/pricing"&gt;more expensive&lt;/a&gt;. The problem, of course, is not that these services are greedy, but the platform to which we are tied. An iOS app can only be built on a macOS, that&amp;rsquo;s it.&lt;/p&gt;</description></item><item><title>Delayed code execution in Flutter</title><link>https://properbits.com/blog/delayed-code-execution-in-flutter/</link><pubDate>Sun, 07 Feb 2021 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/delayed-code-execution-in-flutter/</guid><description>&lt;p&gt;In this article, I&amp;rsquo;d like to take you on a little journey into the depths of Flutter and learn more about scheduling code execution. As a conversation starter, let&amp;rsquo;s assume that we are building an application with a standard &lt;a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/options#bloc--rx"&gt;BLoC&lt;/a&gt; architecture, using the &lt;a href="https://pub.dev/packages/provider"&gt;Provider&lt;/a&gt; library. To make this task challenging, upon opening a new screen we will have to initiate a network request to fetch something over the Internet. In this case, we have several options where to initiate our request:&lt;/p&gt;</description></item><item><title>Installing a self-hosted GitHub Actions runner on a Synology NAS</title><link>https://properbits.com/blog/github-runner-on-synology/</link><pubDate>Sat, 29 Aug 2020 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/github-runner-on-synology/</guid><description>&lt;p&gt;&lt;em&gt;As a disclaimer, I would like to point out that this is not something you would want to do from a security perspective, as it clearly increases the attack surface of your NAS system. Also, GitHub &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#self-hosted-runner-security-with-public-repositories"&gt;does not recommend&lt;/a&gt; using it for anything other than private projects, as again it may pose some security risks to your internal network.&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;Although immediately after the launch of &lt;a href="https://github.com/features/actions"&gt;GitHub Actions CI/CD&lt;/a&gt; was a bit clumsy and lacked many important features, I decided to revisit this service once again. Turns out that the service has since been significantly improved and now fully covers my needs. Another important factor is that it is neatly integrated into the service that I already use, namely GitHub. An unexpected discovery that I made was that you can &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners"&gt;run your own Actions Runner on your device&lt;/a&gt;, which effectively makes this service free of charge for you. Luckily, I had a spare Synology NAS (DSM 6.2.3), so I decided why not use it as a personal build server.&lt;/p&gt;</description></item><item><title>Mobile app user testing on a budget: a practical guide</title><link>https://properbits.com/blog/mobile-app-user-testing/</link><pubDate>Thu, 07 May 2020 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/mobile-app-user-testing/</guid><description>&lt;p&gt;Real user feedback is a vital part of any product development, and the importance of user testing cannot be overestimated here. Unfortunately, for most independent developers this process is literally not affordable and can easily run up to thousands of dollars. In this article, I would like to share with you my methodology for running mobile app user testing which will cost you less than $100 and a few hours of your time. This specific guide describes the testing of applications that are in the pre-release or production stage. Obviously, during the development of a new product, you should strive for feedback as early as possible, but the approaches and goals of this kind of testing will be noticeably different from what I am going to describe here. So let’s get started.&lt;/p&gt;</description></item><item><title>Dart extensions, generating `copyWith` methods</title><link>https://properbits.com/blog/dart-extensions/</link><pubDate>Sun, 15 Dec 2019 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/dart-extensions/</guid><description>&lt;p&gt;As you all are probably aware that the &lt;a href="https://medium.com/dartlang/dart-2-7-a3710ec54e97"&gt;new version of Dart 2.7&lt;/a&gt; was recently released. This version introduces one particularly interesting feature called &amp;ldquo;extension methods&amp;rdquo;. It allows us to extend existing classes with a new functionality. As a basic demonstration of this new feature, we can extend the &lt;code&gt;List&lt;/code&gt; class&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dart" data-lang="dart"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="n"&gt;SafeLast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;safeLast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeLast&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is quite a basic example and doesn&amp;rsquo;t do much. Now let&amp;rsquo;s try to solve a real-life problem I am constantly stumbling upon. I am talking about implementing &lt;code&gt;copyWith&lt;/code&gt; method on &lt;code&gt;@immutable&lt;/code&gt; classes. This is a very popular pattern used to copy a class with some modifications. Unfortunately, it requires a lot of boilerplate code. For example:&lt;/p&gt;</description></item><item><title>A native iOS developer's perspective on React Native vs Flutter (part 3)</title><link>https://properbits.com/blog/react-native-vs-flutter-part3/</link><pubDate>Thu, 21 Nov 2019 09:41:02 +0100</pubDate><guid>https://properbits.com/blog/react-native-vs-flutter-part3/</guid><description>&lt;p&gt;&lt;em&gt;The third and final part of the &lt;a href="https://properbits.com/blog/react-native-vs-flutter-part1/"&gt;&amp;ldquo;A Native Developer&amp;rsquo;s Perspective on React Native vs. Flutter&amp;rdquo;&lt;/a&gt; article series.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="comparing-flutter-and-react-native"&gt;Comparing Flutter and React Native&lt;/h2&gt;&#10;&lt;p&gt;Now I’d like to compare some aspects of React Native and Flutter platforms based on my personal experience.&lt;/p&gt;&#10;&lt;h3 id="language"&gt;Language&lt;/h3&gt;&#10;&lt;p&gt;On the React Native side, there’s JavaScript which is extremely popular and has many developers on its side. This may be an obvious win for a lot companies already using this language. Personally, I don&amp;rsquo;t like JavaScript as a language, even in combination with the &lt;a href="https://flow.org"&gt;Flow&lt;/a&gt; type checker. Despite the assumption that my experience with &lt;a href="https://reactnative.dev/docs/typescript"&gt;TypeScript&lt;/a&gt; may be a bit better, this language isn’t for me.&lt;/p&gt;</description></item><item><title>A native iOS developer's perspective on React Native vs Flutter (part 2)</title><link>https://properbits.com/blog/react-native-vs-flutter-part2/</link><pubDate>Thu, 21 Nov 2019 09:41:01 +0100</pubDate><guid>https://properbits.com/blog/react-native-vs-flutter-part2/</guid><description>&lt;h2 id="flutter-experience"&gt;Flutter experience&lt;/h2&gt;&#10;&lt;p&gt;&lt;em&gt;This is the second part of the &lt;a href="https://properbits.com/blog/react-native-vs-flutter-part1/"&gt;&amp;ldquo;A Native Developer&amp;rsquo;s Perspective on React Native vs. Flutter&amp;rdquo;&lt;/a&gt; article series.&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;I gained a taste of the cross-platform development process with React Native. Yet, I was convinced that cross-platform development could be even better. And that&amp;rsquo;s when Flutter was &lt;a href="https://developers.googleblog.com/2018/12/flutter-10-googles-portable-ui-toolkit.html"&gt;officially released&lt;/a&gt;. Since I wasn’t completely satisfied with the React Native platform I decided to give it a shot and see what Flutter had to offer. For testing, I chose to create a completely new cross-platform application.&lt;/p&gt;</description></item><item><title>A native iOS developer's perspective on React Native vs Flutter (part 1)</title><link>https://properbits.com/blog/react-native-vs-flutter-part1/</link><pubDate>Thu, 21 Nov 2019 09:41:00 +0100</pubDate><guid>https://properbits.com/blog/react-native-vs-flutter-part1/</guid><description>&lt;h2 id="who-i-am-and-what-this-article-is-about"&gt;Who I am and what this article is about&lt;/h2&gt;&#10;&lt;p&gt;I&amp;rsquo;m a native iOS developer and formerly a strong opponent of any non-native development. However, as the new frameworks arrived, they’ve completely redefined what cross-platform development is. Of course, I’m talking about the &lt;a href="https://reactnative.dev/"&gt;React Native&lt;/a&gt; and the &lt;a href="https://flutter.dev"&gt;Flutter&lt;/a&gt; frameworks. In this article, I want to share my own experience with the full cycle of development of two apps. Both developed from scratch to the final release using these frameworks. In the end, I’ll offer some thoughts and conclusions about these technologies from my perspective.&lt;/p&gt;</description></item></channel></rss>