12.12 — Take-Home Assignment Strategy
Opening scenario
You get the prompt: “Build an iOS app that consumes the Hacker News API, shows the top 30 stories, supports detail view + comments. Should take 4–6 hours.” It’s 6 PM on a Friday. The deadline is Monday morning. What do you do in the next 10 hours of work that turns a passing submission into a standout one?
What companies actually evaluate
Hint: not feature completeness.
| What you think they care about | What they actually care about |
|---|---|
| Pixel-perfect UI | Architecture (is the code readable?) |
| All features implemented | Tests + meaningful coverage |
| Fancy animations | Error handling + edge cases |
| Best-of-breed third-party libs | Justified library choices, not kitchen-sink |
| Clever Swift tricks | Idiomatic Swift, readable to a junior |
If you ship 70 % of features with a thoughtful architecture, tests, and a clear README, you beat the candidate who shipped 100 % with a 800-line View Controller.
The 30/60/90 rule
If the prompt says “4–6 hours,” treat it as a time-boxed exercise. Don’t go to 12.
- First 30 % of time — design + skeleton. Build the architecture; stub the features.
- Next 60 % — implement features in priority order. Skip anything that doesn’t fit.
- Last 10 % — polish: README, tests pass, no warnings, build instructions verified on a fresh clone.
This forces tradeoffs that mirror real engineering. Interviewers know the prompt is bigger than the time; they want to see what you chose to skip and why.
Architecture over features
Every take-home should demonstrate:
- Layer separation: Model / Service / ViewModel / View clearly distinguishable.
- Dependency injection: ViewModels take services in
init, not via singletons. - Protocol boundaries: at least one service hidden behind a protocol with both real and test impl.
- Async correctness:
async/awaitused idiomatically; no DispatchQueue dance. - Error handling: every async path has an error state visible to the user.
Even if the prompt is small, baking these in costs maybe 30 min upfront and pays the architecture-readability dividend.
The minimum README
# Hacker News iOS
A take-home for [Company].
## Build
- Xcode 16+, iOS 17+ deployment target
- `git clone …`, open `HackerNews.xcodeproj`, build & run on simulator
- No third-party dependencies (or: SPM resolves on first build)
## What I built
- Top stories list (live API, pull-to-refresh)
- Story detail with WebView for article
- Comments tree (lazy-loaded)
- Offline cache via SwiftData
## What I deliberately skipped (given the 5-hour time box)
- Search — would add a `SearchService` + dedicated view
- User profiles — out of scope for the API question being asked
- Vote submission — requires auth, larger scope
## Architecture
MVVM with constructor-injected services. `HNService` (protocol) has a live URLSession implementation and a `MockHNService` for previews and tests. SwiftData layer for cache, kept behind a `StoryCache` protocol.
## Testing
`HNServiceTests` covers JSON decoding edge cases. `StoryListViewModelTests` covers state transitions for fetch / refresh / error paths. Run with ⌘U.
## Tradeoffs
- I used SwiftUI throughout (iOS 17 target made this clean); for iOS 15 support I'd have built equivalent UIKit screens.
- Comment tree uses a flat list with indentation rather than recursive nested lists — better scroll performance for deep threads.
- I chose not to add a third-party HTTP library; URLSession + Codable was sufficient.
## What I'd do with another day
- Persist scroll position across launches
- Add accessibility VoiceOver tests
- Add a UI test for the full happy path
- Wire crash reporting (Sentry-equivalent) for a real submission
## Time
5h 20m total: 1h design + skeleton, 3h features, 1h tests + polish, 20m README.
This README is itself the deliverable. Companies read it before they read your code.
Minimum tests required
The bar is not “high coverage.” The bar is “evidence of test discipline.”
- One service test with decode round-trip on a sample JSON.
- One view model test asserting state transitions for happy path + error path.
- One mock implementation of your main service protocol.
That’s ~50 lines of test code and signals everything. Going further (UI tests, snapshot tests) is bonus.
What gets take-homes rejected
- No README or one-line README. Auto-fail.
- Doesn’t build on fresh clone. Always test by cloning to a new folder and building before submitting.
- 800-line View Controllers with no separation.
- Singleton-everywhere —
URLSession.shared,UserDefaults.standardsprinkled through views without abstraction. - No tests at all.
- Force-unwraps in production paths.
- Warnings when building. Treat warnings as errors — fix them all.
- Includes
.xcuserdataorDerivedDatain the zip..gitignoreit. - Took 20 hours. You’re hiring yourself for a job; engineers who can’t time-box overwork themselves.
- API keys committed. Use environment /
.xcconfig/ a config file documented in README.
What makes take-homes stand out
- A “what I’d do next” section in the README — signals you know the prompt is incomplete and you have a roadmap.
- One unexpected delightful detail — pull-to-refresh haptics, a thoughtful empty state, a clever error message.
- A commit history that tells a story. Six commits each named clearly beats one giant “initial commit” with everything.
- A short demo video (Loom, 2 min) walking through the app. Optional, but huge signal.
- A
Decisions.mdlog of architecture tradeoffs you considered. - Build success on a fresh device. Test on simulator and a physical iPhone if possible.
SwiftUI vs UIKit choice
If the prompt doesn’t specify, pick based on:
- The company’s stack (research their engineering blog).
- iOS deployment target listed.
- Your strength — don’t pick the one you’re weaker in to “look modern.”
When in doubt, SwiftUI for iOS 16+ targets in 2026.
Library choices
- Networking: URLSession (no third-party needed).
- Image loading: Kingfisher or Nuke if you genuinely need caching; for a 30-image grid, neither is required.
- Architecture: avoid TCA in take-homes unless the company explicitly uses it. The boilerplate cost is too high for the budget.
- Tests: built-in XCTest. Add
swift-snapshot-testingonly if visual regression matters.
Every dependency you add is a signal — “I chose to take on this maintenance cost because…”. Justify it in the README.
Submission checklist (run before zipping)
-
Product → Clean Build Folderthen build — zero warnings, zero errors - All tests pass (⌘U)
- Fresh clone to a separate directory builds and runs first try
- README updated with accurate features list
-
.gitignoreexcludesxcuserdata,DerivedData,.DS_Store - No API keys or tokens committed
- No force-unwraps in shipping code paths
-
Bundle ID + display name are sensible (not
com.example.app) - Verified on iPhone simulator (or device) at iOS deployment target version
Common misconceptions
- “More features = better grade.” Inverted: missing key architecture pieces overrides any feature completeness.
- “Use the latest Swift tricks to impress.” Use the simplest correct code. Clever code reads as ego.
- “Spend whatever time it takes.” Going far over budget is itself a signal — it shows poor time management. Cap at 1.5× the stated estimate.
- “Skip the README, the code speaks for itself.” No code speaks for itself. The README is your chance to explain choices the code can’t.
- “Build the perfect app.” Build the demonstrably thoughtful app. Perfection isn’t the bar; judgment is.
Seasoned engineer’s take
Take-homes test what a first week of work would look like — can you scope, prioritize, architect, ship something useful, and document your reasoning? The candidate who treats it as a hackathon (“ship maximum features”) loses to the candidate who treats it as a paid contract (“ship the most valuable subset on time with quality”).
TIP: Keep a personal “take-home template” repo — your standard project structure, README template, test scaffolding. Reuse it for every take-home. Drops setup time by an hour.
WARNING: Never use AI to write the take-home wholesale and submit without disclosure. Most companies now ask in the follow-up interview about specific design choices; you’ll be unable to defend code you didn’t write. Use AI for spike research, snippets, and review — disclose its use if asked.
Interview corner
Junior: “How long should a take-home take?” The time estimated in the prompt, plus 25 % maximum. Time-box and document what you skipped.
Mid: “What’s the most important deliverable in a take-home besides the code?” The README. It explains your tradeoffs, what you skipped and why, and demonstrates engineering judgment that the code alone cannot show.
Senior: “How would you evaluate a take-home if you were the interviewer?” I’d read the README first — does it show scoping? — then check that it builds clean on a fresh machine. I’d skim the architecture for layer separation and DI. I’d run the tests and see what they cover. Only then would I read the feature code. If the candidate spent obvious extra time on polish at the expense of architecture, I’d downgrade — that’s a senior trap. If they shipped less but with clearer tradeoff thinking, I’d upgrade. The signal is judgment under constraint, not feature count.
Red-flag answer: “I always go above and beyond on take-homes and add lots of features.” This signals poor time management and inverted priorities.
Lab preview
Build your own portable take-home template this weekend: empty SwiftUI app, README template, sample test file, gitignore, and a Decisions.md stub. Reuse it for the next 5 take-homes you do.