Value of SUP (one part of it): Managed Objects
As I was finishing penning the response, I started thinking about Steve Jobs’ comments in the WWDC 1997 closing keynote about developer productivity (41:24 mark in clip):
“The way you get programmer productivity is by eliminating lines of code that you have to write. The line of code that’s the fastest to write, that doesn’t break, that doesn’t need maintenance, is the line of code that you never have to write, right? So the goal here is to eliminate 80% of the code that you have to write for your app. That’s the goal.”
That’s exactly it. SUP’s libraries and code for native apps (the Object API) is a ‘managed object’ approach to developing with on-device persistence, similar to the iOS-specific Core Data framework. Managed object approaches provide significant benefits to developers by eliminating the amount of code they have to write, and eliminating points of failure. SUP’s Object API provides the client-side data management functionality, and also provides a huge set of functionality that Core Data does not:
- The ability to connect to an external data source and authenticate
- The ability to handle (queue) operations on the database when offline
- The ability reconcile with the external data source when the device reconnects. This means processing the format of the result set and writing to the database/exposing to an object ‘under the hood’. Similarly, it means updating the client database without wiping out pending operations.
These features: connectivity/authentication, update handling, and queuing are all API features provided by SUP for which a developer could write code, but it would be long, complex, and difficult to maintain.
To understand just how important a managed object API is, I’ve compared the development processes for a purely client-side app that uses raw SQLite, Core Data, and the SUP Object API. See how the two managed object approaches are quicker to develop and much less likely to be buggy or to break:
Your development process is as follows:
For raw SQLite:
- Write the SQL to create the data structure
- Create NSObject classes for each of your objects. These map to the tables you’ve created in the SQLite db.
- Write the query methods for each of your queries that will be needed by the application. if you’re pretty good, these could be generic (taking the object class types and set of clauses. as parameters), or specific:
-(Customer *)getAllCustomersInRegion:(Region *)region ofGender:(NSString *)gender age:(NSNumber *)age ...
- You need to then write the handles for the database results to pass them to the NSObject. This means if you have 20 attributes (columns) in your table, you’ll be writing a 20-line block of code to accept each item in the result array, assign it a type, and map it to an attribute in the NSObject. This is a freaking pain, because each attribute is name-specific, and possibly type-specific. So you can be clever and create a static array of the attribute names for each NSObject, and then iterate through them for this. But that array is another ordered thing to maintain. The difficulty of maintaining these queries is directly proportional to size and specificity.
For Core Data:
- Use the Core Data modeling tool in xCode to create the data structure
- Generate the NSManagedObject classes for each of your objects. These map to the model.
- Use the Core Data framework (including the FetchedResultsController) as your structure for processing SQL statements. You can use Key Value Coding, which is another thing to learn, but is pretty useful once mastered. You will still need to construct the SQL statements to input to the FRC. Fortunately, you can map result sets directly to the managed objects, so that eliminates all the garbage of maintenance described above.
For SUP Object API:
- Use the Eclipse modeling tool to create the data structure
- Generate the MBO classes for each of your objects. these map to the model. the database is generated at initial runtime ‘under the hood’.
- Use the generated methods for returning results from the database. Results are automatically mapped to managed objects.
So, as you can see: SUP Object API and Core Data are both ‘managed object’ approaches to persisting and working with data on the device (for iOS). They both require learning to use the API for accessing results, but the benefit in terms of unbreakable code and reducing maintenance is huge.
Where SUP Object API extends that benefit is by also managing the code for connecting to an external data source, authenticating, and updating the databases on both the back-end and on the device.
Really quick, think about the mess of attributes and mapping I described in the ‘raw SQLite’ approach above.
Now, think about the code that you’ll have to write in order to make a connection to your data source, authenticate, submit any create/update/delete operations you’ve stored since the last time you connected to the network (you should also create a flag in your tables to create keep track of that…), then retrieve the current values from the data source.
How will you deal with the results? Will you write a block of code to check whether each result is an update or not? Will you just over-write the existing data? What if the user was working while that happened? What if the results for every user are 5MB, and most don’t have WiFi?
It’s doable. It’s an absolute nightmare to maintain, and SUP provides a huge benefit by handling it all for you.