Posts from December 2022

Dev Log #2

Edited and updated 30th January 2023

During the holidays, I’ve been studying other codebases to understand how to write better code. In particular, Apple’s CareKit framework has been largely beneficial in knowing how to structure my Core Data models better. A lot of tutorials mix views and models together for simplicity, but this can quickly become unwieldy as the codebase becomes more complex.

The CareKit code is interesting because all the transactions, such as insert, update, delete, were funnelled through the aptly named transaction() method. Core Data classes are prefixed with ‘CD’ and structs are passed around instead. I liked this approach because it created several layers of abstraction between the actual database and the user (something I’ve learned from using Elixir’s Phoenix framework). It also heavily utilised closures which enabled async. However, while it was straightforward to add new data, it was challenging to update and delete objects. This is because structs are value types, so new instances are created while classes, being reference types enabled direct manipulation of the objects. It made sense for the CareKit framework because data was ‘soft-deleted’ (the DeletedDate of the object was switched from nil to the date of deletion) and updates were essentially inserts with a pointer to the most current version. This may be ideal if you want to maintain a version history of the writes, but it was overkill for a CRUD app.

I initially found a compromise where I would create a new struct, compare it to an existing UUID in the database and then rewrite all the properties of that existing object. However, this was unwieldy because it felt awkward to write the update logic. I also felt that this was against the principles of Core Data, so I thought there could be a better solution.

This article enlightened me. I really enjoyed writing a closure for creating new classes. It felt so fresh compared to the usual var object = <Core Data Class>(context:) dance. However, I found the extra code at the end felt awkward too. Speaking metaphorically, writing the .sink and .receive methods felt like I was waddling with toilet paper trailing from my bum. There had to be something better.

I’m really happy with the solution I conceived. It uses the best of both worlds. I can still write my closures and I can still check if the operation completed successfully. This is the final code I came up with:

class Storage<Entity: NSManagedObject> {
    private let context = StorageProvider.shared.container.viewContext

    func add(_ body: @escaping (inout Entity) -> Void, completion: @escaping (Result<Entity, StorageError>) -> Void) {
        context.perform {
            var entity = Entity(context: self.context)
            body(&entity)
            do {
                try self.context.save()
                completion(.success(entity))
            } catch {
                completion(.failure(.invalidValue(reason: error.localizedDescription)))
            }
        }
    }

    func update(_ entity: Entity, _ completion: @escaping (Result<Entity, StorageError>) -> Void) {
        context.perform {
            do {
                try self.context.save()
                completion(.success(entity))
            } catch {
                completion(.failure(.deleteFailed(reason: error.localizedDescription)))
            }
        }
    }

    func delete(_ entity: Entity, _ completion: @escaping (Result<Void, StorageError>) -> Void) {
        context.perform {
            do {
                self.context.delete(entity)
                try self.context.save()
                completion(.success(()))
            } catch {
                completion(.failure(.deleteFailed(reason: error.localizedDescription)))
            }
        }
    }
}
post

Dev Log #1

Any app worth its salt starts off with a bunch of boxes and arrows drawn on a napkin. XXX is no different.

XXX is a book tracker and organiser. I love reading, but part of the motivation is the tracking feature in Good Reads. But its interface is clunky (I’m never going to download the Good Reads app) and I don’t want to log into a website every time I finish reading. Also, I’ve been reading a lot of technical books, and I forget to add them to my library. So wouldn’t it naturally be better if I could track my reading progress locally on my phone?

That was the motivation. Now we try to translate idea into something more tangible.

Insert Screenshots

Books have four statuses: Currently Reading, Want to Read, Read and Closed (the latter is in case the user decided to drop a book without deleting it completely). The user should also be able to organise books into different folders.

Book reading is organised by reading sessions. It’s like workouts but for book reading. A timer will start and there is a little scratchpad for taking notes.

post

Launching the Dev Log Miniseries

This blog has been lying pretty dormant since its inception. The reason is simple: I was busy.

I nicely wrapped my exams, and then I started a Christmas casual job. I’ve been moving, but it doesn’t mean I haven’t been thinking. I just haven’t had the time to record it.

For the longest time, I’ve been inspired to create an app. I thought I had the technical expertise to execute this year, so I took a risk and tried to build it. It was a valiant effort, but it was eating up my study time. But since the school year is over, I’ve been sharpening my software skills for another stab at it in 2023.

However, I’ve been inspired by an article, The Simplest App that Makes Money, and I’ve decided to launch an app before school starts. Just a proof of concept idea. Also to prove to myself that I’m capable of shipping (glacial-self-62998 was proof that I could ship a website, but I’ve never shipped an app before! On the App Store of all places!)

I’ve dusted off an experimental side project and have decided to use that as my practice app. Though I’m supposed to make the simplest app, my pride will not make it that easy. There are enough interesting ideas and concepts that will keep me on my toes.

Any spare time available in the past week has been spent on the app, and I think I’m at a stage where I can start developing it in public.

So without further ado, I proudly announce the Dev Log Miniseries.

post