Why use descriptive names in our code?
private struct LaunchPayload: Decodable {
let id: Int
let name: String
let missions: [MissionPayload]
let estimatedDate: DatePayload
let provider: NamedPayload?
let vehicle: NamedPayload?
let pad: PadPayload?
let t0: String?
let sortDate: String?
let slug: String?
let dateLabel: String?
let missionDescription: String?
enum CodingKeys: String, CodingKey {
case id, name, missions, provider, vehicle, pad, t0, slug
case sortDate = "sort_date"
case dateLabel = "date_str"
case missionDescription = "mission_description"
case estimatedDate = "est_date"
}
}This is the response type used by Next Rocket Launch to read launch data from RocketLaunch.Live. Before we inspect a single function, names such as estimatedDate, missionDescription and provider already tell us what information arrives. The CodingKeys keep those readable Swift names connected to the service’s actual JSON keys.
Good naming is not decoration. It lets a developer distinguish information that looks similar but has a different meaning. In this app, confusing an approximate launch date with an exact launch time could produce a misleading countdown.
1. The approach
struct LaunchDetails: Equatable, Sendable, Codable {
let provider: String?
let vehicle: String?
let country: String?
let site: String?
let plannedTime: Date?
let sortTime: Date?
let estimatedDateLabel: String?
let missionDescription: String?
let watchURL: URL?
let detailsURL: URL?
init(provider: String? = nil, vehicle: String? = nil, country: String? = nil,
site: String? = nil, plannedTime: Date? = nil, sortTime: Date? = nil, estimatedDateLabel: String? = nil,
missionDescription: String? = nil, watchURL: URL? = nil, detailsURL: URL? = nil) {
self.provider = provider; self.vehicle = vehicle; self.country = country; self.site = site
self.sortTime = sortTime
self.plannedTime = plannedTime; self.estimatedDateLabel = estimatedDateLabel
self.missionDescription = missionDescription
self.watchURL = watchURL; self.detailsURL = detailsURL
}
}After decoding, the app works with this domain value. Notice the separate plannedTime, sortTime and estimatedDateLabel properties. The first can supply a scheduled time, the second can order records, and the third can preserve a description such as “December”. Those are different jobs, even when two values happen to refer to the same day.
Read the optional types too. Date? means the app can lack that information. A clear name and an honest type work together: they tell the next developer what the value represents and whether it is available. Naming everything date would hide both the distinction between the dates and the decision the caller must make.
2. The problem it solves
struct EstimatedLaunchDate: Equatable, Sendable, Codable {
let month: Int?
let day: Int?
let year: Int?
}A launch provider may know the month and year before it announces the day. This complete type preserves that situation. It does not turn an absent day into day one, or an unknown time into midnight.
Now imagine someone tidying this code and replacing the three optional components with one nonoptional Date. The declaration becomes shorter, but the app loses a fact: how precise the provider’s information actually is. The problem is not merely an unattractive variable name. It is making different meanings indistinguishable, then asking every caller to guess.
The older payload still contains the provider-specific name t0. That is a useful reminder that real source is not automatically ideal source. If we rename it to plannedLaunchTimeText, the JSON mapping must still read "t0". A Swift-only rename must not silently change the external contract.
3. Why it works
static func decodeResponse(_ data: Data) throws -> [RocketLaunch] {
try JSONDecoder().decode(Response.self, from: data).result.map { payload in
RocketLaunch(id: payload.id, name: payload.name,
missions: payload.missions.map { LaunchMission(name: $0.name, description: $0.description) },
estimatedDate: EstimatedLaunchDate(month: payload.estimatedDate.month,
day: payload.estimatedDate.day,
year: payload.estimatedDate.year),
details: LaunchDetails(provider: payload.provider?.name, vehicle: payload.vehicle?.name,
country: payload.pad?.location?.country, site: payload.pad?.location?.name,
plannedTime: try payload.t0.map(Self.parseLaunchTime),
sortTime: payload.sortDate.flatMap(Double.init).map { Date(timeIntervalSince1970: $0) },
estimatedDateLabel: payload.dateLabel, missionDescription: payload.missionDescription,
detailsURL: payload.slug.flatMap { launchWebURL("https://www.rocketlaunch.live/launch/" + $0) }))
}
}Follow the conversion rather than treating this as an unexplained block. The decoder reads a payload. Its mission descriptions become domain missions. Its optional t0 becomes details.plannedTime only when present and successfully parsed. Its sort_date string takes a different route to sortTime. The names expose where those meanings diverge.
CFA’s documented rationale: readable domain language helps people follow ownership and behaviour without reconstructing it from generic names. Swift’s custom coding keys let us improve internal names while preserving the data format. Renaming stored or transmitted fields still requires checking their encoding, not just changing references in Xcode.
The mapping shown here is compact. Splitting it into named intermediate values could make it easier to read; adding a separate wrapper type for each expression would not necessarily help. The question is whether a reader can trace each input to its meaning.
4. Advantages of using it
func testUnknownTimeRemainsAnEstimateWithoutInventingMidnight() throws {
let launch = try LaunchFixtures.launches()[2]
XCTAssertNil(launch.details.plannedTime)
XCTAssertEqual(launch.details.estimatedDateLabel, "Dec 08")
}This test states the benefit in product terms: a launch with no precise time retains its estimate. We can inspect the assertion without learning the screen layout or downloading a live schedule. A naming change that accidentally invented a time would break this expectation.
Editorial trade-off: longer names cost some horizontal space. That is usually worthwhile when they distinguish units, precision or ownership; it is not a reason to expand every familiar local variable. Prefer the shortest name that preserves the meaning a caller needs.
When reviewing your own app, start with two values that are easy to confuse. Name what each contains, follow their callers, and check persistence or network keys before renaming. The result should make the program easier to understand without changing what it tells the person using it.
Try this with the CFA AI Toolkit for iOS:
Using CFA for iOS, review the names in this code and preserve its external data contracts.
Scope: code from the linked app revisions; smaller excerpts belong to their containing types and targets. The articles distinguish older implementations from current CFA conventions. Source verification is not a full app build or device test. Suggested checks are guidance, not claims they ran against your application.