All good projects start with a good foundation. Let's take a look at what I like to do.
I typically follow the Clean Code methodology, ish. More information on clean code can be found at https://cleancoders.com/
I have a small confession, I've only read about half the book. It's on my read list, but I don't read as often as I should. I wont tell if you wont.
What is clean code
The general principal is that code should be divided into layers. You should have a domain layer that holds repositories. These repositories are responsible for fetching the data. For mobile apps this is from either a RESTful service, or a local database.
The next layer up from that is the data layer holding your services. These services are responsible for the logic surrounding and fetching from the repositories. These services typically hold more business logic around what repositories to fetch from. It's in this layer we'll take a look at if we should be looking for something from the local database, or from the REST service.
And the final layer I'll use is the UI layer. This layer is responsible for getting information from the services and responding to UI events. This is what we'll actually interact with.
What I don't take from clean code, is each layer having it's own set of models. I prefer to use the same model from the domain right up to the UI. I feel that the cost/benefit of constantly transforming objects is not worth it in my opinion. We will need to make sure we don't keep so called 'god' objects that hold everything in one spot. If the UI only needs on field out of 20, the services and repositories will need to fetch all 20 to get the one. Where we can we will make our objects as small as possible.
One thing to note while were talking about preventing god objects, is single responsibility. Each class, be it a service, repository, model, UI, or whatever bit of code, should only be responsible for one thing at a time. Repositories should not need to know about each other, and the state of each other. That's the job of the service calling the repository.
With this in mind, let's talk about how we want to set up our directory structure.
-/ | -/assets | | -[IMAGE STRUCTURE] | -/lib | | - main.dart | | -/src | | | - main_page.dart | | | -/data | | | | -/services | | | -/domain | | | | -/repositories | | | | | -/local | | | | | -/remote | | | -/models | | | -/ui | | | | -/[PAGE] | | | | | -/bloc | | | | | -/widets
This is something I've found works well for me. You can see the clean architecture I was talking about before, with more details. Under repositories I'll put each data source under it's own directory. The data directory contains services. If we start to get groups of similar services, we'll add those groups in their own directory. Next up we have our models, which will be simple dart objects, with some generated code we'll get to in a minute. Lastly is our UI directory. This is where our widget tree will live. Each page will get it's own directory. Blocs and widgets get their own directory under each page as well. This keeps things contained, but separated. The last one to talk about is the assets directory. This will include things like fonts, images, videos, or anything that's not code but still needs to be bundled with the app. I left this vague as I don't know what assets will need right now.
The last thing I want to talk about in this post, is code generation tools. I'm a huge fan of them. With minimal configuration you can have repeatable objects that are managed by something else. Here's some packages that generate code that I'll be starting off with.
Injectible is a code generation for get_it, a service locator. This will allow us to decouple all of the layers. Each layer will take in what it needs in the constructor, and Injectible/get_it will create all the objects as they're need (or at app start) and provide us with instances when we ask for them.
Freezed allows us sealed classes. Objects will be immutable, meaning no one can just change it willy-nilly on us without creating a new instance first. This will pave the way for nice equatable methods on fields rather than their location in memory.
Lastly, json_serialization is a generation for to/from json. This makes it harder to make mistakes on the serialization and destabilization of our objects. Freezed nicely integrates it at the same point, making it easy to use as well.
One thing we want to note here is that all generated classes will not be committed. They'll be placed in the .gitignore file, and the CI/CD services will be responsible for creating them on compile. This ensures everything is kept up to date.
When are you getting to the good stuff?
But let's take a preview at what we're going to build at least!
I've drawn up some simple mock ups using Sketch. Give 'er a whirl! Let me know what you think. It's basic to start, and I'll be working on it as we go. Next up will actually be some code, I promise.
If no one subscribes, is it really a blog?
If you want to stay in tune with the updates, sign up below and I'll send you emails when new posts go live! I pinky swear not to sell my email list.