Refactoring for a better state of mind
As a part-time/hobbyist coder I have probably been Apple’s target programmer: keen, full of energy but in serious need of help if I’m going to actually achieve anything.
It’s no secret that Apple advocates a variant on Model-View-Controller app design, but thankfully they don’t market it like that; they just give you all the tools you need, and the templates, and the auto-complete to let you build your first app within a single file, a UIViewController to be specific. It is possible to do wonderful things without ever leaving that file, but if you do venture out into another scene that’s fine, just put another UIViewController on the StoryBoard, create a segue and off you go.
Now you have a rich app with things to do, and just two files to worry about. The simplicity is beguiling and it means anyone can make an app and sell it on the App Store.
But then I started making apps with 4 views, then 5, 6. Then I wanted to make it look different on iPad. And what about orientation. Oh, and of course I want everything to be connected and flow. I was starting to seriously lose control and wonder what MVC even meant, since I only seemed to have ViewControllers aplenty, but luckily a podcast came to help me and show me another route.
Swiftcoders by Garric Nahapetian: Episode 38 with Krzysztof Zabłocki
There are other, far better places (see below or that podcast) to find out about different ways to structure your programs, but I like to think of it like this: if you are an independent porgrammer, structure it how you’d structure anything else. Reflect your personality.
What about me?
I like control, I like having everything laid out neatly and I like knowing that if I put something over there, it will jolly well stay there.
What about my old app design?
I’m currently working on an app for teachers, so it’s my most complex so far needing to hold timetable, student and assignment data. I spent time planning the Core Data structure and the app flow in Graphic, then created the View Controllers in a Storyboard, gave each VC its own Swift file and set off on a journey that quickly turned into a maze, a jungle, a quagmire even. Actually, not so quickly as it took time to write the thousands of lines of code, but with each VC containing a number of variables, functions, alert controllers, table views, etc etc, they had long since lost structure and debugging was an ordeal.
What about now?
There’s more code and my VCs are not much shorter surprisingly, but there’s structure. For each ‘view’ I now have 3-4 files, so for my Student view I have: StudentVM, StudentVC, StudentVCLayout and, since it has a table, StudentVCCells. Let’s go through their roles:
StudentVM: This has all the variables and functions the view will need. I have a Student Entity in Core Data and this ViewModel reads that and extracts all the data into useful variables and arrays, such as to return all attendance data, fetch the correct size of photo and even query the Assignments Entity for relevant data.
StudentVC: The ViewController still does a lot but it doesn’t calculate anything. If it wants a medium size photo, it doesn’t work out the size or resize it, the VC simply calls a function in the VM, which returns the correct photo.
StudentVCLayout: To really get control, I define all the views and layout constraints in a separate file, which is actually an extension of the view controller. But with each subview having 2–5 constraints, it gets long (1500 lines here). This is also where I add actions to buttons and set initial values for labels etc.
StudentVCCells: Similar to the VCLayout file, but defining and laying out each of the cells.
To further control things, there are (hopefully) no string literals or similar in these files, everything is set using enums and structs in a separate file that stores my MyStyleColor, MyStyleFont and MyAutoLayout settings. This allows me to make global changes in one place. As an example, I have a value in MyAutoLayout for verticalPadding so that when I set a layout constraint I can use that as the constant, giving me fully parametric design. I have also just switched to using a UIImage Extension to store all my images in enums, so anywhere in the app can ask for UIImage.Icons.Class.Small to get the correctly sized image returned.
Finally, or firstly perhaps, I am using a coordinator to manage flow, keeping all these VCs distinct. When changing view, the current VC calls a delegate method telling the Coordinator that it has finished and that the user wants to go to another view. The coordinator dismisses the first view (as needed), sets up the VM for the next view and injects it, then calls the next VC.
What do I get from this?
A lot of code. Really, it doesn’t save typing in the slightest.
But, to me, it is clean, elegant code that I am genuinely proud of.
My structure is best described as MCVMVC I think:
- Model: The database
- Coordinator: Takes overall control of the flow. Primes the View Models and injects them as it calls the View Controllers
- View Model: Acts as a conduit between the Model and View Controller
- View Controller: Displays information as provided by the View Model. I use 2 or more files to separate initial layout from active logic
This method is good, but it’s not the be-all-and-end-all. It suits my mind perfectly and so I take genuine pleasure from the knowledge that my code is all neatly arranged and does what I want.
It is also understandable, readable and hopefully reusable (so maybe it will save me typing one day).
I don’t recommend this route to everyone, but I do suggest all programmers read and learn about different models, get some ideas and then approach your next project with a clear, deliberate plan that suits your natural style.