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 PostsViewController
.
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 FeedViewController.swift
, PostViewController.swift
, CommentViewController.swift
, and 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.
I actually came to the same conclusion and it’s way easier to understand the architecture of the project files this way.
Hi Teodor,
Yes, intent gives you additional semantic meanings, while type gives you redundant info.
Nice post!
How about those models? would you place them everywhere too? and the “shared” folder will include views, models, view controllers, right?