Swift Namespaces and the Science of Code Organization
There’s something satisfying about well-organized code. Ok, maybe not everyone finds it that satisfying - especially now, when you can just let AI manage all this chaos. But… there are still those of us for whom it matters. For me, definitely. And it’s not only about aesthetics (although sometimes I wonder if aesthetics might actually be the key), but about how it affects the way we think, work, and where we waste our energy.
But how do you organize code well? We have 3 basic tools at our disposal:
- namespaces
- file grouping
- file/folder naming
Seems simple and obvious, but are there any scientific foundations that would tell us exactly what to do? Not everywhere, but I managed to find a few things.
The Working Memory Bottleneck
Here’s the uncomfortable truth: your brain can only juggle about four chunks of information at once. Not seven, as Miller originally suggested in 1956 - Nelson Cowan’s 2001 1 review revised that number downward. Some studies show it might be as low as two chunks in certain conditions.
This isn’t just trivia. When you’re reading code, every unrelated concept you need to hold in mind competes for that limited space. The goal of good code organization is - reducing extraneous cognitive load so you can focus on what actually matters.
Names Matter More Than You Think
Research shows naming has measurable impact:
- 19% faster comprehension with meaningful identifiers vs. abbreviations 2
- ~14% better defect location with descriptive compound names 3
- Effect is stronger for experienced developers - expertise amplifies good naming benefits
- camelCase vs snake_case? Training dominates - use what your team uses consistently
Does Name Length Matter?
Here’s where it gets interesting. Your brain doesn’t read character-by-character - it processes words as chunks. A 15-character word like userRepository is one chunk, not fifteen separate units competing for working memory.
Research on identifier length 4 found:
- Single letters (
x,i,n) - slowest comprehension, highest cognitive load - Abbreviations (
usr,repo,mgr) - better, but still require mental expansion - Full words (
user,repository) - fastest recognition, lowest effort - Very long names (30+ chars) - diminishing returns, eye-tracking overhead
The sweet spot? 8-20 characters for most identifiers. But character count is the wrong metric - what matters is meaningful word boundaries. getUserById (11 chars) is instantly clear. gUBI (4 chars) requires translation. fetchAuthenticatedUserFromRemoteRepositoryById (45 chars) is technically descriptive but exhausting.
The practical rule: use complete words, avoid abbreviations, and if a name feels too long - that’s a signal to namespace or refactor, not abbreviate.
What Else Do We Know
Some findings are well-established:
- Developers spend 10:1 time reading versus writing code
- 58% of developer time goes to program comprehension
- Context switching hurts: developers switch tasks 13.3 times per hour on average, spending only 6.2 minutes per task
- Autocomplete’s primary benefit is information access, not typing reduction - equivalent to 7+ years of programming experience in one study
That last point deserves attention. When you organize code so autocomplete can surface relevant options, you’re not saving keystrokes. You’re providing information scent for exploration.
Armed with these facts, let’s see what we can actually do with them.
Swift’s Namespace Pattern
An obvious mechanism for creating namespaces is SPM - each module is a separate namespace. But we don’t always have that option, and Swift itself lacks a dedicated namespace keyword. However, we have an elegant workaround: caseless enums. Apple does this officially in many places of their own frameworks. Here’s what it looks like in practice:
enum API {
enum Endpoints {
static let users = "/api/users"
static let posts = "/api/posts"
}
enum Headers {
static let authorization = "Authorization"
static let contentType = "Content-Type"
}
}
Why enums instead of structs? Because caseless enums cannot be instantiated. With a struct, you’d need a private init() workaround.
The practical benefit: type API. and Xcode’s autocomplete surfaces everything grouped under that namespace. Information at your fingertips. If you can’t use physical modules, this trick enables elegant code grouping:
enum MyAmazingFeature {
// Models
struct User { let id: UUID, name: String }
struct Stats { let views: Int, streak: Int }
// Views
struct DashboardView: View { ... }
struct StatsCard: View { ... }
// ViewModel - if you still need ViewModels
@Observable final class DashboardViewModel { ... }
// Domain / Business Logic
enum Domain { // extra nesting level - just for illustration
struct FetchUserUseCase { ... }
struct UpdateStatsUseCase { ... }
protocol Repository { ... }
}
// Config
enum Config {
static let maxItems = 50
static let refreshInterval: TimeInterval = 30
}
}
// Usage - clean and discoverable
let vm = MyAmazingFeature.ViewModel()
let limit = MyAmazingFeature.Config.maxItems
Types inside the namespace can reference each other directly - no feature prefix needed. This simplifies the code and reduces cognitive load:
enum MyAmazingFeature {
struct DashboardView: View {
let user: User // not MyAmazingFeature.User
var body: some View {
StatsCard(user.name)
.refreshInterval(Config.refreshInterval) // direct access
// it is just a silly example
}
}
}
I probably don’t need to mention that in a large codebase without physical module separation, namespaces feel like a blessing: no more name conflicts, dependencies between features become explicit, and the structure actually communicates intent.
The Nesting Trap
But here’s where you can shoot yourself in the foot. Too many nesting levels or an absurdly long namespace name will backfire - you’ll end up increasing cognitive load instead of reducing it. Remember those 4 chunks? Each nesting level consumes one.
// Don't do this
enum MyMegaHyperBombasticAmazingFeature {}
// Or this
enum Feature {
enum SubFlow {
enum SubSubFlow {
struct SubSubView: View { ... }
}
}
}
extension Feature.SubFlow.SubSubFlow.SubSubView {
// if you still in love with ViewModels
@Observable final class ViewModel { ... }
}
The example above should give you a sense of what to avoid. 1-2 nesting levels is the sweet spot - enough structure to organize, not enough to obscure.
Filename Conventions - The Forgotten Layer
There’s another layer of organization that often gets overlooked: how you name your files. Should you use prefixes? Suffixes? Group by type or by feature in the name itself?
The research on identifier naming applies here too, but with a twist. Studies on ambiguous words (homonyms) show that readers experience slower comprehension when they encounter words with multiple possible meanings - the brain activates various interpretations simultaneously. A file named Manager.swift could be anything. UserSessionManager.swift tells you exactly what you’re dealing with.
The Gestalt principle of similarity suggests that files with common prefixes are perceived as related. When you see Auth_LoginView.swift, Auth_PasswordReset.swift, Auth_Session.swift (underscore or dot doesn’t matter) - your brain groups them automatically before you even read the full names. This is the same chunking mechanism at work. Abbreviations can work here too, as long as the folder context gives them meaning.
One study on file naming patterns found that people with documented naming conventions could find files 3x faster six months later compared to those making up names on the fly. That’s not a small improvement - that’s the difference between flow state and frustration.
Prefixes also play nicely with Xcode navigation. Type Auth_ in Project Navigator filter field or Open Quickly popup and see all related files. Same principle as namespaces - you’re creating information scent that guides exploration.
But just like with namespaces, there’s a danger of going overboard.
The Long Filename Trap
Here’s the practical problem: MyAmazingFeature_UserDashboardViewModel.swift might be descriptive, but good luck reading it in Xcode’s navigator. Long filenames get mid-truncated, and you end up seeing MyAmazingFea...oardViewModel for half your files - defeating the whole purpose.
And there’s another Xcode quirk: it doesn’t handle files with identical names well, even in different folders5. So you end up adding prefixes anyway. In this case, abbreviations might actually help - keeping names from getting even longer.
When abbreviations make sense? When your namespace already provides context. MAF.UserDashboard is clear if everyone knows MAF means MyAmazingFeature. The namespace carries the semantic weight; the type name can stay concise.
The Feature vs. Type Organization Gap
This surprised me: despite widespread expert advocacy for feature-based folder organization (Login/, Settings/, Profile/) over type-based organization (ViewModels/, Views/, Services/), no controlled empirical study directly compares them.
Robert C. Martin’s “Screaming Architecture” 6 argues your folder structure should communicate what the system does. Jimmy Bogard’s Vertical Slice Architecture 7 advocates grouping all concerns for a feature together. The theoretical support is strong - feature-based aligns with functional cohesion, the highest quality form.
But the direct evidence? Missing. We’re operating on expert consensus and theoretical frameworks, not measured outcomes.
Still, even without direct studies, it’s safe to assume that code related to a feature should stay close together. Jumping between folders to find what you need isn’t practical - and in the long run, it’s exhausting.
A small bonus tip: folder-based organization (which Apple finally gave us - Android had this for years) means files are sorted alphabetically. You can’t manually reorder them. A workaround? Add a prefix like • (alt+8) - files and folders with this character land at the very top of the sort order.
And that’s probably it for today. I hope you found something useful here.
Until next time, Bart 🤗
Practical Takeaways
The science:
- Your brain handles ~4 chunks at once - don’t waste them on noise
- Descriptive names = 14-19% faster comprehension
- Documented conventions = 3x faster file retrieval
The practice:
- Use caseless enums for namespacing - Apple’s own pattern
- Keep 1-2 nesting levels - enough to organize, not enough to obscure
- Prefer namespaces over long filenames - short files, full context in code
- Design for autocomplete - type
Namespace.and discover what’s available
The honest bit:
- Feature vs. type folder organization? No empirical winner yet
- Stay curious, measure what you can, be skeptical of strong claims ;-)
References
-
Cowan, N. (2001). The magical number 4 in short-term memory: A reconsideration of mental storage capacity. Behavioral and Brain Sciences. ↩
-
Hofmeister, J., Siegmund, J., & Holt, D. (2017). Shorter identifier names take longer to comprehend. IEEE SANER. ↩
-
Scanniello, G. et al. (2014). The effect of identifier naming on source code comprehension. IEEE ICPC. ↩
-
Binkley, D. et al. (2013). The impact of identifier style on effort and comprehension. Empirical Software Engineering. ↩
-
A minor inconvenience of organizing code via folders instead of Xcode groups. ↩
-
Martin, R. C. (2017). Clean Architecture. Prentice Hall. ↩
-
Bogard, J. (2018). Vertical Slice Architecture. NDC Conference. ↩