<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Louis Tsai</title>
    <description>The latest articles on DEV Community by Louis Tsai (@louis993546).</description>
    <link>https://dev.to/louis993546</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F82478%2F9b98ea55-e30b-4c37-8a8a-28d7b81b6103.png</url>
      <title>DEV Community: Louis Tsai</title>
      <link>https://dev.to/louis993546</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/louis993546"/>
    <language>en</language>
    <item>
      <title>My plan to become more productive in a month</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 06 Dec 2020 21:42:08 +0000</pubDate>
      <link>https://dev.to/louis993546/my-plan-to-become-more-productive-in-a-month-4048</link>
      <guid>https://dev.to/louis993546/my-plan-to-become-more-productive-in-a-month-4048</guid>
      <description>&lt;p&gt;2020 is almost over, and I just so happen to have almost an entire month off to do whatever I want. One of the things I have learn about myself this year is that my productivity often relies on supervision &amp;amp; “too afraid to say no so now I have to get it done in the next 4 hours”. So one of my goal in the next month 25 days is to figure out something that can keep me productive (and hopefully subsequently fulfilled and happy).&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s the status quo
&lt;/h3&gt;

&lt;p&gt;Currently, I have 2(-ish) system going on: 1 for my work stuff, and 1 for my personal stuff&lt;/p&gt;

&lt;h3&gt;
  
  
  Work: 2D version of Einsenhower Matrix using Asana
&lt;/h3&gt;

&lt;p&gt;For some reason, I remember very distinctly how I got introduce to the Eisenhower Matrix: it was when I was like 16, during a tutorial session (Hong Kong style, i.e. watching a pre-recorded video from one of the “famous” tutors), in which there was just me and 1 other student. Anyway, ever since then, I have this concept in mind for a lot of the things I do, but for like 10 years, I have not been able to translate to something that works. I either worry too much about things that I should not be (e.g. “What if I need to work remotely”, which never happen until COVID-19), or I just don’t really need/care about a comprehensive system. That chances a few months ago:&lt;/p&gt;

&lt;p&gt;Back in August, I got a chance to become a temporary team lead, which means my role changes from “dealing with Jira tickets” to “making sure others have Jira tickets to deal with”, which means a shit ton of meetings, a shit ton of messages and emails, and a shit ton of documents to write. It doesn’t take long before I realize how fucked I am if I don’t come up with some system that works, and that combine with moving to a bigger place for myself, I ended up dedicating a wall to build a physical Einsenhower Matrix&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MGAiT6NL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6_ElaEqs4_dnaogF9leDiA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MGAiT6NL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A6_ElaEqs4_dnaogF9leDiA.jpeg" alt="An image of my wall with 5 post-it notes creating a grid, 2 for x-axis, 2 for y-axis, and 1 in the middle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it actually works pretty well! It forces me to be honest to myself what is urgent/important, and stop working on things that’s interesting but can be dealt with later. And that’s what I have been using for about 2.5 months. And then November comes, and I started to take some lessons before going to work in the office, which means now I need some ways to make it portable. And right now in our team, there seems to be a trend to use more of Asana to organize tasks, and since the company is already paying for it, I might as well give it a shot.&lt;/p&gt;

&lt;p&gt;It does not take long before I start missing the Eisenhower Matrix. While “urgent or not” can easily be reproduce by due date, there does not seems to be a build-in way to indicate importance. Thankfully after a quick Google, I found an extension call &lt;a href="https://chrome.google.com/webstore/detail/asana2go/meaajmlecpkbjcofehfpjngpnpfpjlkd"&gt;Asana2Go&lt;/a&gt;, which has a feature to build an Eisenhower Matrix by adding a custom field to specify which quadrant does a task falls into. Actually, after like 2 days, I just use the custom field and forgot about the extension completely. I just rely on sorting to display the tasks by due date first, then pick the next task to work on according to its quadrant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4JYeeZOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/793/1%2Atji2w95tksQarKNcbFyQPw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4JYeeZOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/793/1%2Atji2w95tksQarKNcbFyQPw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it has been about 2 weeks since I started using this Asana + custom field to mimic Eisenhower Matrix, and so far I really like this approach. As long as I can figure out a way to Asana visible (i.e. a vertical monitor), I am able make sure I work on the next most urgent and/or important task 👍&lt;/p&gt;

&lt;p&gt;(And of course we use Jira for all the tickets 😭)&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal: “Whatever is closest to me” is a system, right?
&lt;/h3&gt;

&lt;p&gt;For my personal tasks, I have not been paying much attentions to it for a very long time. I switch between different to-do-list-app constantly, and even more ways to keep track of my notes. Here are some of the things I have tried&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evernote + Google Tasks&lt;/li&gt;
&lt;li&gt;OneNote + Google Tasks&lt;/li&gt;
&lt;li&gt;Google Drive + Wunderlist (RIP)&lt;/li&gt;
&lt;li&gt;Google Drive + Todoist&lt;/li&gt;
&lt;li&gt;GitHub + (every to-do-list-app)&lt;/li&gt;
&lt;li&gt;Calendar + Google Tasks (the new one)&lt;/li&gt;
&lt;li&gt;Google Keep + Apple Reminder&lt;/li&gt;
&lt;li&gt;Apple Notes + Apple Reminder&lt;/li&gt;
&lt;li&gt;Microsoft To Do + reMarkable + Post-it notes on the wall + Apple Notes + Google Keep&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, it’s really a mess.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s working
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Separating work &amp;amp; person tasks is mostly good
&lt;/h3&gt;

&lt;p&gt;Except for 1 or 2 edge cases, I have extremely separate personal and work life (that’s just how I always deal with things). And so far the only “issue” I really have is that there is no way to check work tasks if I don’t have work machines with me. For 95% of the time, that’s not a bad thing anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Due date + Eisenhower sorting is actually not bad
&lt;/h3&gt;

&lt;p&gt;Like I said above, so far I am really enjoying the 2D version of Eisenhower matrix using Asana. It forces me to give each task an end date, it’s easy enough to figure out how those tasks are gonna fit into the schedule, and it’s super easy and satisfying to update and finish a task 👍&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s not working?
&lt;/h3&gt;

&lt;p&gt;The entirety of my personal system is not working. It’s not just the fact that I didn’t get things done on time, the fact that I constant switch systems also translates to a lot of long term tasks and goals getting lost. While so far it has not cause any major trouble, it definitely needs to be fix up ASAP, hence this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the options
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Notion
&lt;/h3&gt;

&lt;p&gt;It sponsored so many YouTube channels to a point that it’s kinda hard to escape it. I have created an account to play with it a little bit to see what it’s all about, and while it definitely looks nice, I am not sure Notion is the right approach.&lt;/p&gt;

&lt;p&gt;(Note: this is &lt;strong&gt;not&lt;/strong&gt; a review of Notion at all)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It feels too flexible&lt;/li&gt;
&lt;li&gt;It often feels like a bad compromise between “a full fledge tasks management system” and “a full fledge note taking system”&lt;/li&gt;
&lt;li&gt;It’s not satisfying to use, esp. from my phone&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Google Calendar everything, LITERALLY
&lt;/h3&gt;

&lt;p&gt;I think I very briefly tried it in the past, but life is just way too chaotic to try to schedule every little tasks. It took me maybe 2 days before I realize how stupid I was.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other apps/system/method that I have heard of/tried before
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://apps.apple.com/gb/app/hour-blocks-day-planner/id1456275153"&gt;Hour Blocks&lt;/a&gt;: not a bad idea, but the fact that it relies on my phone (i.e. source of distraction) means I can’t use it. However, I do like the idea a lot 😍, which you will see in a minute.&lt;/li&gt;
&lt;li&gt;Pomodoro: In a world where I have a bunch of meetings, Pomodoro just doesn’t fit well into the system. I need something that’s more flexible &amp;amp; more predictable at the same time, and “let just start a 25 minutes timer at any time of the day” it just not gonna work on itself.&lt;/li&gt;
&lt;li&gt;Asana: I don’t wanna pay for my personal account🤑. Also I don’t think all the project/milestone/roadmap are useful to organize my personal tasks anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build my own app
&lt;/h3&gt;

&lt;p&gt;Because I don’t have enough dead side projects already 😂&lt;/p&gt;

&lt;p&gt;And the winner is…&lt;/p&gt;

&lt;h3&gt;
  
  
  Jira!? 🤨
&lt;/h3&gt;

&lt;p&gt;I know this does sound like the stupidest idea. Isn’t it already tragic enough that I have to use Jira on a daily basis at work, why am I doing this to my personal life as well? Well, let me explain a bit of what I have learned in the last 3 months of dealing with Jira…&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 1: CONFIGURABLE
&lt;/h4&gt;

&lt;p&gt;On one hand of the spectrum, you have tools like Microsoft To Do, in which there is pretty much nothing you can configure. And then you get tools like Asana, which (if you pay) you have access to custom fields, some decent filtering, but you are still very much in the bubble of how Asana thinks you should work. And then there is Jira, in which most things are configurable, but it still feels very “type-safe” and somewhat complicated to change, but at least it’s possible. And if you keep driving along the spectrum, you will get to tools like Notion and AirTable, which basically is a free canvas/spreadsheet/database/all-of-the-above with extra steps.&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 2: JQL
&lt;/h4&gt;

&lt;p&gt;As a programmer, the fact that there is a query language to find tasks has proven to be a godsend. Imagine if you got dozens of new tickets a day (that’s not kidding, it seriously happen for like 2 months straight), there is no reasonable way to keep them sorted and filter correctly without something advance, and JQL has proven itself to be very useful. I hope it won’t come to that day for my personal tasks, but you’ll never know.&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 3: NEXT-GEN PROJECT
&lt;/h4&gt;

&lt;p&gt;Another thing that makes my personal Jira better than the work Jira is the fact that I am using the next-gen project. It is actually a lot closer to Trello (which is now another Atlassian product anyway) than the traditional Jira. And since it’s just me and myself in the “project”, something lighter and simpler is just what I need&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 4: REASONABLE APP
&lt;/h4&gt;

&lt;p&gt;There are so many software that never figured out how make their mental model works well in mobile client, and for that I really have to applaud the Jira apps. It’s actually pretty useable. A lot of other apps either can’t figure out how to make all the info fit on screen (e.g. Asana, in which the list does not display any fields), not a very good app (e.g. Microsoft To Do, in which I very often swipe away a task when I was just trying to go back), or combination of both (e.g. Notion, which is just trying to cramp the entire webpage to a small screen. Please stop).&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 5: CONFLUENCE (🤞)
&lt;/h4&gt;

&lt;p&gt;If you take another look in my person system above, you can see that I often have a tasks list + a note taking app. And so far, they are always 2 separate entities, and some information are always separated. And right now I am hoping the fact that Jira &amp;amp; confluence can cross-reference each other can turn itself into something a lot more powerful. I have seen how it makes my life a lot easier when I build our team’s documentation at work, and I am hoping to transfer that to my own Jira + Confluence setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  PROS 6: I AM ALREADY USING IT AT WORK ANYWAY
&lt;/h4&gt;

&lt;p&gt;I have spend the last 3 months managing tickets on Jira, and documents on Confluence, I am already quite familiar with how it works, even though we are still using the ugly classic version of Atlassian apps. And at the end of the day, I am trying to get shit done, and spending way too much time to figure out how to setup a new system is not particular practical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actually, it’s Jira + Google Calendar
&lt;/h3&gt;

&lt;p&gt;So Jira should explain all the part about task management &amp;amp; documentation. And for time management, I think we are all stuck with Google Calendar anyway (if you have any reasonable alternative please let me know 🙏). However, I took the idea of Hour Blocks, and only put big generic blocks of tasks, instead of trying to make detail and accurate schedule.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RiWgqPOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AlN6mnnZilmd8Zlx6wSdaGQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RiWgqPOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AlN6mnnZilmd8Zlx6wSdaGQ.png" alt="An obfuscated image of how I am using Google Calendar. Each event have at least 15 minutes gap between them, and they almost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example: currently I am reading the “Atomic Habits” by James Clear, and I am trying to have a committed time and place to actually build my habits. So about 80% of the blocks you see are actually events to build my habit. And the fact that I can easily make sure they are not interfering with my other events and meetings is extremely useful.&lt;/p&gt;

&lt;p&gt;So far the only major thing that’s missing for me is the lack of a easy (and free) way to see both Jira and Google Calendar together, and so far it has not been a big issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So this is what I am trying out for the next 25 days. Let’s see if this system is enough to drive me back to a productive and healthy lifestyle. And if you don’t see a follow-up of this article in January 2021, there are only 3 possibilities&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shit hits the fan and I got busy AF&lt;/li&gt;
&lt;li&gt;The system does not work&lt;/li&gt;
&lt;li&gt;I am dead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🤞🤞🤞🤞🤞&lt;/p&gt;

</description>
      <category>taskmanagement</category>
      <category>eisenhowermatrix</category>
      <category>productivity</category>
      <category>timemanagement</category>
    </item>
    <item>
      <title>Let’s see if Flipper can make me a 1.1x engineer</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 16 Aug 2020 07:36:39 +0000</pubDate>
      <link>https://dev.to/louis993546/let-s-see-if-flipper-can-make-me-a-1-1x-engineer-3paj</link>
      <guid>https://dev.to/louis993546/let-s-see-if-flipper-can-make-me-a-1-1x-engineer-3paj</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SmV9aEaW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AzcH7d_sJTAgIvdgWwUhH-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SmV9aEaW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AzcH7d_sJTAgIvdgWwUhH-g.png" alt="Website of Flipper"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fbflipper.com/"&gt;Flipper&lt;/a&gt; is a debugging tool build by facebook, which in a sense is a spiritual successor to &lt;a href="https://facebook.github.io/stetho/"&gt;Stetho&lt;/a&gt;. For those who don’t know, Stetho is also a debugging tool, which allows Android apps to redirect a bunch of debugging data to chrome://inspect, most notably networking requests. I have used Stetho quite extensively in one of my last companies, because how easy it is to setup and use, so I do have some fond memory of it. However, slowly and gradually, it stops being maintain, and then I found out the existence of Flipper. So obviously the next logical step is to give it a shot, and see how useful it is 👀👀&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;The process is actually quite straight forward, thanks to the pretty extensive-yet-not-too-verbose &lt;a href="https://fbflipper.com/docs/getting-started/indexhttps://fbflipper.com/docs/getting-started/index"&gt;documentation site&lt;/a&gt;. The only hurdle I ran into is when setting up the &lt;a href="https://fbflipper.com/docs/setup/network-plugin"&gt;networking plugin&lt;/a&gt;, you have to make sure you have the same instance of the plugin use by both the interceptor, and the setup step. I messed up some setup in Dagger, and it took me like a solid 30 minutes before I really how stupid I was 🤦‍♀&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Plugin
&lt;/h3&gt;

&lt;p&gt;So the biggest selling point of Flipper is probably it’s plugin API. &lt;strong&gt;It opens the door to build project-specific and user-friendly GUI dev tools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a lot of projects, probably at some point someone will think “hmm, what if I just wrote a script to make it easier to debug this?”, and then they hack the script together in record breaking time (because it’s usually the fun part), and tell the entire team “now your problem is solved”. But when team grow/change, suddenly everyone is relying on that script with little to no test, often convoluted code, and even more confusing and cryptic inputs/outputs (and stacktrace if something went terribly wrong).&lt;/p&gt;

&lt;p&gt;So these are the problems that I hope Flipper can solve/mitigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Confusing to use&lt;/strong&gt; : By having a GUI, I can at least try to layout all the buttons and text in a way that is less confusing. And the fact that it uses React should also help make it easier to build the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too many dev tools&lt;/strong&gt; : By having just 1 debugging application, this can consolidate most of the random dev tools into just 1 windows, which should make it easier to deal with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“Sketchy” dev tools&lt;/strong&gt; : It’s not that you cannot write script that testes those script, it’s just that by having a “normal” project setup, hopefully it can encourage me to not only write dev tools, but also write test to make sure those dev tools works in the long run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So with these goal in mind, here’s what I have learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;documentation of building your own native (i.e. apps) plugin is also very good&lt;/strong&gt;: on the &lt;a href="https://fbflipper.com/docs/tutorial/android/"&gt;client side,&lt;/a&gt; it took me maybe 15 minutes to have a basic network plugin that filters out only the traffic that I care&lt;/li&gt;
&lt;li&gt;And for &lt;strong&gt;building desktop plugin, it’s less good but still not terrible&lt;/strong&gt; : While &lt;a href="https://fbflipper.com/docs/tutorial/js-setup"&gt;the documentation&lt;/a&gt; itself is still pretty good, there are quite a few issue that I ran into and with not a lot of useful debugging. The biggest problem I have is “how to get Flipper Desktop to see my plugin”, and according to the documentation, it is to add the path to the plugin to the config.json Flipper created in your machine. But it looks like if Flipper thinks the path you added is “wrong”, it will just remove it when Flipper Desktop closes. So it ended up taking me another hour of trial and error, and looking through the entire site to found &lt;a href="https://fbflipper.com/docs/extending/js-setup#dynamically-loading-plugins"&gt;another page&lt;/a&gt; that explains what is the exact path that I should have used, and the fact that I should have run yarn watch to build the tar ball for Flipper to detect the plugin correctly.&lt;/li&gt;
&lt;li&gt;Depends on what you want to build, you can put the logic on the client plugin or desktop plugin. Putting logic on client side means writing those logic in Kotlin, which would have been a lot easier; but at the end &lt;strong&gt;I’d recommend putting those logic on the desktop side&lt;/strong&gt; , in the hope that A) it might be share if the iOS all also adopts it, and B) my TypeScript knowledge is good enough, or worst case scenario, it’s not that hard to Google the solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Building a user-friendly desktop plugin is not as simple as it seems&lt;/strong&gt; , mostly because the level of abstraction that comes with Flipper is either too high, or too low. If you just want to show “a list of something”, createTablePlugin makes things very simple. But since I want to do some data processing before it shows on table, I ended up copying that entire file, make like 10 line changes in there to expose a lambda for me to sanitize the data, before showing it in the table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Currently it is entirely still an experiment, and also I have not asked my boss if I can even share it. I hope in a month or 2, I will be able to share if Flipper turns out to be a good idea or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1x Engineer
&lt;/h3&gt;

&lt;p&gt;And to end this blog post, I just want to do a quick shout-out to the &lt;a href="https://dev.to/tlakomy/become-a-10-engineer-g78"&gt;&lt;strong&gt;1.1x/+10% engineer concept&lt;/strong&gt;&lt;/a&gt;. What I have started to realized that I like to do is to “help other people do what they are good at, but even better”, and I think more people should give it a shot. Imagine if every month, 1 of the engineers build/do something that makes everyone works 10% more efficient/more productive/happier, in 2 years, 1.1²⁴ = 9.85, i.e. the team will be almost &lt;strong&gt;10 times better than 2 years ago&lt;/strong&gt;! And I am 1000% sure you cannot simulate these kind of growth just by hiring more people/“10x” engineers.&lt;/p&gt;

&lt;p&gt;At the end of the day, I hope Flipper will allow me to make our team 10% more efficient, and so far it looks promising, and I recommend you to give it a shot!&lt;/p&gt;

</description>
      <category>development</category>
      <category>android</category>
      <category>flipper</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Random Compose Project #1: Compose95</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sat, 25 Jul 2020 14:10:17 +0000</pubDate>
      <link>https://dev.to/louis993546/random-compose-project-1-compose95-2h53</link>
      <guid>https://dev.to/louis993546/random-compose-project-1-compose95-2h53</guid>
      <description>&lt;p&gt;Jetpack Compose is getting closer and closer to becoming “stable enough”, and for the next few weeks/months, I will be working on a bunch of completely random projects, and document what I have learned along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR: This is not tutorial/how-to of Jetpack Compose at all. This is just blog post of my experience of using it.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Compose95
&lt;/h3&gt;

&lt;p&gt;As it’s name suggest, it’s trying to build Jetpack Compose that looks like it’s 1995, more specifically, Windows 95. It is inspired by Miguel Beltran’s work on &lt;a href="https://github.com/miquelbeltran/flutter95" rel="noopener noreferrer"&gt;Flutter95&lt;/a&gt;, which is inspired by Artur Bień’s &lt;a href="https://github.com/arturbien/React95" rel="noopener noreferrer"&gt;React95&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ajt7pi5ngR2aNOLD5QsM81g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ajt7pi5ngR2aNOLD5QsM81g.png" alt="Screenshot of Flutter95 on GitHub"&gt;&lt;/a&gt;miquelbeltran/flutter95&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ankfvrtln7TS2C4KWywN7fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Ankfvrtln7TS2C4KWywN7fw.png" alt="Screenshot of home page of React95 on GitHub"&gt;&lt;/a&gt;arturbien/React95&lt;/p&gt;

&lt;h3&gt;
  
  
  What am I building, exactly?
&lt;/h3&gt;

&lt;p&gt;For this post, I am documenting what I went through when buildling&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Window (most of it)&lt;/li&gt;
&lt;li&gt;Button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s all open-source, click &lt;a href="https://github.com/louis993546/Compose95" rel="noopener noreferrer"&gt;here&lt;/a&gt; to judge how bad the code is 😂&lt;/p&gt;

&lt;h3&gt;
  
  
  Window
&lt;/h3&gt;

&lt;p&gt;Window is the relatively straight forward component to build. It is basically just a container with a bar at the top, optionally the ability to minify/maximize/close the window, which doesn’t make sense in the case of an Android app anyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A55NcXvojhGPXkBYD10d2_A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A55NcXvojhGPXkBYD10d2_A.png" alt="Screenshot of Android Studio, which has code of Window95, Preview of Window95, and an emulator showing what it looks like"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Windows95 is pretty straight forward. The most "complicated" part is probably the border. If you remember, Windows 95 is very skeuomorphism (is this word an adjective?), and the borders colors really sells the elevation, even to this date. I am not saying it looks great, but it certainly is effective. Using React95 as reference, I can see that the border is actually more like 2 boarders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 on the outsize with pure white or black&lt;/li&gt;
&lt;li&gt;1 on the inside a few shares of grey to make it look more like shadow, instead of just color borders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And to achieve that look, basically I have to figure out how to draw border that has different color accordingly, and that means digging into what .drawBorder is doing. Since it is a receiver function of Modifier, of course there is a Modifier.Element powering it, in this case: DrawModifier. And once you get the draw scope inside of it, you just have to figure out the coordinates, and then it is not too complicated to draw the 8 lines.&lt;/p&gt;

&lt;p&gt;And 1 last thing: if you check DrawBorder, you can see there are a lot more complexity inside, with how round corner should be, and most importantly cache. At some point Window95 probably should do that, but it is way too early for me to do any kind of optimization. Hell the code still looks like shit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Button
&lt;/h3&gt;

&lt;p&gt;Button95 is also structurally quite simple, the "biggest" challenge is to figure out how to detect press state, and flip the borders around to sell the effect of "from above surface to below surface". And to figure out how, I digged into .ripple.&lt;/p&gt;

&lt;p&gt;Inside .ripple, I found RippleModifier, but there is nothing too interesting to look into, since it looks like most of the code is about the animation of the ripple. What I want in this case is just a very basic "is it pressed or not" callback of some sort. And after I while, I realized that there are more than 1 argument for .clickable, esp. Indication. It is exactly what I need in this case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A8syesNMCHQ-yswfx6-rqwQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A8syesNMCHQ-yswfx6-rqwQ.png" alt="Screenshot of Android Studio, which has code of Button95, Preview of Button95, and an emulator showing what it looks like"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Indication does is actually more like IndicationFactory, which creates IndicationInstance, and that IndicationInstance just have a function that gets a ContentDrawScope to draw whatever I want. And now things are starting to look very similar to how I draw the boarders inWindow95, except I have to check interactionState to see what color each border should be.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F430%2F1%2A5y3sebbyauJ_H3A6XFs2WA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F430%2F1%2A5y3sebbyauJ_H3A6XFs2WA.gif" alt="A GIF of Button95 being click, and what happens when it got long press (content got highlited)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While technically not a bug, it looks like I still have some work to do to figure out how to make it behave more naturally……&lt;/p&gt;

&lt;p&gt;This is the end of this blog post, it is absolutely gonna take me forever to get it to a working state. I wish I have more energy and time to work on stuff like this……&lt;/p&gt;

</description>
      <category>jetpackcompose</category>
      <category>android</category>
      <category>windows95</category>
    </item>
    <item>
      <title>Went from “liking tweets about remote working” to “being 100% remote” in 1 day</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Wed, 08 Apr 2020 19:22:48 +0000</pubDate>
      <link>https://dev.to/louis993546/went-from-liking-tweets-about-remote-working-to-being-100-remote-in-1-day-3m3p</link>
      <guid>https://dev.to/louis993546/went-from-liking-tweets-about-remote-working-to-being-100-remote-in-1-day-3m3p</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bXIlQW57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AvVjZravYvhbsQnPxqvsW8g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bXIlQW57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AvVjZravYvhbsQnPxqvsW8g.jpeg" alt=""&gt;&lt;/a&gt;My desk setup from a week ago&lt;/p&gt;

&lt;p&gt;Today is &lt;strong&gt;2020 April 1st&lt;/strong&gt; , and we are in the middle of a pandemic. Roughly 2 weeks ago, the company I worked for went “remote first”, and in terms of work, things are starting to get back to usual (well, as usual as it can get). So today, I’d like to write down some of my first impressions of the whole situation so far!&lt;/p&gt;

&lt;h3&gt;
  
  
  How it went down (simplified)
&lt;/h3&gt;

&lt;p&gt;Even before Berlin starts getting it’s first COVID-19 case, there has been a bunch of people asking if the company’s policy about WFH and other preventive measures are gonna adapt to it. And after Berlin has it’s first confirmed case, it takes a few more days until the management establishes official news source. And a few more days (&amp;amp; a lot of messages on the chat room) later, the company held a basically impromptu-all-hands in the morning, and announced the procedure of how to “apply” for WFH for most employees. And the next thing you know, half the people are gone before lunch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Perception of remote working before this
&lt;/h3&gt;

&lt;p&gt;I have been living in Berlin for 3 years now, and worked in multiple companies as full time employee, in their office, at least 9–5. I am now mostly used to it, but I don’t think I ever really liked it.&lt;/p&gt;

&lt;p&gt;I like being able to easily make friends at work, but I don’t like waking up when it’s one of those days where I just don’t feel like socializing at all.&lt;/p&gt;

&lt;p&gt;I like that it forces me to have a consistent schedule and lifestyle, but I don’t really enjoy the hours being so inflexible, given my work is not really time-specific.&lt;/p&gt;

&lt;p&gt;I like that an office provides a safe space in terms of productivity (usually), but I hate having to spend 1+ hour each day on the commute.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: I never &lt;strong&gt;hate&lt;/strong&gt; showing up to office per se, but I have a list of things I can complain about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The first 24 hours of “OK you work from home now”
&lt;/h3&gt;

&lt;p&gt;Even though I was one of the people who tried to push the company to adopt WFH as soon as possible (i.e. “wrote on the super long COVID-19 thread to keep the conversation going”), the sudden announcement still throws me off. I spend basically the whole afternoon planning what do I have to do to get my room ready, and try to organize the work to make sure I won’t forget anything (although this didn’t really work because I was so distracted the entire time).&lt;/p&gt;

&lt;p&gt;I left office a bit later than usual to try to avoid the crowd, and then I went to supermarket to get enough groceries for a week, and tried to go get a microphone for all the video chat (although the store was out of the cheap one). The last thing I did before officially working remotely is that on the next day at 7AM, I planned out how I am gonna move the furnitures in my room around to have a more separate work &amp;amp; rest place (sorry downstairs neighbors). Living in a tiny room in a share flat in the middle of a pandemic is not ideal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: Chaotic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What happens in the next week
&lt;/h3&gt;

&lt;p&gt;In terms of the work itself, things are quite typical, since it is such a short notice, we are not really prepared to adapt anything to be more remote friendly. We still have a lot of meetings, but with video chat instead of face-to-face. It’s ever so slightly worse than what I usually experience.&lt;/p&gt;

&lt;p&gt;In terms of productivity, I’d say I am able to focus around 60% of the time. There is only so much you can do to improve your home office in such short notice. And I tried to compensate for it with working extra hours, which ever so slightly cancel out my reduced productivity (but not sustainable at all).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CrfymKsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOI7YC42PLEtTNTV7" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CrfymKsY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOI7YC42PLEtTNTV7" alt=""&gt;&lt;/a&gt;This comic from Alex Norris speaks to my soul: &lt;a href="https://twitter.com/nadiaoxford/status/1239588500212789248"&gt;&lt;/a&gt;&lt;a href="https://twitter.com/nadiaoxford/status/1239588500212789248"&gt;https://twitter.com/nadiaoxford/status/1239588500212789248&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The biggest change probably happens in terms of my sanity. This sheer amount of news around the pandemic drives my stress level high already, combine with issues with the work itself with a tight deadline that actually needs to be met or “shit might go down”, and me trying to compensate it with extra work hour, is driving my mood to an all time low.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: Externally business as usual, internally pulling my hairs out&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Now what?
&lt;/h3&gt;

&lt;p&gt;Knowing that I will be stuck on this chair for a while, I am starting to plan how am I gonna survive this without going me insane (if I am not already insane).&lt;/p&gt;

&lt;p&gt;First thing I did: online shopping. If all the advertisements have taught me anything, it is “buy this product and your problem will go away”. I am now aware of how much “useless” things I just bought, and I am doing a slightly better job at controlling my spending habit than a week ago. But I do need to make a few adjustments to the physical environments, and I am fortunate enough to have some saving &amp;amp; incomes to do just that.&lt;/p&gt;

&lt;p&gt;Next thing I did: spend a lot of time on the internet to try to figure out how WFH usually work. What should I expect (under normal circumstances), how should I adjust that expectation based on the situation, how people usually work, etc. One of the thing that kinda blows my mind is the &lt;a href="https://www.pscp.tv/w/1nAKEdbbnPgxL"&gt;Q&amp;amp;A session by David Heinemeier Hansson and Jason Fried from Basecamp&lt;/a&gt;. While some of it do feel a bit too much like an ad for Basecamp, I think the rest is a good short summary of what a team of expert remote workers is experiencing, along with how newly remote workers can/should expect.&lt;/p&gt;

&lt;p&gt;While I am coming up with a list of improvements for my surrounds physically, I also started to think about how to change my behavior to reduce my stress level, so that I don’t have to pull my hairs out.&lt;/p&gt;

&lt;h4&gt;
  
  
  Workout
&lt;/h4&gt;

&lt;p&gt;A lot of people have suggested that keeping your workout routine is very helpful, and I will try to do some quick research on what body weight exercise can I do in such a tiny space. I haven’t do much body weight exercise since my Uni days.&lt;/p&gt;

&lt;h4&gt;
  
  
  “Separation of concerns”
&lt;/h4&gt;

&lt;p&gt;A lot of people also suggested to keep your work space and personal space separate. While it’s physically hard to do in my tiny room, I can kinda achieve that by removing all work-related items from my sight (all notes, computer, accessories, etc.) when the day is over, and let my laziness do the the rest (a.k.a. “Nah I am too lazy to move the chair and take the computer back out. I will check it tomorrow”)&lt;/p&gt;

&lt;h4&gt;
  
  
  Clean your room/apartment/mansion/whatever
&lt;/h4&gt;

&lt;p&gt;A lot of people suggested to keep your space tidy, plus the act of tidying can double as a distraction. That’s just a good idea in general, especially now that we are all spending 24 hours in the apartment everyday.&lt;/p&gt;

&lt;h4&gt;
  
  
  Spend less time on internet
&lt;/h4&gt;

&lt;p&gt;First I have to say I love the internet, without it I would be absolutely useless. But in the last few months, the amount of time I spent reading COVID-19 related news is pretty much inversely proportional to my mood.&lt;/p&gt;

&lt;p&gt;Back in 2003 when SARS was hitting Hong Kong, I remember everyone can’t stop watching the news, and it drives everyone into panic mode. And this time around, it started for me back in Jan-Feb, when my family and friends in Hong Kong are panicking on how they are gonna get enough masks, and pretty much my entire instagram feed is about how people are trying to keep themselves safe (from the virus or the police, or both). And when cases start to appear in Europe, I just can’t stop scrolling on Twitter and panic.&lt;/p&gt;

&lt;p&gt;And even if you find the news about COVID-19 useful, there is still a huge problem of misinformation being share around, from random obfuscated screenshots on Instagram, to actual leaders of multiple countries (yes of course I am referring to Trump). One of the most vivid memory I have is that in the early days of the spread in Hong Kong, no one actually knows what the symptom should be, how they spread (WHO were saying “human to human transmission is unlikely”), and someone share a (later to be proven fake/taken out of context) video, of a men puking blood on some China subway/underground/U-Bahn/MTR, for like a full minute straight. That was really disturbing, not because of the visual, but the idea of “what if this happens to people I care about”. I was (and still am) not prepared for this. I just can’t stop thinking about it and focus at work for 2 days straight.&lt;/p&gt;

&lt;p&gt;I think it’s safe to say I should spend a lot less time on the internet.&lt;/p&gt;

&lt;h4&gt;
  
  
  Take up some new hobbies/pick up some old hobbies
&lt;/h4&gt;

&lt;p&gt;Now that I promise to spend less time on the internet, I’d need some other form of distractions. Some of my recent hobby-building purchase (i.e. online shopping spree) includes buying a Nikon FM (i.e. an old-school film camera from the 70s?), some books (currently reading &lt;a href="https://www.goodreads.com/book/show/42086897-how-to"&gt;how to by &lt;em&gt;Randall Monroe&lt;/em&gt;&lt;/a&gt;), and a decent speaker set (Creative T40 II to be exact. I am not an audiophile I just bought it because my work computer speaker starts cracking). Each of them should be enough distraction for quite a while.&lt;/p&gt;

&lt;p&gt;There are also hobbies that does not involve extra spending, like writing, playing some instruments (A lot of people probably have an instrument laying around), or cooking (you have to eat everyday anyway, might as well make your food better).&lt;/p&gt;

&lt;p&gt;We are all gonna be stuck here for a while, and by we I mean those who are privileged enough to work from home. The best we can do is to buy scientist and manufactures time to develop the vaccine and more effective cure, to help keep those who cannot work from home as safe as possible. In the day and age when both the physical world and digital world is plague with danger, it would be my first step to figure out how I can embrace remote working and get my sanity back on track.&lt;/p&gt;

&lt;p&gt;Stay safe!&lt;/p&gt;

</description>
      <category>remoteworking</category>
    </item>
    <item>
      <title>Mental Models of Jetpack Compose #4: Components and Hindsight</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Wed, 26 Feb 2020 23:36:58 +0000</pubDate>
      <link>https://dev.to/louis993546/mental-models-of-jetpack-compose-4-components-and-hindsight-25o7</link>
      <guid>https://dev.to/louis993546/mental-models-of-jetpack-compose-4-components-and-hindsight-25o7</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AmaVyEvb84qWJfihU" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AmaVyEvb84qWJfihU"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@jamie452?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Jamie Street&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After months of procrastinating, I am finally getting to the last chapter of “Mental Models of Jetpack Compose”, at least for now. Today, we are gonna talk about components, and hindsight.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component
&lt;/h3&gt;

&lt;p&gt;If you just look at the basics structure of Component in React or Widget in Flutter, you will probably find it not too far off from android.view.View on the typical Android View API.&lt;/p&gt;

&lt;p&gt;React:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ASYCkv93V-Ljo6gF-olC7Rg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ASYCkv93V-Ljo6gF-olC7Rg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flutter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AECaQmCkUuBB3HanGUz4sJA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AECaQmCkUuBB3HanGUz4sJA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typical Android View:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Av2CHCknVxL9iaPwW8LZSCw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Av2CHCknVxL9iaPwW8LZSCw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More specifically, they all have 1 method that ultimately determines what should be display. So what makes the concept of Component different? Well, the biggest distinction is that the render/build function defines an &lt;strong&gt;abstraction&lt;/strong&gt; on what the view should look like, while in onDraw function you are responsible for specifying every last detail. Basically it goes back to &lt;a href="https://dev.to/louis993546/mental-models-of-jetpack-compose-1-state-programming-models-20eh"&gt;episode 1&lt;/a&gt;, which we talk about declarative programming vs imperative programming.&lt;/p&gt;

&lt;p&gt;And that’s pretty much what the concept of component is! On it’s own component is nothing special, what makes it fun and powerful is that it only carries information, not instructions, which usually makes it more understandable, and also more lightweight. Speaking of fun, that brings us to a minor addition to the concept of component. But first, let’s take a look at this example from React:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AklU5pzPuLrP0noo1COP7uA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AklU5pzPuLrP0noo1COP7uA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Sample from&lt;/em&gt; &lt;a href="https://reactjs.org/docs/hooks-overview.html" rel="noopener noreferrer"&gt;&lt;em&gt;React documentation&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if you don’t know JSX, when you read render(), you probably still understand what it is trying to do: it will have a text, and a button, probably as a column, and each click will trigger some text to change. But why are there so many other stuff? OMG does the constructor in JavaScript looks like the one in Java!? And what the hell are componentDidMount() and componentDidUpdate() doing there when they do exactly the same thing?&lt;/p&gt;

&lt;p&gt;And if we take a step back, and try to remember why React was created in the beginning, what they wanted to do is basically this:&lt;/p&gt;

&lt;h3&gt;
  
  
  UI = f(state)
&lt;/h3&gt;

&lt;p&gt;(read: given a state, a function transforms it into a UI)&lt;/p&gt;

&lt;p&gt;So what if we just take that &lt;strong&gt;literally&lt;/strong&gt;? That brings us to the concept of &lt;strong&gt;functional component&lt;/strong&gt;. The mental model of component is still there, but instead of representing it with a “class”, just directly represent it with the function, and it would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ATwpI41PzVluyKsHeP2SaNw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2ATwpI41PzVluyKsHeP2SaNw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sample from &lt;a href="https://reactjs.org/docs/hooks-overview.html" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Making function directly the star of the component encourages/forces us to embrace composition (since there is nothing to inherit from), and all it needs are a set of good API to expose the lifecycle and state management API back out.&lt;/p&gt;

&lt;p&gt;React calls this “hooks”, named after all the API (i.e. hooks) it exposes for components to interact with the runtime, i.e. all the use___ functions. And after barely more than a year, it seems that React hooks have become the standard way of building components for them. And for Jetpack Compose, which is heavily inspired by React, it took it to the next level/extreme, by only having function components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hindsight
&lt;/h3&gt;

&lt;p&gt;This is the last mental model I want to mention for this series, which is not actually a technical thing, but more of a mindset you should be aware of.&lt;/p&gt;

&lt;p&gt;Often when we look at “legacy code”, we will say “ah they should have done X instead of Y”. But then 5 minutes later, you remember you are the one who wrote those code to begin with. Is that because you/that person was “young and dumb” back then? That’s possible, but the far more likely scenario is that things and people change in ways that were not participated. Who knew build time would be such a big issue 5 years ago? Who knew RxJava will be overuse 5 years ago? Who knew assuming there are only 2 genders is a bad idea 10 years ago? Probably not a lot of people.&lt;/p&gt;

&lt;p&gt;And that’s what makes hindsight important: being able to learn from not just your own experiences, but also from others, is very important for your learning. And in the context of building a UI framework, knowing how annoying opinionated people can get, and what pattern people often use, are extremely useful information, even if we are not building for the same platform, or with the same language. (P.S. &lt;a href="https://reactjs.org/docs/hooks-intro.html#motivation" rel="noopener noreferrer"&gt;hindsight from React on what motivates them to create hooks&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So how does it apply to you? Well, even though there are not a lot of Jetpack Compose material (also half of those blog posts and videos out of date, since the API change so drastically), you can still learn from React, Flutter, and more other frameworks, see what other people have been doing, how they get used to it, what they have learned, and more. I promise a lot of the concepts are applicable to Jetpack Compose as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This will be the end of the “Mental Model of Jetpack Compose” series, at least for now, mostly because now Android Studio 4.0 is available, you can actually go try it out yourself. And very soon I will try to pick some random ideas I have and document my experience of “turning theories into practices”.&lt;/p&gt;

&lt;p&gt;And also it’s 0:24 and I really should go to sleep right now 😴&lt;/p&gt;

</description>
      <category>android</category>
      <category>mentalmodels</category>
      <category>jetpackcompose</category>
    </item>
    <item>
      <title>How much am I really worth?</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 16 Feb 2020 21:32:51 +0000</pubDate>
      <link>https://dev.to/louis993546/how-much-am-i-really-worth-1aek</link>
      <guid>https://dev.to/louis993546/how-much-am-i-really-worth-1aek</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zgQeSB-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A2ZIck82yK7X9Jb906WgFhA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zgQeSB-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A2ZIck82yK7X9Jb906WgFhA.png" alt=""&gt;&lt;/a&gt;The beginning of #KnowYourWirth&lt;/p&gt;

&lt;p&gt;In the last 2 days, the tech community on Twitter blew up with the &lt;a href="https://twitter.com/hashtag/KnowYourWorth"&gt;#KnowYourWorth&lt;/a&gt; movement. The TL;DR it is to share your salary, so that minorities can have a better grasp of what the market rate is, instead of relying on anonymous sites that you never really know if they can be trusted.&lt;/p&gt;

&lt;p&gt;And just like every movement on Twitter, immediately there are a lot of supporters, along with a lot of criticisms. And what I want to do today is to share my 2 cents of what I fell about #KnowYourWorth.&lt;/p&gt;

&lt;p&gt;First, I would like to get a few facts straight, before jumping into my own train of thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tech industry lacks diversity (and has been like that for a very very long time). &lt;a href="https://insights.stackoverflow.com/survey/2019#developer-profile"&gt;According to Stack Overflow 2019 Survey, 91.7% of the respondent identifies as male, and 70.8% identify as “White or of European descent” (!)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The gender pay gap is (sadly) still real. &lt;a href="https://www.harnham.com/2020-european-diversity-report"&gt;According to Harnham European Diversity Report 2020, the gender pay gap is around 16%, while the gap in Germany being just 4% (so close!)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am sure there are a lot of peer-reviewed studies on these topics, just go to Wikipedia and go through all of the citations for &lt;a href="https://en.wikipedia.org/wiki/Gender_disparity_in_computing"&gt;gender disputesarity&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Gender_pay_gap"&gt;gender pay gap&lt;/a&gt;, not to mention race, sexuality, age, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The TL;DR of what I think I am worth boils down to the following:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Honestly I think right now I am worth less than what my company is paying me&lt;/li&gt;
&lt;li&gt;However, just 2 years ago, I am probably underpay (because I know nothing)&lt;/li&gt;
&lt;li&gt;I wish the society has less stigma on compensation transparency&lt;/li&gt;
&lt;li&gt;And hopefully with that, we can have a much better look at the inequality as a whole&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What should be the criteria?
&lt;/h4&gt;

&lt;p&gt;One of the bigger group of discussion focuses on “should people with the same title have the same compensation, regardless of where they live”. Personally I am more in the camp of “pay people with same responsibility with same base compensation + compensation based on context”.&lt;/p&gt;

&lt;p&gt;The reason why I am against same salary for everyone is because it is kinda unrealistic. Some people are gonna like to live in expensive places (SF, Norway, etc.) for a wide range of reasons. And unless you pay everyone that high level of compensations, you are excluding them based on something that they may have no power to change. There are also a lot of other reasons why you might want to pay people differently, like appreciation of loyalty, compensation in salary vs days off, and not to mention bonus on performance of individuals.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ok, so what are you really worth?
&lt;/h4&gt;

&lt;p&gt;And based on this criteria, I honestly think I am very lucky and maybe &lt;a href="https://twitter.com/louis993546/status/1228570372771123201"&gt;even overpay&lt;/a&gt;. I did not ask my teammates what their compensations are (since this blow up during the weekend), but from what I understand about our company’s pay structure, they probably get paid less than I do, while doing the same or even more than what I do. I fucked things up on such a regular basis, that I am still wondering if I am gonna pass the probation period 🤞&lt;/p&gt;

&lt;p&gt;And in terms of the context, we more or less joined at the same time, with more or less the same amount of expertise of what we do (more then I do to be honest), and surprisingly similar backgrounds, and we are all living in Berlin now, so I think from that perspective we should more or less score the same as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  Umm, so are you gonna do anything about it?
&lt;/h4&gt;

&lt;p&gt;This is something I have been thinking about for the last 48 hours (i.e. not that much time), and here’s my train of thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I should ask my leads on criteria of judging our pay grade&lt;/li&gt;
&lt;li&gt;I should find out what’s the law on “keeping salary a secret” in Germany&lt;/li&gt;
&lt;li&gt;Try to remember and write down how I got this offer (which is more than 5 months ago), and hopefully some of it can be useful to others&lt;/li&gt;
&lt;li&gt;Spread the message to border audiences&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Wait that it?
&lt;/h4&gt;

&lt;p&gt;For now that’s the list of things that I can come up with, and that brings up to a topic that I am no an expert in, but after watching this video, makes me appreciate this whole movement a lot more:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RSgXcFdHxFI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;While it is not about salary or compensation or money, it does bring up a quite interesting topic on how much an individual can do, when facing a deep-rooted mental model that the society held. And from this video, this reminds me of this somewhat exaggerate &amp;amp; American-focus snippet of Adam Ruins Everything:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/7xH7eGFuSYI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The more I think about it, the more I agree that currently the common practices for companies are the biggest bottleneck for achieving fair compensation regardless of age, gender, sexuality, race, and more. How can people have an open discussion on how to tackle pay gap, when people are still arguing that pay gap is not real (although to be fair, there are also people who think the earth is flat, so I guess data and statistics are not as powerful as I think they are 🤷‍♀️).&lt;/p&gt;

&lt;p&gt;Hopefully one day, we can all sit down, have detailed and meaningful analysis and discussion on the inequality in the tech industry, and how we can tack the issue as a whole.&lt;/p&gt;

&lt;h4&gt;
  
  
  Closing thoughts: some criticisms of #KnowYourWorth
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Intentional or not, some of the tweets gonna feel more like &lt;a href="https://www.urbandictionary.com/define.php?term=Humble%20Brag"&gt;humble-brag&lt;/a&gt; (“Oh I make 1000k in SF and you should too!”).&lt;/li&gt;
&lt;li&gt;Privacy is absolutely a big issue here. I get the point here is “This is my name, this is my compensation, and you can trust this info”, but judging by the amount of people who &lt;a href="https://twitter.com/HeatherDoshay/status/1228743317300510726"&gt;backtracking their decisions&lt;/a&gt;, and amount of things people can extract from &lt;a href="https://twitter.com/newsycombinator/status/1228665735632822273"&gt;these data&lt;/a&gt;, I guess it is safe to say this is not a scalable solution to raise awareness.&lt;/li&gt;
&lt;li&gt;Context is absolutely still a very big problem. Does earning 200k in SF means the same thing as 100k in Berlin? And what about things that money cannot buy, like public health care that does not cost an arm and a leg, or nicer weather, or friends and family?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope that it could be the beginning of a much bigger movement towards eliminating inequality, and I swear to god I will do my best to make that happen!&lt;/p&gt;

</description>
      <category>knowyourworth</category>
      <category>compensation</category>
      <category>salary</category>
    </item>
    <item>
      <title>From Android zero to kinda-middle: Basic shell script for Android dev</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 12 Jan 2020 16:01:04 +0000</pubDate>
      <link>https://dev.to/louis993546/from-android-zero-to-kinda-middle-basic-shell-script-for-android-dev-1l28</link>
      <guid>https://dev.to/louis993546/from-android-zero-to-kinda-middle-basic-shell-script-for-android-dev-1l28</guid>
      <description>&lt;h1&gt;
  
  
  From Android zero to kinda-middle: Basic shell script for Android dev
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m72Bc8YB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/uk0ASap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m72Bc8YB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/uk0ASap.png" alt="A bunch of random stuff you can do with shell script"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has been a while since I did my last "From Android zero to kinda-middle" series, and today I'd like to talk about shell script. &lt;/p&gt;

&lt;h2&gt;
  
  
  WTF is shell script
&lt;/h2&gt;

&lt;p&gt;You can think of it as a scripting language + the program that interprets it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you should know shell script?
&lt;/h2&gt;

&lt;p&gt;All the buttons in Android Studio will ended up executing some shell script in one way or another. For example,&lt;/p&gt;

&lt;p&gt;"Run" 👉 &lt;code&gt;./gradlew assemble${flavor}&lt;/code&gt; + &lt;code&gt;adb install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install newer version of Android SDK 👉 &lt;code&gt;sdkmanager "platforms;android${versionCode}"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Commit 👉 &lt;code&gt;git commit -m "${message}"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But if all of the task can be done with buttons, why would anyone want to type all the steps out instead? Well, if you have a series of events you want to run repetitvely, having a script will often makes it a lot easier to deal with, esp. when compare to reading documentation and do it step-by-step. And those automated task can also be done by computers more accurately, for example, have a computer that builds and ship the app every time &lt;code&gt;master&lt;/code&gt; branch is updated. And that is basically what "Continuous Integration" or "Continuous Delivery" (also known as CI/CD) are.&lt;/p&gt;

&lt;p&gt;But this only explains half of the question. What makes shell script different than, let say JavaScript? Well, it's all about the history. Shell script is very much tied to Unix, i.e. the foundation of Linux and macOS, and the popularity of the 2 (amongst developers and servers) makes it pretty much the universal way to tell a computer how to do something. Not only that, being super close to the operating system, it allows a multitude of tools to do whatever they want to do, from transforming video between formats, framerate, resolutions, and more with &lt;code&gt;ffmpeg&lt;/code&gt;, to compiling Java/Kotlin code with &lt;code&gt;javac&lt;/code&gt;/&lt;code&gt;kotlinc&lt;/code&gt;, to tools that communicate with external sources or devices like &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;adb&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can shell script do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In general

&lt;ul&gt;
&lt;li&gt;Travel in the file system (&lt;code&gt;cd&lt;/code&gt;) 🚙&lt;/li&gt;
&lt;li&gt;See where you are (&lt;code&gt;pwd&lt;/code&gt;) 🗺&lt;/li&gt;
&lt;li&gt;Create folder(s) (&lt;code&gt;mkdir&lt;/code&gt;) 📁&lt;/li&gt;
&lt;li&gt;See what files are there (&lt;code&gt;ls&lt;/code&gt;) 🗂&lt;/li&gt;
&lt;li&gt;Modify files (&lt;code&gt;vi&lt;/code&gt;/&lt;code&gt;nano&lt;/code&gt;) 📝&lt;/li&gt;
&lt;li&gt;Open files and programmes (&lt;code&gt;open&lt;/code&gt; on macOS) 👀&lt;/li&gt;
&lt;li&gt;Read files (&lt;code&gt;cat&lt;/code&gt;/&lt;code&gt;less&lt;/code&gt;) 🖨&lt;/li&gt;
&lt;li&gt;Install other softwares (&lt;code&gt;brew&lt;/code&gt;) ⬇️&lt;/li&gt;
&lt;li&gt;Version control with Git (&lt;code&gt;git&lt;/code&gt;, dah) 📚&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Android-specific

&lt;ul&gt;
&lt;li&gt;Talk to Android devices (&lt;code&gt;adb&lt;/code&gt; and &lt;code&gt;fastboot&lt;/code&gt;) 📱&lt;/li&gt;
&lt;li&gt;Update tools to build Android app (&lt;code&gt;sdkmanager&lt;/code&gt;) 📲&lt;/li&gt;
&lt;li&gt;Contribute to AOSP (&lt;code&gt;repo&lt;/code&gt;) 💪&lt;/li&gt;
&lt;li&gt;Use dependencies (&lt;code&gt;gradle&lt;/code&gt;) 😯&lt;/li&gt;
&lt;li&gt;Build the app (still &lt;code&gt;gradle&lt;/code&gt;) 😮&lt;/li&gt;
&lt;li&gt;Test the app (also &lt;code&gt;gradle&lt;/code&gt;) 😲&lt;/li&gt;
&lt;li&gt;Install a specific version of gradle (yes the answer is &lt;code&gt;gradle&lt;/code&gt;, and then you can use &lt;code&gt;gradlew&lt;/code&gt;) 🤯&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to run shell script
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you are on Windows, I'm sorry but 50% of this article is not for you. While the concept is the same, they are so fundamentally different, that you should be using something call "Command Line" or "PowerShell". These are 2 different program + scripting language that runs on Windows, and I have little to no knowledge about them. A quick Google will help you a lot more. And if you are brave enough, you can also try out WSL (and WSL2) to run the following steps. Not everything will work.&lt;/strong&gt; &lt;/p&gt;




&lt;p&gt;Now that Windows users are out of the way, let see some basic commands on Linux or macOS!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open "Terminal" on your computer&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;pwd&lt;/code&gt; to see where you are in the file system&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;cd ${folder name}&lt;/code&gt; to move into a folder &lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;cd ..&lt;/code&gt; to move to out of a folder&lt;/li&gt;
&lt;li&gt;If you are not sure where you are, just type &lt;code&gt;cd&lt;/code&gt; will take you back home.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;mkdir ${folder name}&lt;/code&gt; to create a new folder&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;touch ${file name}&lt;/code&gt; to create a new file&lt;/li&gt;
&lt;li&gt;(macOS only) Open a file with it's default program with &lt;code&gt;open ${file name}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;(macOS only) Open a folder with &lt;code&gt;open .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; means the folder you are currently in&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;man ${command}&lt;/code&gt;(e.g. &lt;code&gt;man git&lt;/code&gt;) shows a manuel of the command&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And now, let's try to create a new git repository, and then delete it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a folder&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;newProject

&lt;span class="c"&gt;# Move into that folder&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;newProject

&lt;span class="c"&gt;# Tell git this is a new repository&lt;/span&gt;
git init

&lt;span class="c"&gt;# Create an empty README&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;README.md

&lt;span class="c"&gt;# Enter some text into README&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Hello, World!"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; README.md

&lt;span class="c"&gt;# Tell git to stage everything&lt;/span&gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Commit with message&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;

&lt;span class="c"&gt;# Show commit history&lt;/span&gt;
git log

&lt;span class="c"&gt;## Go back out&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;## Delete folder (the -r is needed to remove folder. It stands for recursive)&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; newProject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the line starts with &lt;code&gt;#&lt;/code&gt; are short comments that explains what the command does. And feel free to mix and match all of these, or just randomly roll around and try things out. But be careful, you don't want to mess up your computer. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid &lt;code&gt;rm -rf ${anything}&lt;/code&gt; until you know what you are removing&lt;/li&gt;
&lt;li&gt;Stay within the home folder ( &lt;code&gt;echo $HOME&lt;/code&gt; ), most of the stuff outside are programmes that the rest of the system relies on. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical shell script examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install &lt;a href="https://httpie.org/"&gt;httpie&lt;/a&gt;, a pretty user-friendly way to call REST API form terminal
&lt;/h3&gt;

&lt;p&gt;On &lt;strong&gt;Linux&lt;/strong&gt;, there are a lot of "Package Manager", and in this case we will use Debian/Ubuntu as an example, which uses &lt;code&gt;apt-get&lt;/code&gt;, and that is includes when you install the OS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="c"&gt;# Then type your password for the computer&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;httpie
&lt;span class="c"&gt;# Then you will have to accept it&lt;/span&gt;

http &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on &lt;strong&gt;macOS&lt;/strong&gt;, the most popular package manager is call "&lt;a href="https://brew.sh/"&gt;homebrew&lt;/a&gt;", and first, you will need to install it. At the time of writing (Jan 2020), you just need to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# This is from Jan 2020. Please check the website for the most up-to-date install instruction&lt;/span&gt;
/usr/bin/ruby &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/master/install&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Install httpie. This will usually take quite a while&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;httpie

http &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run unit tests for the entire project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Assuming you are already in the folder of your project&lt;/span&gt;
./gradlew &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify code style with pre-commit hook
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/pinterest/ktlint"&gt;ktlint&lt;/a&gt; is a tool that verifies and fixes kotlin code. And git hook is basically a script that runs in specific time in the git process, in this case, pre-commit will run when you are trying to commit, and if it failes, the commit also fails, which makes it a great place for enforce coding style in a team.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the latest version (0.36.0)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSLO&lt;/span&gt; https://github.com/pinterest/ktlint/releases/download/0.36.0/ktlint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nb"&gt;chmod &lt;/span&gt;a+x ktlint &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nb"&gt;sudo mv &lt;/span&gt;ktlint /usr/local/bin/

&lt;span class="c"&gt;# Ask ktlint to install itself as pre-commit git hook&lt;/span&gt;
ktlint installGitPreCommitHook

&lt;span class="c"&gt;# Imagine you have typed some kotlin code that's not perfectly format&lt;/span&gt;

&lt;span class="c"&gt;# Commit and this will fail&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Bad commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build &amp;amp; Publish app automatically with Gradle and fastlane
&lt;/h3&gt;

&lt;p&gt;You probably already know the existance of Gradle (via &lt;code&gt;build.gradle&lt;/code&gt;), and fastlane is a tool that can automate a lot of stuff for Android and iOS developers. Instead of writing all the steps here, please checkout the official documentation on how to &lt;a href="https://docs.fastlane.tools/getting-started/android/setup/"&gt;install&lt;/a&gt; and &lt;a href="https://docs.fastlane.tools/getting-started/android/release-deployment/"&gt;publish to Play Store&lt;/a&gt;, and &lt;a href="https://about.gitlab.com/blog/2019/01/28/android-publishing-with-gitlab-and-fastlane/"&gt;this article from GitLab&lt;/a&gt; on how to compile and run fastlane on Linux&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;I still remember when I start learning/using shell script from about a year ago, and I was like "Ugh really? It's 2019 and I am going back to using computer like the 70s?". But after a while, I realised the flexibility of it opens a lot of doors. It did took a while for me to understand some basic shell script syntax, but I promise you at some point you will file some usecases that shell script will make you life as an Android developer a lot easier to deal with! Thank you for reading, and I will see you next time!&lt;/p&gt;

</description>
      <category>androiddev</category>
      <category>shell</category>
    </item>
    <item>
      <title>Mental Models of Jetpack Compose #3: Inheritance, Composition, and why they matter</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Tue, 22 Oct 2019 06:42:53 +0000</pubDate>
      <link>https://dev.to/louis993546/mental-models-of-jetpack-compose-3-inheritance-composition-and-why-they-matter-4dal</link>
      <guid>https://dev.to/louis993546/mental-models-of-jetpack-compose-3-inheritance-composition-and-why-they-matter-4dal</guid>
      <description>&lt;h3&gt;
  
  
  Mental Models of Jetpack Compose #3: Inheritance &amp;amp; Composition
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JvBsFaQ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_2BwC6xlUiSt5VHeMTFrIA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JvBsFaQ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A_2BwC6xlUiSt5VHeMTFrIA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Previously, on MMoJC:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;We talked about what even is mental model&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We talked about what is state&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We talked about what is Programming Model&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We talked about Declarative UI&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We talked about separation of concerns&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for today, I’d like to talk about Inheritance &amp;amp; Composition in the context (&lt;a href="https://twitter.com/ataulm/status/1185637270730268672"&gt;no not that&lt;/a&gt;&lt;a href="https://twitter.com/ataulm/status/1185637270730268672"&gt;Context😂&lt;/a&gt;) of Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance
&lt;/h3&gt;

&lt;p&gt;Android was born (officially) in 2008: Java 1.6, JavaScript is just some things you use to animate stuff, not build a full blown web app, not even the word “app” is a thing just yet. And when it comes time to build all the basic view components, there are probably quite a lot of restrictions on what they can build in a limited amount of time (esp. since iPhone just got released, the pressure is on!). So in order to encourage code-reuse (i.e. DRY), they made a View class that every classes extend from, and then they can add extra functionality, and it just keep growing like that, &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/8ek3ot/shots_were_fired_in_my_discrete_math_textbook/"&gt;just like a tree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kVHz5s-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AFdawx1uv8swSvhgsg14Cdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kVHz5s-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AFdawx1uv8swSvhgsg14Cdg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s wrong with inheritance
&lt;/h3&gt;

&lt;p&gt;While it definitely helps everyone to reuse UI code, like “Button don’t have to implement their own text rendering logic”, it is also very limiting on building complex things, which turns out to be the case, when Android become the most popular OS in the world.&lt;/p&gt;

&lt;p&gt;For example: Button with an image instead of text. When I first start learning Android, at some point I was trying to use an image instead of text for a button, so when I find ImageButton, I was like “jackpot”, and just converted it in the XML. but then 20 seconds later, everything broke, and I got a bunch of compile error. Turns out a lot of the functions that I was calling from the Java side don’t work anymore, and it’s because Button and ImageButton, although share a very similar name, has almost nothing in common 😐&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--djVyek84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AMQN1tnnnJDIxPqh7Gj3lHg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--djVyek84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AMQN1tnnnJDIxPqh7Gj3lHg.png" alt=""&gt;&lt;/a&gt;ImageButton and Button are both View, so that's something I guess 🙆‍♀️&lt;/p&gt;

&lt;p&gt;Maybe the Android team could have design these 2 views the other way around? But in general I hope you got the point of “how difficult it is to predict how people mutate their UI, and what would be the best hierarchy to ensure high level of compatibility”.&lt;/p&gt;

&lt;p&gt;There is another way people discover this to be an issue over time, and it’s when people try to update existing UI: we get some ticket on what new feature we needs to implement in the UI, we updated that View, and make sure it’s covered with test. What could possibly go wrong? Well, if you are building a library of views that thousands if not millions of other classes inherent from, too bad! Since there is no clear mechanism to warn every single places that extends from you to double check if the change in behaviour is acceptable, you kinda just have to prey nothing went wrong. One example that the Google team pointed out is the “selectable text in Button”, which maybe 3 apps in the world needs it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B_T60zqO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AugomrHFMusnZRLkbt0gEwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B_T60zqO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AugomrHFMusnZRLkbt0gEwg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR: Building UI with inheritance does not scale over space and time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(BTW inheritance is not the only thing that didn’t aged well with View, but that’s story for another day)&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Composition: Is it the answer we are looking for?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So how else can we build reuseable View? For that, let see if composition helps: Instead of saying “Button = modify view to show text, and modify text to have a specific style”, just say “Button = Whatever hint you want + some background + click callback”. And an example for that can be seen in Flutter, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/media/b954722363f4154bff5eeb209c18658a/href"&gt;&lt;/a&gt;&lt;a href="https://medium.com/media/b954722363f4154bff5eeb209c18658a/href"&gt;https://medium.com/media/b954722363f4154bff5eeb209c18658a/href&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And all of these are technically possible in the past, but the developer experience/ergonomics will be so bad, no one will like to develop for the platform to begin with! With much better tooling like IDE with crazy-good autocomplete support, build system that can process a huge amount of dependencies, and stack traces that gets more and more human-friendly over time, we are start to utilize composition to our advantage!&lt;/p&gt;

&lt;p&gt;So is it the “ultimate” solution to UI building? It’s closer, but there are still some gaps to fill, and with the each of the composition-based UI framework, there are different trade-offs they’ve made, and that’s what we will cover in the next chapter!&lt;/p&gt;

&lt;p&gt;Hope you like what I have wrote, and if you have any feedback or anything, feel free to leave a comments down below! Thanks!&lt;/p&gt;

</description>
      <category>jetpackcompose</category>
      <category>android</category>
    </item>
    <item>
      <title>Mental Models of Jetpack Compose #2: Declarative UI (with code) &amp; separation of concerns</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Mon, 19 Aug 2019 13:31:33 +0000</pubDate>
      <link>https://dev.to/louis993546/mental-models-of-jetpack-compose-2-declarative-ui-with-code-separation-of-concerns-4636</link>
      <guid>https://dev.to/louis993546/mental-models-of-jetpack-compose-2-declarative-ui-with-code-separation-of-concerns-4636</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4GIqZqoc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyEOKwO2nR_D-uraGqiMNNw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4GIqZqoc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AyEOKwO2nR_D-uraGqiMNNw.jpeg" alt=""&gt;&lt;/a&gt;Separation. Photo by &lt;a href="https://unsplash.com/@jamie452?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Jamie Street&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/lanes?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/louis993546/mental-models-of-jetpack-compose-1-state-programming-models-20eh"&gt;last chapter&lt;/a&gt;, we looked at 2 mental models: “state”, and “programming models”. And now, let’s take it 1 step further and see how declarative model translated to the world of UI development. 🌀&lt;/p&gt;

&lt;h3&gt;
  
  
  Declarative UI (and the spectrum of it)
&lt;/h3&gt;

&lt;p&gt;Even when the goal went from “describing the process of building a house 🏠 ”(imperative) to “describe the house 🏠”(declarative), there are still a lot of different ways to “describe the house 🏠”. You can make a CAD, you can sketch it out on pen and paper, or you can write a 200 page descriptions of every single texture, material, and color of every single wall. And in my opinion, it is more or less the same story for declaring UI. There are a lot of different solutions, and the amount of flexibility you have is one of the most obvious different between them:&lt;/p&gt;

&lt;h4&gt;
  
  
  The static kind of declarative UI
&lt;/h4&gt;

&lt;p&gt;Basically most if not all markup languages (e.g. XML, HTML) are in this category. In those languages, there is not much you can do, other than laying out existing “components” or “tags” or “whatever you want to call it”. If you want to do pretty much anything else, you will have to go back to imperative-programming-land.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" \&amp;gt;

    &amp;lt;TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, World!" \&amp;gt;

&amp;lt;/LinearLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Less static kind of declarative UI
&lt;/h4&gt;

&lt;p&gt;While XML is not the most human-friendly syntax, it’s still far from “terrible to read” or anything. And if it is still understandable, what if we just add a few extra feature on top of it? Introducing data binding, officially introduced to Android Developer back in 2015.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5sCQjeGoE7M"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It is still very much based on all the existing syntaxes, along with all the XML skills developers have build up over the years. It basically just introduce a series of basic imperative programming tools, and makes it a lot easier to keep more of the “concern of the UI” in the XML itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

&amp;lt;TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewmodel.userName}" \&amp;gt; // &amp;lt;- tada 🎩

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  A really dynamic kind of declarative UI
&lt;/h4&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/GW0rj4sNH2w"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And just 2 years before that, in the world of web development, a little project call &lt;a href="https://reactjs.org/"&gt;React.js&lt;/a&gt; got open-sourced by facebook, and while the early responses was not exactly stellar, it doesn’t take long before the industry adopts it in a very rapid pace. And not just React itself, similar frameworks also started to pop up and got adopted by the industry: Vue.js, Angular, and later to the world of Android (and iOS) with React Native, Anko, Litho, and more recently Flutter. So what makes it special?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Hello extends React.Component { 
  render() { 
    return &amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;gt;; 
  } 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While data binding introduces logic into a markup language, React does the opposite, by introducing markup language into a imperative programming language. While that might sound counter-intuitive (if the goal is to encourage declarative code, why would we make it so easy to write imperative code!?), the reality is that making a generic declarative programming framework is really really really hard. People build wildly different things that looks and acts very differently, and the last thing a developer wants to do is staying up at 3am to debug not their own code, but deep dive into the framework, and is still 10 hours away from realizing that the framework just haven’t take that edge case into account, and the only way to really fix it is to reverse the order of how the framework interpret 50% of the code.&lt;/p&gt;

&lt;p&gt;Basically it’s just a very long way to say “we hate black magic”, and having a good “developer ergonomics/experience” is a big missing piece that previous attempts of declarative UI framework missed. Stuff like debugger and breakpoints, log, and a syntax that you are already used to, are really helpful, and by using an imperative programming language like JavaScript, it makes React (and similar UI frameworks) very attractive to developers.&lt;/p&gt;

&lt;p&gt;There are also a lot of other reason why people find React attractive, and they will be cover in later chapters with other mental models. So stay tune ! ⏰&lt;/p&gt;

&lt;h3&gt;
  
  
  Separation of concerns
&lt;/h3&gt;

&lt;p&gt;I feel like one of the biggest concerns some developers have had with the React.js kind of declarative UI is that “it violates the &lt;a href="https://en.wikipedia.org/wiki/Separation_of_concerns"&gt;separation of concerns&lt;/a&gt;”. While I’ll admit that now that everything can be in the same place, it can be tempting to just “nah I will just throw everything this one class”. It’s just that XML is not necessarily a good way to “separate concerns” either. For example, “show ProgressBar when loading, show RecyclerView when load finished”, I would definitely classify that as view logic, but the Java/Kotlin code is the one that triggers that. Simple cases like this can be mitigated with data binding, but then you can also &lt;a href="https://medium.com/@hellotimmutton/an-argument-against-data-binding-13e2aaf7a9b1"&gt;go way over-board with it&lt;/a&gt; as well, and add business logic into XML.&lt;/p&gt;

&lt;p&gt;What I am trying to say, is that while XML encourages separation of concerns, sometimes XML can give us the illusion that it is actually there when it’s not. And the limitation of it being just a markup language makes it harder to see the big picture at once. Having the UI + UI logic + business logic (+ more) in the same syntax makes it a lot easier to refactor (or just simple re-organize) them, into the most logical “concern” that it actually belongs.&lt;/p&gt;

&lt;p&gt;So that wraps up chapter 2, and again, more chapters are coming up. If you have any comments, ideas, or feedback, leave a comment down below, or find me on twitter! 🐦&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/louis993546"&gt;Louis Tsai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>separationofconcer</category>
      <category>declarativeprogramm</category>
      <category>jetpackcompose</category>
    </item>
    <item>
      <title>Mental Models of Jetpack Compose #1: State &amp; Programming Models</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 18 Aug 2019 19:11:47 +0000</pubDate>
      <link>https://dev.to/louis993546/mental-models-of-jetpack-compose-1-state-programming-models-20eh</link>
      <guid>https://dev.to/louis993546/mental-models-of-jetpack-compose-1-state-programming-models-20eh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Update (2019.08.19): &lt;a href="https://dev.to/louis993546/mental-models-of-jetpack-compose-2-declarative-ui-with-code-separation-of-concerns-4636"&gt;Chapter #2 is now up&lt;/a&gt; 🎉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P4vEd95u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Azij_6EWgVip4GyOtH8zBMA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4vEd95u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Azij_6EWgVip4GyOtH8zBMA.jpeg" alt=""&gt;&lt;/a&gt;Generic representation of “mental model”. I don’t really know how to visualize this concept 🤷&lt;/p&gt;

&lt;p&gt;So last month, droidcon Berlin happened, and &lt;a href="https://twitter.com/droidconBerlin/status/1140894454909419520"&gt;I gave a talk on Jetpack Compose&lt;/a&gt;, and &lt;a href="https://speakerdeck.com/louistsaitszho/jumping-into-jetpack-compose-way-too-early-to-see-whats-inside"&gt;gave a brief overview of the internals, and some decisions they have made&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I did wrote &lt;a href="https://dev.to/louis993546/prepare-a-jetpack-compose-talk-with-me-1-where-do-i-even-start-2li8-temp-slug-4755348"&gt;a bunch of blog posts&lt;/a&gt; leading up to the conference, and I really appreciate all the supports. While the videos are still not available 😠, and there is also not much feedback from the attendees, I do feel like there are a lot of basics that should have been covered instead. So today, I would like to give you guys a brief overview of a bunch of so call “Mental Models”, which IMO is the 1st step to get you to understand what Jetpack Compose really means to being an Android Developer in the future.&lt;/p&gt;

&lt;p&gt;So first, before talking about any mental models, let’s briefly talk about what even is it, and why I think they are important. According to Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A mental model is an &lt;strong&gt;explanation&lt;/strong&gt; of someone’s thought process about how something works in the real world.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First and foremost, it’s an explanation. Second, it’s from a person, so it can be personal, subjective, even over-simplified (i.e. technically wrong).&lt;/p&gt;

&lt;p&gt;And why is it important know some mental models to understand Jetpack Compose? In my opinion, there are so many potentially earth-shattering changes that Jetpack Compose brings, and along with it, a bunch of current best practices or standards are gonna be obsolete at best, and flat out wrong in some cases. And just like the transition from Jave to Kotlin, or AsyncTask to Rx, or Rx to Coroutine, there are some things you might want to un-learn, and in order to un-learn those things, you have to wrap your head around the original problem, and then reapply the new way of thinking onto it, i.e. the mental model.&lt;/p&gt;

&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;Unless you are playing &lt;a href="https://github.com/fractalwrench/ApkGolf"&gt;apk golf&lt;/a&gt;, your apps have &lt;a href="https://en.wikipedia.org/wiki/State_%28computer_science%29"&gt;states&lt;/a&gt;. The view have states, your logic have states, there’re states everywhere. Basically if your code &lt;strong&gt;remembers&lt;/strong&gt; any event (it can be text change, network response, system callback, pretty much anything), your application is consider “stateful”, and that piece of data is a “state”. All those event only happen for a few milliseconds, and a state exists to persist it longer that.&lt;/p&gt;

&lt;p&gt;And what you usually do with any state is to transform the view accordingly. Some common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the flag &lt;code&gt;checkCheckbox == true&lt;/code&gt;, then set a &lt;code&gt;CheckBox&lt;/code&gt; to checked&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;List&amp;lt;User&amp;gt;&lt;/code&gt; changes, then set the &lt;code&gt;ProgressBar&lt;/code&gt; to &lt;code&gt;GONE&lt;/code&gt;, and set the &lt;code&gt;RecyclerView&lt;/code&gt; to &lt;code&gt;VISIBLE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Programming Models/Paradigm
&lt;/h3&gt;

&lt;p&gt;So your program have states, but how do we change between them? We do that with code, and the different ways we write code is what we call “Programming Models” or “&lt;a href="https://en.wikipedia.org/wiki/Programming_paradigm"&gt;Programming Paradigms&lt;/a&gt;”. And when I say “different ways”, I don’t just mean programming languages, or architectures, or “how many ways to add 1 to &lt;code&gt;x&lt;/code&gt;”(&lt;code&gt;++x&lt;/code&gt;, &lt;code&gt;x++&lt;/code&gt;, &lt;code&gt;x += 1&lt;/code&gt;, &lt;code&gt;x = x + 1&lt;/code&gt;, and more).There is a fundamental thought process baked into the language design, the standard libraries, and everything in-between, and that defines how we come up with solutions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Imperative programming
&lt;/h4&gt;

&lt;p&gt;TL;DR: In &lt;a href="https://en.wikipedia.org/wiki/Imperative_programming"&gt;imperative programming&lt;/a&gt;, you use statements (or so call “instructions”) to change the state of a program. As a programmer, you are in charge of writing &lt;strong&gt;how&lt;/strong&gt; to change a state, like every &lt;code&gt;setText&lt;/code&gt;, every &lt;code&gt;notifyDataSetChanged&lt;/code&gt;, and every &lt;code&gt;invalidate&lt;/code&gt;. If you trigger it multiple times, you might not generate the same result; and if you trigger it at different state, it might not generate the same result as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  Declarative programming
&lt;/h4&gt;

&lt;p&gt;TL;DR: In &lt;a href="https://en.wikipedia.org/wiki/Declarative_programming"&gt;declarative programming&lt;/a&gt;, instead of writing how a program should perform, you more or less just write a general rule/expected outcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In SQL, you don’t write “go to the beginning of the user table, and extract 5 rows”, you just write “fetch 5 items from the user table”.&lt;/li&gt;
&lt;li&gt;In regular expressions, you don’t write “split the input by &lt;code&gt;.&lt;/code&gt;, and then count how many groups are there”, you go to &lt;a href="https://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp"&gt;StackOverflow and copy the most upvoted answer&lt;/a&gt; on “the rule of digits-dot-digits-dot-digits-dot-digits”, i.e. IP address.&lt;/li&gt;
&lt;li&gt;And in Android layout (we are talking about xml here), you don’t write “add &lt;code&gt;TextView&lt;/code&gt; to &lt;code&gt;LinearLayout&lt;/code&gt;, and then add another &lt;code&gt;TextView to that&lt;/code&gt;LinearLayout&lt;code&gt;”, you write 2&lt;/code&gt;TextView&lt;code&gt;s surrounded by a&lt;/code&gt;LinearLayout`.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And once you wrote all of that, you pass it off to someone: SQLite, &lt;code&gt;java.util.regex.Pattern&lt;/code&gt;, and &lt;code&gt;LayoutInflator&lt;/code&gt;, and they will magically find a (probably) efficient way to give you the result you expected.&lt;/p&gt;

&lt;p&gt;One thing to note is that there can be quite a bit of overlap/intertwine between these 2 models, and &lt;code&gt;RecyclerView&lt;/code&gt; is a good example: the ViewHolder pattern is quite declarative: it doesn’t really care who/how/why someone trigger’s it, you just render the ViewHolder according to the input; while the &lt;code&gt;Adapter&lt;/code&gt; is very much imperative, since you are responsible using statement(s) to notify the right position to trigger that specific ViewHolder to update.&lt;/p&gt;

&lt;p&gt;It’s also not that uncommon to wrap existing imperative code in a declarative way, and the &lt;a href="https://developer.android.com/guide/navigation/navigation-getting-started"&gt;Navigation Component&lt;/a&gt; is a good example for that. It is powered by all the existing Fragment APIs, but instead of imperatively giving the manager a transaction, we declaratively pre-define all the possible screens and directions between them, and the correct transaction will be generated and executed. Other common examples includes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON parsing with Moshi’s codegen&lt;/li&gt;
&lt;li&gt;Data binding&lt;/li&gt;
&lt;li&gt;And pretty much everything Gradle does&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of them are generate code at compile time, some of them just transform them into the correct parameter at runtime, either way, as a user of those libraries, you are only responsible for asking “what”, not “how”. And while Wikipedia list Java (and presumably Kotlin) as imperative languages, it is also not uncommon for them to get some features that is more declarative, most notably, annotation, and DSL.&lt;/p&gt;

&lt;p&gt;So this wraps up the first chapter of “Mental Models of Jetpack Compose”, and a few more chapters have already been planned. If you want to know more, or if there are any comments, or if I have made any mistakes, please feel free to let me know 🤗&lt;/p&gt;

</description>
      <category>android</category>
      <category>jetpackcompose</category>
      <category>programming</category>
      <category>mentalmodels</category>
    </item>
    <item>
      <title>From gqlgen to GraphQL.js: a story of “choosing the right tool for the right job”</title>
      <dc:creator>Louis Tsai</dc:creator>
      <pubDate>Sun, 14 Jul 2019 15:40:29 +0000</pubDate>
      <link>https://dev.to/louis993546/from-gqlgen-to-graphql-js-a-story-of-choosing-the-right-tool-for-the-right-job-3ca9</link>
      <guid>https://dev.to/louis993546/from-gqlgen-to-graphql-js-a-story-of-choosing-the-right-tool-for-the-right-job-3ca9</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AHKerLy4MDPdmIqvfbLovKA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AHKerLy4MDPdmIqvfbLovKA.jpeg"&gt;&lt;/a&gt;&lt;a href="https://unsplash.com/photos/C8V9gKjMr_s" rel="noopener noreferrer"&gt;Oh this? It has nothing to do with the content, I just took this yesterday and I quite like it ¯_(ツ)_/¯&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few months ago, I briefly talked about &lt;a href="https://medium.com/@louis993546/loft-choosing-graphql-instead-of-rest-api-w-the-help-of-gqlgen-14c8643ee9a1" rel="noopener noreferrer"&gt;using gqlgen to create a backend&lt;/a&gt; for a now &lt;a href="https://dev.to/louis993546/loft-i-ll-be-back-3ha5-temp-slug-6235093"&gt;“postponed” project&lt;/a&gt;. And after that, I have been trying to create a GraphQL wrapper for the official HackerNews REST API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/louistsaitszho/HackerNews-GraphQL" rel="noopener noreferrer"&gt;louistsaitszho/HackerNews-GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HackerNews/API" rel="noopener noreferrer"&gt;HackerNews/API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And about a week ago, I finally said “screw it”, delete everything, and restart from scratch with GraphQL.js&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/99designs/gqlgen" rel="noopener noreferrer"&gt;99designs/gqlgen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/graphql/graphql-js" rel="noopener noreferrer"&gt;graphql/graphql-js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what went wrong? Is it because of Go? Is it because of gqlgen? Or is there something/someone else to blame? Let’s find out!&lt;/p&gt;

&lt;p&gt;So, the premise of the project is simple: the REST API is kinda weird, since it returns (almost) exclusively just ID. Clients will have to fire a billion extra requests to get enough data to show on screen. This is probably not a good thing, especially for mobile devices, so let’s use GraphQL as a proxy, and expose the flexibility to the client. The (presumably) powerful server does most of the heavy lifting, and in might even be able to add some clever caching mechanism at some point.&lt;/p&gt;

&lt;p&gt;So I started the project with Go and gqlgen, mostly because of 3 reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want to practice my Go skills&lt;/li&gt;
&lt;li&gt;I have use gqlgen before&lt;/li&gt;
&lt;li&gt;The premise of “type safe + codegen” seems like a perfect fit for GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I still stand by all those reason why I chose it in the first place. And at the beginning, it doesn’t take long to whip out a super simple “happy path only + not efficient” schema + resolver + query. But the moment I start to drill down a bit, it starts to get kinda convoluted. Here’s a list of things that I have to figure out how to solve with my very limited knowledge of Go &amp;amp; gqlgen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the query only ask for id, it should not invoke any extra API call. That means I need to tell gqlgen to use resolver to get every-single-field-in-basically-every-single-type. It gets really verbose real fast.&lt;/li&gt;
&lt;li&gt;The ID for item (story, comment, job listing, poll, poll option) is an integer, while the ID for user is a string (like handler for twitter), but I can’t teach gqlgen to interpret GraphQL’s ID type to 2 different type at the same time.&lt;/li&gt;
&lt;li&gt;It took me way too long to realized that I should at least put the resolver functions into another file, so that when I have to update the schema and regenerate resolver.go, I don’t have to painfully put the logic back in -_-&lt;/li&gt;
&lt;li&gt;Update from dep to mod. Not really a problem, just something I have to deal with.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And after like 2 month, I really starting to feel like I am fighting both Go and gqlgen at every level. I just want to get a Hacker News API in GraphQL done. There’s got to be a better way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F281%2F1%2AXHhbQ21lLyLw3i2i6qeNEw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F281%2F1%2AXHhbQ21lLyLw3i2i6qeNEw.gif"&gt;&lt;/a&gt;&lt;em&gt;my brain after 2 months&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since I don’t control Hacker News, nor its API, I will have to adjust how I tackle the problem. Here’s a list of things that I have re-consider during that time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type-safety: Maybe for this project it matter less? The output definitely needs to match what the GraphQL schema specified, but the internals don’t have to be. In fact, there are some benefit to not having type-safety, so that there are less ceremonial type cast/check/conversion.&lt;/li&gt;
&lt;li&gt;Framework: Having schema-first with codegen + a billion lines to configure it is probably not what this project needs. Just do a typical resolver-first approach.&lt;/li&gt;
&lt;li&gt;Developer ergonomics: I am still very much in Java-esq-languages-land, and trying to figure out pointers, basically no OOP, and not knowing how to do basic parallelism, means I probably spend more time going the wrong way, run into dead end, and go back and realize what the right approach is. Don’t get me wrong, it’s nice to learn, but it’s not nice to feel like you have accomplish nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F498%2F1%2AsigTjKGJtjmJ0pVJLoqLFg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F498%2F1%2AsigTjKGJtjmJ0pVJLoqLFg.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So after considering all of the above, I decided to give GraphQL.js a shot. And fast-forward to today, I have already build a lot more of the resolvers comparing to the old one with Go + gqlgen, so I think it’s safe to call it a success (for now).&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, &lt;strong&gt;I still really like Go and gqlgen&lt;/strong&gt;. It’s just that in this very particular case, &lt;strong&gt;it’s not the right tool for me nor this project&lt;/strong&gt;. And on the other side of the spectrum, there are still a lot of things I don’t like about Node.js + JavaScript + GraphQL.js, but most of them are trade-offs that I can deal with (for now).&lt;/p&gt;

&lt;p&gt;So what’s the takeaway here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the right tool for the right job.&lt;/li&gt;
&lt;li&gt;If you have good reasons, don’t be afraid to do some experiment, and even restart what you are working on. It might actually pay off.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/skirani/status/1149302828420067328" rel="noopener noreferrer"&gt;10x engineers&lt;/a&gt; are the future of society, and you have to learn how to spot and keep them. &lt;a href="https://www.urbandictionary.com/define.php?term=%2Fs" rel="noopener noreferrer"&gt;/s&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you are interested in Go/gqlgen/Node.js/JavaScript/Hacker News/this project/GraphQL/basically anything, feel free to leave a comment or reach out to me 🤗&lt;/p&gt;

</description>
      <category>go</category>
      <category>node</category>
      <category>graphql</category>
    </item>
  </channel>
</rss>
