Side note: been burdened with recent long pieces, didn't I say "Try shorter pieces in 2021"? I get it, striving for good showmanship in writing is a respectable pursuit, but if trying to overachieve makes the whole thing unsustainable, then you've got to stop! Stick to the basics, focus on the main value of the blog.
So, I've been itching for a new (coding) project lately (merely reading SN code or learning related concepts is far less stimulating). A learning project mostly, a messaging app, maybe with some social features. That directs me to mobile devices. I could still do a web app in Elm (I'd love to work with Elm, and Elm-UI, for DX's sake), but besides performance disadvantages, accessing it from a public URL is not ideal.
I wasn't into mobile, until now. Between my laptop and my phone, I'd choose laptop in a nanosecond. But for real-time communication, phones are necessary. Now I suppose a native app will be superior to an equivalent web app in theory, and I already know what working with the latter platform is like, hence the one thing left is to get my hands dirty and see for real how good (or bad, compared to e.g. the Elm experience) the life in the mobile land is.
Because of the jail situation, iOS is not an ecosystem I want to get involved (macOS is fine, you know, as long as people can install apps outside the store. BTW, an interesting inconsistency there... so is iPhone doing PG or something for a special demographic?). That leaves me Android. Yet we're facing options again: standard Android with Kotlin, or Flutter with Dart (see below). Now compared to Elm, the "batteries-included" Android SDK is heavyweight. But I'm fine with that, for 1) I get to save a lot of time on visual design and UI components, and 2) by actually using Android's pro-made dev resources and guidelines, I get to expand my horizon beyond n=1 (well, not literally 1), and hopefully learn something new. (But I'm yet to see evidence of innovation or superiority, e.g. Android uses the old "padding and margin" scheme, while Elm-UI's "padding and spacing, but no margin" is vastly more ergonomic, and design-wise, I consider it elegant.)
With Elm, you do a lot of DIY, esp. in UI, and that's a big part of the Delight. Now I suppose in Android, thanks to so many ready-to-use layouts and widgets, I can shift my focus to the backend. Indeed, I believe the main challenge of a messaging app is in the design of a server-side architecture that is high-performance, secure, and supports rich data API.
Did I say "server", aka. the sin of the web? Well, that's why I postponed learning about the evil deeds, until now. The realization came much earlier, but because of existing projects, I couldn't manage to invest in new ones. The realization was as follows: client-server is simple, and thus easy to think about. Yes, in practice, it is shit to make a real backend with, but the consumers of a backend loves it when they only need to deal with a server. That's why DynamoDB, a distributed system, offers an API that makes it feel just like a bad old server. Even the Safe Network, when designing its data API, aims to make it easy for traditional developers to switch over, namely, by making SN function like one big server, from the perspective of frontend apps. Again, client-server is the simplest model of frontend-backend communication, and even if in the happy future distributed systems take over the internet, this mental concept will not go away. We know distributed is good, but nobody wants to talk to it, it's meant to be a "boring complexity" well hidden from us, just as we don't model our learning process in terms of neural signals and wiring changes, but abstract yet simple cognitive constructs.
The now ubiquitous async/await syntax is quite an analogy here. Synchronous programming is simple, but performance-wise it is, again, shit. So people invented asynchronous mechanisms to bring about concurrency. Yet programmers don't like coding "asynchronously", if they can at all. Therefore, language designers introduced "await" to make the code look synchronous again. (Perhaps the floppy disk icon for the save button gives the same idea.)
Moreover, client-server is not only simpler to reason with, but also implement in. Therefore, it is the natural order of development and progress, esp. in the engineering domain. David Irvine started as a server guy, making network appliances (Hooli Box?), and there, he saw the problems. And, could Einstein have discovered relativity without knowing Newtonian mechanics first? Probably not, because without seeing the problems of an existing system, no one is driven to make something more complex than an "MVP" in the first place. That's also why HTTPS was an afterthought.
One particular example is user authentication. SN's self-auth (without servers) is a big part of its fundamental characteristics, but one has to see traditional auth in action before being able to appreciate truly the significance.
I as an non-programmer just believed in SN's way based on common sense, which is fine for a user. But as a programmer now, the journey of trial and error must not be skipped, because in engineering, details are extremely important, and to clearly see them, there is no substitute for actual doing.
Go learn servers.
Flutter vs. Kotlin
Flutter was the first thing I looked into, as judging from the face value, it appeared to be a winner. One codebase in Dart gives you both Android and iOS apps. (But as I said, I don't care about iOS.)
Of course, I could try it out and then decide. But I prefer smelling to tasting, and I did end up smelling some Flutter smells.
Dart: A language initially made to be a better JavaScript, for developers, yet they thought the answer was to make it look/feel like Java, even more Java than Kotlin, a JVM language, is willing to go. This is very uninspired. JS is somewhat functional-friendly; Kotlin embraces functional programming extensively, with more ergonomic syntax, plus null safety (which Dart is still catching up). Even without a complete tour of Dart, I was already turned down - A young non-JVM language copycatting Java syntax and paradigm is so anti-climatic of a design.
Skia: I understand why the decision was made (performance and completeness), but reinventing a new UI library that fully encompasses and emulates two large UI libraries (also keeping everything up-to-date), just for the sake of using a single language, is too heavy-handed to my taste. I much prefer the Kotlin approach of coding the UI part natively: if I ever started to care about iOS, I would just learn Swift and do things the Apple way. Kotlin Multiplatform is lean and mean, while Flutter, although ambitious, might be aiming for a simplification that could end up complicating things, as Flutter is unlikely to replace and kill two hugely popular and mature SDKs, but instead must play catchup endlessly to stay relevant.
The Book: The Flutter team officially partnered with a book as the go-to tutorial for learning the SDK. After the intro chapter, I jumped directly to later topics I was curious about (HTTP and state persistence), and the presentation turned out to be a mindless dread. A book "for zombies" if you will. I mean the example (a recipes app) is approachable, but the way technical things are communicated is like they don't care, or have given up. I know tutorial books like this exist (you are mindlessly walked through a bunch of examples), and apparently there is a market for them, but the warning sign is that the Flutter team picked this book to promote officially (even if this is the only book on Flutter now, the team doesn't have to do it). If I were to recommend a book written by others about something I made myself, I would make damned sure that it is better than anything I could write myself. Maybe the Flutter team just couldn't wait any longer? Any publicity is good publicity?
The Details: Here comes the devil again. Again, I prefer to smell out the winner without tasting each, not only due to innate laziness, but even if I set up both SDKs and tried the same toy example in each, I would most likely still not see any problems, because obviously both systems work. Until I dive way deeper, the devil is not going to show up. Google is big, but the necessary ecosystem for a mobile SDK to be "healthy" is even bigger. As far as I can see, Flutter is still an experiment, and people have written about the rough edges regarding Flutter and the supporting resources around it, including libraries and IDE tooling.
Kotlin, on the other hand, comes with everything the Android ecosystem has to offer, for free. This is the same reason why TypeScript is rapidly gaining momentum. All to gain, nothing to lose, that's the trick (including to win the official support status from Google/Android). A language designed by JetBrains, a tooling company, that almost made me think if it could be made overly ergonomic? Like synthetic drugs designed to maximize high? Indeed I saw a surprising amount of syntactic sugar to make it look attractive for us the spoiled, well, I guess we are doomed anyway.
Since I'm only choosing from two options, let's call it done and move on.
P.S. Flutter is also shown to produce larger-sized Android apps than Kotlin/Java; and even though it does compile to native code, in certain test cases, the performance is still not on par with Kotlin/Java. So apparently code optimization level is one of the tradeoffs for abstracting over two large platforms.
DynamoDB vs. Redis
My previous (toy) learning project, a Workflowy/Dynalist clone, used WebSocket (for "push") + Redis (for storage and pubsub), back then, I just read the Rust book, but decided to go with a Python web framework ("aiohttp") so that I could move at a reasonable pace. I remember I did check out a Rust server framework ("tide"), but I didn't even know how to add Redis to the context. I didn't regret that decision, but now I've had one and a half Rust projects under my belt, the sure way forward is to Rust on.
For "push" (server sending a message to chatroom members), I know WebSocket works, in Web context, but how about native Android? TODO.
Now for storage, I initially wanted to try something new. Redis was quite something, and chat is even more performance-sensitive than note taking, but I wasn't sure if "DIY server" is still a sane thing to do any moore. What if going "cloud" is the more hygienic approach nowadays? Solid security, state-of-the-art scalability, and you don't need to do a thing. Maybe DynamoDB?
A few factors eventually pushed me away from that road.
- No local dev setup (way harder to play with)
- Had to deal with a heavy AWS SDK (moreover, Rusoto is "dead", and the new kid is in alpha)
- Magic & blackbox, etc
This is a learning project, so if you go cloud, then instead of learning e.g. Redis Cluster, you take the hard part of distributed systems for granted. The opposite of learning.
DynamoDB is opaque, made to be deceivingly comfy to use, while Redis is a much simpler, and more transparent solution, and it's open technology.
I also stumbled upon AWS's MemoryDB, so yes, even they know Redis is good. And if I recall correctly, MaidSafe mentioned Redis in one of the README files.
So, Redis, round 2.