All of us have certainly seen source code files being organized by types. There’s a group named View Controllers, a group named Models, a group named Views, and so on. But organizing by types like this may not be a sound strategy.
Such code organization doesn’t provide any useful context about why you group some files together, while keeping others separate.
It is also redundant.
PostsViewController.swift already tells you it’s a view controller.
PostView.swift already tells you it’s a view. Putting a view controller file inside a View Controllers group, and a view file inside a Views group isn’t going to help you learn anything new. It feels so redundant just by reading it. Isn’t it?
It doesn’t scale well. When your app is in its infancy with just 5 view controllers, it’s manageable. But when it grows to have 35 view controllers, you’ll have 35 files listed under the View Controllers group.
As programmers, we know vertical screen real estate is at a premium. And most of us are allergic to scrolling. Constant expanding and collapsing groups is just not very productive.
The same goes with your test files. All your test files are already under the top most Test target group. There’s no need to have a Tests folder again.
PostsViewControllerTests.swift already tells you it’s a test file written to test the
I would even go further to say organizing by types hurts productivity. Think about it. When you’re working on
PostsViewController.swift, what happens if you want to pull up
PostView.swift to see its structure? You would need to expand the Views folder!?
I know there’s quick open, but that’s not the point here. When you aren’t yet familiar with a code base, quick open isn’t going to help you. In the same way Spotlight doesn’t remove the need for Finder.
Often, browsing a group gives you the additional context you need to build a mental picture of where you’re at.
If organizing by types doesn’t provide any real value, what should we do instead?
Organizing source code files by intent
Most iOS apps aren’t one-screen apps. The user frequently navigates from one screen to another to accomplish a task. For example, an user looks at the posts feed (
FeedViewController.swift), taps on a post (
PostViewController.swift), taps the comment button, enters some text (
CommentViewController.swift), and taps the post button.
This series of view controllers (or scenes as they call them in storyboard terminology) combine to constitute a use case flow. It makes a lot of sense to group
PostView.swift together in the same group named Posting.
When you’re working in the Posting use case, you only need to expand the Posting group and you have it all. All related files are there ready to be clicked on. There’s no unrelated file such as
SettingsViewController.swift to distract you from the task on hand.
What if my view controller is reused in multiple places?
Continuing with the social app example, you may have a profile view of an user (
ProfileViewController.swift). The same
PostViewController.swift can be reused in this use case flow. It could, arguably, be grouped under the Profile group.
But there could only be one
PostViewController.swift. And it can’t go in two places.
You can move
PostViewController.swift out of the Posting or the Profile group. Instead, put it in a top-level group named Shared.
Logically, it belongs to both the Posting flow and the Profile flow. But because it’ll get buried in one use case when you’re working on the another. It may be better to always expand this Shared group such that it’s always visible.
It’s not ideal, but at least you won’t be hunting for it in the expected group and think it’s missing. You sacrifice a bit of vertical screen real estate. You can further nest logical groups under Shared too if it’s the right thing to do.
Overall, I think organizing source code files by intent is a huge improvement over organizing by type. What do you think?
Read this post to understand why you should always check in your dependencies to the repository.