diff --git a/content/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md b/content/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md new file mode 100644 index 0000000..9e088d8 --- /dev/null +++ b/content/posts/2024.01.01.mobile-dev-what-i-enjoy-using.md @@ -0,0 +1,208 @@ +--- +title: "What I'm enjoying using for mobile app development" +date: 2024-01-02T04:33:55Z +draft: false +toc: false +images: +tags: + - dev + - react + - mobile + - typescript +--- + +I like baking bread. Well, most of all I love bread, and baking it myself is +more convenient than tracking down a good bakery nearby. I used to bake a lot +--and as a hipster I'll tell you that it was before everyone else started doing +it at the start of the pandemic-- but I got bored of it some time ago and quit. +But I've been eating more bread recently, and decided I could bake something +better, and cheaper, than the bread from the grocery store. I'm pretty happy +with what I've been baking too, they are all turning out with a good crust and +soft insides. What's the inside of the bread called? Anyway, my bread is good +but a little bland, so I decided to also get back into sourdough bread to get +some nice flavor. + +Sourdough bread is made with sourdough starter, a live culture of yeast and +bacteria that needs to be maintained with regular feedings of flour. So before +you can bake sourdough bread, you must first prepare your starter and grow it +for a few weeks to get its strength up, then keep it alive for as long as you +want to keep baking. And before you can prepare a sourdough starter, you must +first develop a mobile app. + +Well, of course I could have just set up reminder in my calendar and skip having +to develop an actual app. Or just use on of the proprietary ones. But why do the +easy thing when you can waste tens --if not hundreds-- of hours developing an +app to maybe save a few seconds of your time or to make a point about using open +source software? At least it will teach me some stuff along the way. + +## What tech to use? + +But before I could start developing an app, I had to decide what to build it +with. My first two requirements: it had to be cross platform, and it had to be +able to show scheduled notifications on my phone. My first thought was to use a +PWA. PWAs are web apps that can be "installed" on your phone like a regular app, +but run entirely on your browser. It's sort of an Electron-lite. That would be +great since I already know a lot about web development, alas PWAs can't send +scheduled notifications while the app is in the background. That's a pretty +vital part of this project so that rules out PWAs. Also I think Safari has some +problems with PWAs? So that also would have ruled it out if I somehow worked +around the notifications. + +Similar to PWAs, I could have used something like Electron to develop an app +using web technologies. In this case it would be an actual app, so I could +actually run code in the background and send scheduled notifications. Hurray! +Except that I wasn't sure I wanted to do this. My experience with apps developed +this way is terrible, and it's often very obvious someone basically put a web +browser in kiosk mode. These apps are often slow, the UIs are completely devoid +of the native look and feel, and they are often full of weird browserisms like +being able to hold and select the text on the page. Maybe this perception is a form of [Survivorship bias](https://en.wikipedia.org/wiki/Survivorship_bias#In_the_military) +and there are lots of apps I used developed with these technologies that work great, +but I decided to see what else was available first. + +After more digging, I finally narrowed my choices down to 2 options: React +Native and Flutter. React Native takes the usual React, and instead of rendering the virtual DOM into a real DOM it renders it +to native UI components. React Native is something I used before, with my [Bulgur Cloud](https://bulgur-cloud.github.io) project. +While I liked React Native, I actually ended up rewriting Bulgur Cloud --in Next.js-- so I was a little hesitant. +Flutter on the other hand uses Dart, and is developed by Google with a focus on cross platform apps. +Flutter works by rendering everything to a canvas... which sort of surprised me. +My biggest concern with this was performance and accessibility, using native components +gives you both out of the box. If you render everything yourself, then it's +your responsibility to handle accessibility and optimize rendering. +Articles and discussions I came across online reassure me that Flutter is "doing better" at all of these, +so hopefully it's not a problem. + +At this point I was still paralyzed by this decision, so I ended up creating a project with both to check out +the out of the box example. Which really did not help, they both work and look fine. +The code is pretty easy to understand with both. I have concerns with the future of both projects, +because React Native feels too under control of Expo and Flutter feels too under control of Google. + +I finally broke my paralysis by just going with React Native. I already know +React, I know a ton of stuff about the React ecosystem, I've already used React +Native before. Flutter and the Dart language look fine and I'm sure I could +learn them, but it's just easier for me to get this project off the ground if I +use what I already know. I also remembered that the reason why I rewrote Bulgur +Cloud was because React Native for Web is a bad experience, but in this case I +don't care about the web so it's not a problem. + +## To Expo, or not to Expo? + +When you start using React Native, the first thing you see is Expo. Look at the +official getting started guide for React Native and it immediately recommends +you use Expo. Expo then keeps coming up again and again in the docs. It's easy +to see why: + +- Expo solves a major getting started hurdle: installing Android Studio or XCode + and connecting it to your phone so you can run it. Instead, you install the + Expo Go app from your phones app store and scan a QR code to get started + immediately. +- Expo comes with a lot of built-in packages. If you go with Expo, you can use + all these packages *and* you can still use all the regular React Native + packages. +- Expo doesn't technically lock you into anything, you can "eject" from Expo at + any time. + +I decided to use Expo. While I have some concerns that Expo is an +investor-backed company and not a community effort, the Expo packages are all +open source. Expo Go is open source. And you can still install Android Studio +and XCode and build everything yourself. + +## What else? + +Expo comes with a lot out of the box, but there were some packages I wanted to +play with and some packages I knew I wanted on top of that. Some of these include: + +### Tamagui + +[Tamagui](https://tamagui.dev) is a UI kit for React Native. I first saw it +advertised as a "headless" library meaning that it implements all the +functionality but comes with no styles, so you style everything yourself. I +later found out that this was not entirely correct though because Tamagui does +come with default styles, but lets you opt out of them or customize them. + +I really like Tamagui because it comes as a complete package. It's not just UI +components but also animations, CSS shorthands and a token based design system. +It also comes with a cool "sub-theme" system that allows you to have variants of +your themes, so you don't just have a "dark" theme but you can also have +"dark-forest" and "dark-blue" and "dark-whatever" to create different themes for +different sections of you app without having to hand-code everything. + +### Expo-Sqlite + +[Expo-sqlite](https://docs.expo.dev/versions/latest/sdk/sqlite/) is an expo package, but it's an optional one. +It gives you Sqlite. That's about all. Sqlite is awesome, so why not. +There are some other options for storage, some even support additional features like encryption +if that's something you need. But I don't think it's crucial if I encrypt +my sourdough starter data, so I'd rather take the Sqlite features. + +### nearform/sql + +[@nearform/sql](https://github.com/nearform/sql) is a library for SQL injection +prevention. What's cool about it is that you get to write SQL queries with the +javascript string interpolation without risking SQL injection. So you can do: + +```js +DB.query(SQL`INSERT INTO students(name) VALUES (${name})`); +``` + +without little [Bobby Tables](https://xkcd.com/327/) ruining your day. + +nearform/sql is not compatible with Expo-sqlite out of the box, but a basic +wrapper function can easily get you there. Here it is, I'd +publish it on npm but it's so short you might as well just copy and paste it. + +```ts +export function sql(strings: any, ...values: any[]): Query { + const statement = SQL(strings, ...values); + return { + sql: statement.text, + args: statement.values, + }; +} +``` + +### SWR + +[SWR](https://swr.vercel.app) describes itself as "React Hooks for Data +Fetching". My little app is local only and doesn't need to fetch data from +anywhere, so why SWR? Well, SWR is great whenever you need to get data from +anywhere outside of your apps own state. In my case, I need to get data out of +SQLite and into my app, so I use SWR to fetch the data from the database. + +The main use case for me is the caching and deduplication. SWR caches results +and won't fetch again if the same hook is called multiple times, so you can use +your hooks everywhere without having to worry about the same data being fetched +multiple times for no reason. You can also invalidate the cache whenever you +want, which will invalidate all users of the hook and fetch the data just once +to update everything. + +You need some workarounds to get SWR working in React Native, but [official docs have you covered](https://swr.vercel.app/docs/advanced/react-native.en-US). + +### Formik + +I was hesitant and I dragged my feet the very first time I encountered +[Formik](https://formik.org), but after trying it once I actually fell in love +with it. It really does everything you need a form to do. The best part to me is +that you get to avoid having a million `useState`s in your form, and thanks to +the Formik context you can organize your code without drilling values and +setters down into components. + +You have to do a bit of work for Formik to work in React Native, but the [official guide tells you what to do](https://formik.org/docs/guides/react-native) +so it's an easy change. Wrap that in a custom form input component and you can forget +the incompatibility exists at all. + +## Some More Packages + +This is getting really long (for my usual posts), so a few more quick mentions: + +- `date-fns` is the definitive date & time library. It's incredible. +- `radash` is like lodash. I'm honestly not fully sure if it's better or worse, but I do keep coming back to it. +- `rrule` makes calculating recurring dates easy. You can serialize and deserialize your rrule's which I also appreciate. +- `ulidx` is a random ID generator. It's like nanoid, but at the cost of just a few more characters they are ordered by creation date. +- `zod` is my favorite schema tool. Never leave home without it. + +## Fin + +I'm about done with the basic functionality I wanted for this app, so I'm hoping +to have a version of this up on the Google Play store by the end of the week. + +Oh and I still haven't made that sourdough starter,