Swift: Dirty vs Clean code | Improve your coding skills

CodingRasi
6 min readJust now

--

Hi everyone,

If you read my articles but haven’t subscribed yet, I strongly suggest you do so now, because I’ll soon be sharing some amazing news that you won’t want to miss. 😉 Oh, also, if you want to learn iOS Development, I strongly suggest you to checkout my Udemy course by clicking here. You won’t regret. 🤠

And here is the special code for my Medium followers/readers: FORMEDIUM 🫠

Did you read my last 5 articles? 🤔 If not, then here they are: 👀

Ok, now let’s start with our main topic. 🧐

I always mention the importance of clean code. I remember, when I started to write in Medium, my first article was also about clean code and there I shared a lot of resources for further reading. When you write Swift code, it’s easy to fall into the trap of quick fixes and shortcuts. Especially when you’re on a deadline. But writing clean code isn’t just about making your code “look nice.” It’s about setting up your future self (and anyone else who touches the code) for success.

I believe that the best lesson is the lesson that teaches with an example, so in this article, I am going to show 10 common examples of “dirty” code and show you how to clean them up. It is all about making your code simpler, easier to read, and maintainable in the long run.

Choose clear & descriptive name

Check the following code and see if it is possible to understand at first glance, what this function does? Neither would most developers. The abbreviations ‘u’ and ‘p’ are too vague.

Dirty code

func c(u: String, p: String) -> Bool {
return u == "adming" && p == "password"
}

Clean code

func checkCredentials(username: String, password: String) -> Bool {
return username == "admin" && password == "password"
}

By giving the function a name that actually describes what it does (‘checkCredentials’) and using ‘username’ and ‘password’ instead of ‘u’ and ‘p’, it’s immediately clear what this function does.

Use Guard Statements to Avoid Nested Conditions

In the following dirty code, you will see nested conditions. And they are making our code harder to follow. In addition, the force unwrap in the following code (‘age!’) is risky if ‘age’ returns ‘nil’ value.

Dirty code

func validateAge(age: Int?) {
if age != nil {
if age! >= 18 {
print("Eligible")
} else {
print("Not eligible")
}
}
}

Now let’s see how to clean it.

Clean code

func validateAge(age: Int?) {
guard let age = age, age >= 18 else {
print("Not eligible")
return
}
print("Eligible")
}

Using a ‘guard’ statement lets you handle the “not eligible” case early, so the code reads like a conversation: if ‘age’ isn’t ‘nil’ and is 18 or older, we say “Eligible.”

Don’t Use Magic Numbers

Magic numbers are numbers thrown into your code without any explanation. In the following dirty code example, the ‘3.14159’ is dropped in without contextx. Anyone reading this code might be able to guess it’s supposed to be pi, but why make them guess?

Dirty code

func calculateArea(radius: Double) -> Double {
return radius * radius * 3.14159
}

Clean code

let pi = 3.14159

func calculateArea(radius: Double) -> Double {
return radius * radius * pi
}

Defining ‘pi’ as a constant gives us clarity, and if we need to change it, we only do it in one place. Simple and easy.

Avoid Force Unwrapping Optionals

Force unwrapping (‘!’) is tempting, but risky. It will crash your app if ‘userAge’ is returning ‘nil’, and we are never safe from it unless we unwrap properly. Check following dirty code and opposite.

Dirty code

let userAge: Int? = 25
let age = userAge!

Clean code

let userAge: Int? = 25

if let age = userAge {
print("User age is \(age)")
}

Using ‘if let’ lets us safely unwrap ‘userAge’. No crashes, just clean and stable code.

Drop Redundant Comments

In the following example, the comment adds literally no value. It is just repeating what the code already tells us. Comments are great when you need to explain why something’s done, but not to restate the obvious.

Dirty code

// This function calculates the square of a number
func square(number: Int) -> Int {
return number * number
}

Clean code

func square(number: Int) -> Int {
return number * number
}

In this example, the code is self-explanatory, so we don’t need a comment. Less clutter, more clarity.

Give Enums Clear Names

If you have ever seen cryptic enum cases like ‘s1’, ‘s2’, and ‘s3’, you know they don’t help anyone to understand the code’s purpose. Let me explain it in a better way with an example.

Dirty code

enum Status {
case s1
case s2
case s3
}

Ok, now let me show how to clear this dirt.

Clean code

enum Status {
case success
case failure
case pending
}

By renaming them to ‘success’, ‘failure’, and ‘pending’, anyone reading your code knows what to expect.

Stick to the DRY Principle (Don’t Repeat Yourself)

You probably know about the DRY principle. If you don’t know, check my old articles, I have written about this topic in detail. Let me now show you with an example.

Dirty code

func calculateCircleArea(radius: Double) -> Double {
return radius * radius * 3.14159
}

func calculateCircleCircumference(radius: Double) -> Double {
return 2 * radius * 3.14159
}

Using ‘3.14159’ in two functions like this violates the DRY principle, which states that code should never repeat unnecessarily.

Clean code

let pi = 3.14159

func calculateCircleArea(radius: Double) -> Double {
return radius * radius * pi
}

func calculateCircleCircumference(radius: Double) -> Double {
return 2 * radius * pi
}

Now, if ‘pi’ ever changes, we only update it once, and it’s applied everywhere.

Simplify Boolean Expressions

In the next example, writing ‘loggedIn == true’ is redundant because loggedIn is already a Boolean.

Dirty code

func isUserLoggedIn(loggedIn: Bool) -> String {
if loggedIn == true {
return "User is logged in"
} else {
return "User is not logged in"
}
}

Clean code

func isUserLoggedIn(loggedIn: Bool) -> String {
return loggedIn ? "User is logged in" : "User is not logged in"
}

As you can see, instead of using unnecessary if-else statement, we used ternary operator which simplifies the code, making it concise and easy to read.

Reuse Code with Functions

If you need to print user information from multiple places, it is easy to copy-paste this, but that leads to duplication. Let me show you what I mean with two examples.

Dirty code

func processUser(user: User) {
print("Name: \(user.name)")
print("Age: \(user.age)")
print("Email: \(user.email)")
}

Clean code

func printUserInfo(user: User) {
print("Name: \(user.name)")
print("Age: \(user.age)")
print("Email: \(user.email)")
}

func processUser(user: User) {
printUserInfo(user: user)
}

By using a separate function, we avoid duplication and make the code modular.

Use Guard Statements for Early Returns

I have already talked the importance of guard statements. Let me explain it a bit more. Check the following dirty code.

Dirty code

func checkPassword(password: String?) {
if password != nil {
if password!.count >= 8 {
print("Password is strong")
}
}
}

Nested conditions like this create hard-to-read code.

Clean code

func checkPassword(password: String?) {
guard let password = password, password.count >= 8 else {
print("Password is weak")
return
}
print("Password is strong")
}

By handling the “weak password” case up front with a guard, we make the “strong password” logic clearer.

Oh you want to thank me: You have couple of options: clap, comment, share, follow or buy me a coffee. 🙂

Learn iOS Development — Udemy Course

Subscribe to my Youtube channel

Follow me on X

Be Patreon

--

--

CodingRasi

I speak 6 human and 5 programming languages. 🥳  iOS Developer. To support me: https://codingrasi.com