Tom Insam

Data Models in iPhone apps

[This is a lightly-edited flow-of-consciousness thing taken from a slack conversation]

Is it worth trying to write complicated Codable implementations in Swift to map your network model to the local business model you prefer? It’s a lot of complicated code, but maybe having a single representation of your data is worth the trade-off.

I hate doing it, but no. I always end up with a network model and a database model and a “used in the app” model and mapping methods between them.

I hate it because it’s irritating, because the models are always almost the same as each other and it grates maintaining the conversions which are always boring 40 line functions of self.foo = other foo over and over. (At least now we have swift you don’t get weird bugs where some of your mappings forget to instantiate all the properties.) It feels like it should be possible to build a magical perfect object that you can decode from the wire and then put directly into the database, then pull it out and power the UI from it.

But the Codable example is an excellent demonstration of why you can’t really do that. Your wire protocol isn’t quite what you want, so to have a wire object that’s also your business object you need to write a ton of Codable conformance code. (You can’t write just a little bit - Codable auto-conformance is all or nothing.) In fact, you need to write so much code that it would be easier and more maintainable to just write a simple-as-possible wire-format Codable container and a mapping function. For all intents and purposes the Codable conformance is a wire format object, you’re just writing it in an inconvenient syntax.

Your database representation needs to be much flatter than the business object - your model is a deep structure but you don’t want 300 tables and 600 joins so you need to flatten out the deep object to a single table - you’re doing the same thing with custom SQL statements to serialize and un-serialize your rich object, whereas a flat object and a mapping could write to the table without custom code, and would be easier to read.

And that’s even before getting to things like “it would be super convenient if my view data models were immutable, so I can use swift UI / redux” but core data models are not only mutable, but some other thread can mutate them for you with no indication that things changed unless you’re explicitly observing for that sort of thing.

More complication - there are actually 2 (sometimes 3) network representations, because you sometimes need to send objects back to the server. The create call (normally) won’t have, say, an object ID or a created date, but those properties are non-optional on your network model for incoming objects, so your create call object is different from the get call. And your update call probably wants everything to be optional so you can update only one property at once.

So no, your life will be easier if you just write multiple specialist representations of your objects for different contexts, keep them all as simple as possible, and write mappings between them.