what swift can teach us all
TRANSCRIPT
Let’s talk about functions!
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
var number = 4 // A boring Int
Let’s talk about functions!
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
var number = 4 // A boring Int
Let’s talk about functions!
var sum = { (a: Float, b: Float) in return a + b }
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
var number = 4 // A boring Int
Let’s talk about functions!
var sum = { (a: Float, b: Float) in return a + b }
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
// A fun...ction
var number = 4 // A boring Int
Let’s talk about functions!
var sum = { (a: Float, b: Float) in return a + b }
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
// A fun...ction
var number = 4 // A boring Int
Let’s talk about functions!
var sum = { (a: Float, b: Float) in return a + b }
let four = sum(2, 2) print(four) // Prints 4.0
Did you know that in Swift you can assign functions to variables?No, seriously…
*pun intendedfun
// A fun...ction
Higher order functions
Moment…
What’s that?
Roughly speaking…
"A higher order function is a function that accepts functions as parameters"
- Some guy.
let sum = { (a: Float, b: Float) in return a + b } let subtract = { (a: Float, b: Float) in return a - b } let multiply = { (a: Float, b: Float) in return a * b } let divide = { (a: Float, b: Float) in return a / b } func main() { let eight = operateOn(6, and: 2, usingFunction: sum) let four = operateOn(6, and: 2, usingFunction: subtract) let twelve = operateOn(6, and: 2, usingFunction: multiply) let three = operateOn(6, and: 2, usingFunction: divide) } func operateOn(a: Float, and b: Float, usingFunction f: (Float, Float) -> Float) -> Float { return f(a, b) }
let sum = { (a: Float, b: Float) in return a + b } let subtract = { (a: Float, b: Float) in return a - b } let multiply = { (a: Float, b: Float) in return a * b } let divide = { (a: Float, b: Float) in return a / b } func main() { let eight = operateOn(6, and: 2, usingFunction: sum) let four = operateOn(6, and: 2, usingFunction: subtract) let twelve = operateOn(6, and: 2, usingFunction: multiply) let three = operateOn(6, and: 2, usingFunction: divide) } func operateOn(a: Float, and b: Float, usingFunction f: (Float, Float) -> Float) -> Float { return f(a, b) }
We have defined 4 functions
as variables.
let sum = { (a: Float, b: Float) in return a + b } let subtract = { (a: Float, b: Float) in return a - b } let multiply = { (a: Float, b: Float) in return a * b } let divide = { (a: Float, b: Float) in return a / b } func main() { let eight = operateOn(6, and: 2, usingFunction: sum) let four = operateOn(6, and: 2, usingFunction: subtract) let twelve = operateOn(6, and: 2, usingFunction: multiply) let three = operateOn(6, and: 2, usingFunction: divide) } func operateOn(a: Float, and b: Float, usingFunction f: (Float, Float) -> Float) -> Float { return f(a, b) }
We have defined 4 functions
as variables.We pass in those functions in the operateOn call "as if" they were variables… (well, they
actually are)
operateOn is a higher order function, because it accepts a function as an input parameter.
let sum = { (a: Float, b: Float) in return a + b } let subtract = { (a: Float, b: Float) in return a - b } let multiply = { (a: Float, b: Float) in return a * b } let divide = { (a: Float, b: Float) in return a / b } func main() { let eight = operateOn(6, and: 2, usingFunction: sum) let four = operateOn(6, and: 2, usingFunction: subtract) let twelve = operateOn(6, and: 2, usingFunction: multiply) let three = operateOn(6, and: 2, usingFunction: divide) } func operateOn(a: Float, and b: Float, usingFunction f: (Float, Float) -> Float) -> Float { return f(a, b) }
We have defined 4 functions
as variables.We pass in those functions in the operateOn call "as if" they were variables… (well, they
actually are)
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Let’s see a more practical example…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Mutability
Let’s see a more practical example…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Mutability
Danger!
Let’s see a more practical example…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Mutability
Danger!
But… Hold on… Why?
Let’s see a more practical example…
Nope,it’s not this…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Mutability
Danger!
But… Hold on… Why?
Let’s see a more practical example…
Mutability:
By using mutable variables, we are not 100% sure what the value of the variable at some point is.
It could be modified somewhere, and that leads to the fact that we need to keep track of where that variable is being used and how it’s being modified.
In smaller cases like this, it’s easy to keep track, but…
for jsonRow in rows { var post = Post(json: jsonRow) let postId = jsonRow["id"].stringValue if let storedPost = realm.objects(Post).filter("id = %@", postId).first {
post = storedPost post!.refresh(jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = PostType(rawValue:(storedPost.postType.rawValue | feedType.rawValue)) updates.append(post!.id)
} else { post = Post(json: jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = feedType additions.append(postId)
} realm.add(post!, update: true)
}
How about this…?
for jsonRow in rows { var post = Post(json: jsonRow) let postId = jsonRow["id"].stringValue if let storedPost = realm.objects(Post).filter("id = %@", postId).first {
post = storedPost post!.refresh(jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = PostType(rawValue:(storedPost.postType.rawValue | feedType.rawValue)) updates.append(post!.id)
} else { post = Post(json: jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = feedType additions.append(postId)
} realm.add(post!, update: true)
}
How about this…?
Let’s keep track of post…
for jsonRow in rows { var post = Post(json: jsonRow) let postId = jsonRow["id"].stringValue if let storedPost = realm.objects(Post).filter("id = %@", postId).first {
post = storedPost post!.refresh(jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = PostType(rawValue:(storedPost.postType.rawValue | feedType.rawValue)) updates.append(post!.id)
} else { post = Post(json: jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = feedType additions.append(postId)
} realm.add(post!, update: true)
}
How about this…?
Let’s keep track of post…
for jsonRow in rows { var post = Post(json: jsonRow) let postId = jsonRow["id"].stringValue if let storedPost = realm.objects(Post).filter("id = %@", postId).first {
post = storedPost post!.refresh(jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = PostType(rawValue:(storedPost.postType.rawValue | feedType.rawValue)) updates.append(post!.id)
} else { post = Post(json: jsonRow, endpoint: self.basePath as! ServerEndpoint) post!.postType = feedType additions.append(postId)
} realm.add(post!, update: true)
}
How about this…?
At this point, we can’t easily ensure what the post is going to be…
Let’s keep track of post…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } } return teenagers }
Back to our example…
Could we replace it, somehow, such that we avoid mutability?
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let :)
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let 😊
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let 😊
Yes, emojis are allowed in Swift source code… ✌
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let 😊
Yes, we are tending to become hippies
Yes, emojis are allowed in Swift source code… ✌
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let 😊
Yes, we are tending to become hippies
Yes, emojis are allowed in Swift source code… ✌
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter({ (person) -> Bool in return person.age > 12 && person.age < 20 }) return teenagers }
Higher order functions to the rescue!
// let 😊
Yes, we are tending to become hippies
Yes, emojis are allowed in Swift source code… ✌
If we could just simplify this…
func teenagersFromPeople(people: [Person]) -> [Person] { let teenagers: [Person] teenagers = people.filter { $0.age > 12 && $0.age < 20 } return teenagers }
Simplicity, oh, yeah…
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
Even simpler, baby…
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } }
return teenagers }
Notpreferred
Higher order functions
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } }
return teenagers }
Notpreferred
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
Preferred
Higher order functions
func teenagersFromPeople(people: [Person]) -> [Person] { var teenagers = [Person]() for person in people { if person.age > 12 && person.age < 20 { teenagers.append(person) } }
return teenagers }
Notpreferred
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
Preferred
FILTER
Higher order functions
func idsFromPeople(people: [Person]) -> [String] { var ids = [String]() for person in people { ids.append(person.id) } return ids }
Notpreferred
Higher order functions
func idsFromPeople(people: [Person]) -> [String] { var ids = [String]() for person in people { ids.append(person.id) } return ids }
func idsFromPeople(people: [Person]) -> [String] { return people.map { $0.id } }
Preferred
Notpreferred
Higher order functions
func idsFromPeople(people: [Person]) -> [String] { var ids = [String]() for person in people { ids.append(person.id) } return ids }
func idsFromPeople(people: [Person]) -> [String] { return people.map { $0.id } }
Preferred
Notpreferred
MAP
Higher order functions
func childrenCountFromPeople(people: [Person]) -> Int { var count = 0 for person in people { count += person.children.count } return count}
Notpreferred
Higher order functions
func childrenCountFromPeople(people: [Person]) -> Int { var count = 0 for person in people { count += person.children.count } return count}
func childrenCountFromPeople(people: [Person]) -> Int { return people.reduce(0) { $0 + $1.children.count } }
Preferred
Notpreferred
Higher order functions
func childrenCountFromPeople(people: [Person]) -> Int { var count = 0 for person in people { count += person.children.count } return count}
func childrenCountFromPeople(people: [Person]) -> Int { return people.reduce(0) { $0 + $1.children.count } }
Preferred
Notpreferred
REDUCE
Higher order functions
FILTER
MAP
REDUCE
You want some of the original elements
You want new elements based on the original elements
You want a result based on the original elements
Pure functions
A pure function is a function where the return value is only determined by its input values, without observable side
effects.
Pure functions
A pure function is a function where the return value is only determined by its input values, without observable side
effects.
• There is a return value
Pure functions
A pure function is a function where the return value is only determined by its input values, without observable side
effects.
• There is a return value
• Result depends only on input values
Pure functions
A pure function is a function where the return value is only determined by its input values, without observable side
effects.
• There is a return value
• No side effects
• Result depends only on input values
Pure functions
A pure function is a function where the return value is only determined by its input values, without observable side
effects.
• There is a return value
• No side effects
• Result depends only on input values 100% unit-testable!
• There is a return value
• No side effects
• Result depends only on input values
func configureLabelTextWithNumber(number: Int) { self.numberLabel.text = "\(number)" }
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func configureLabelTextWithNumber(number: Int) { self.numberLabel.text = "\(number)" }
• There is a return value ❌
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func configureLabelTextWithNumber(number: Int) { self.numberLabel.text = "\(number)" }
• There is a return value ❌
• Result depends only on input values ✅
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func configureLabelTextWithNumber(number: Int) { self.numberLabel.text = "\(number)" }
• There is a return value ❌
• No side effects ❌
• Result depends only on input values ✅
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func configureLabelTextWithNumber(number: Int) { self.numberLabel.text = "\(number)" }
• There is a return value ❌
• No side effects ❌
• Result depends only on input values ✅
Example #1
Functions using "self.something" are a call to side effects
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• Result depends only on input values ✅
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ✅
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ✅
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
Pure function
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ✅
func labelTextForNumber(number: Int) -> String { return "\(number)" }
Example #1
self.numberLabel.text = self.labelTextForNumber(1)
Pure function
Pure functions
func teenagers() -> [Person] { return self.people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
Example #2
Pure functions
func teenagers() -> [Person] { return self.people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
Example #2
Pure functions
func teenagers() -> [Person] { return self.people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
Example #2
Pure functions
func teenagers() -> [Person] { return self.people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
Example #2
• Result depends only on input values ❌
Pure functions
func teenagers() -> [Person] { return self.people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
Example #2
• Result depends only on input values ❌
How would you test it?
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
Example #2
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
Example #2
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
Example #2
• Result depends only on input values ✅
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
Example #2
• Result depends only on input values ✅
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
Example #2
• Result depends only on input values ✅
Pure function
Pure functions
func teenagersFromPeople(people: [Person]) -> [Person] { return people.filter { $0.age > 12 && $0.age < 20 } }
Example #2
func test15YearsOldIsTeenager() { let filter = PeopleFilter() // System Under Test let someone = Person(name: "asd", age: 15) let input = [someone] let output = filter.teenagersFromPeople(input) XCTAssertEqual(output.count, 1) if output.count == 1 { XCTAssertEqual(output.first!, someone) } }
Pure function
100% unit-testable!
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ❌
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ❌
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Functions involving randomness can never be pure functions
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ❌
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Functions involving randomness can never be pure functionsThey are not unit-testable, because we can't know what expected result is
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ❌
func randomCharacterFromString(string: String) -> String { let maxNumber = UInt32((string as NSString).length) let randomNumber = Int(arc4random_uniform(maxNumber)) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3
Functions involving randomness can never be pure functionsThey are not unit-testable, because we can't know what expected result is , unless…
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
func randomCharacterFromString(string: String, seed: Int) -> String { let maxNumber = Int32((string as NSString).length) srand(UInt32(seed)) // Configure the randomizer's seed let randomNumber = Int(rand() % maxNumber) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3 , unless…
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
func randomCharacterFromString(string: String, seed: Int) -> String { let maxNumber = Int32((string as NSString).length) srand(UInt32(seed)) // Configure the randomizer's seed let randomNumber = Int(rand() % maxNumber) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3 , unless…
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• Result depends only on input values ✅
func randomCharacterFromString(string: String, seed: Int) -> String { let maxNumber = Int32((string as NSString).length) srand(UInt32(seed)) // Configure the randomizer's seed let randomNumber = Int(rand() % maxNumber) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3 , unless…
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ✅
func randomCharacterFromString(string: String, seed: Int) -> String { let maxNumber = Int32((string as NSString).length) srand(UInt32(seed)) // Configure the randomizer's seed let randomNumber = Int(rand() % maxNumber) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3 , unless…
Pure functions
• There is a return value
• No side effects
• Result depends only on input values
• There is a return value ✅
• No side effects ✅
• Result depends only on input values ✅
func randomCharacterFromString(string: String, seed: Int) -> String { let maxNumber = Int32((string as NSString).length) srand(UInt32(seed)) // Configure the randomizer's seed let randomNumber = Int(rand() % maxNumber) let range = NSRange(location: randomNumber, length: 1) return (string as NSString).substringWithRange(range) }
Example #3 , unless…
Pure function
Pure functions
Pure functions
Higher order functions
Protocol-orientedprogramming
Immutability
Genericprogramming
Pattern matchingMVVM
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
But also…
The intention of your code is clearer
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
But also…
The intention of your code is clearer
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
But also…
Code is easier to understand for others
The intention of your code is clearer
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
But also…
Code is easier to understand for others
Less headaches when maintaining each others’ code
The intention of your code is clearer
If you start applying these little yet valuable concepts…
Your brain starts to think in different ways and your mind gets open to learn more and more!
But also…
Code is easier to understand for others
Less headaches when maintaining each others’ code
More effectiveness, more productivity