Skip to content

Improving Code Readability #28

@phucledien

Description

@phucledien

What’s our biggest problem?

In 2006, Microsoft in collaboration with Carnegie Mellon University published a paper called “Maintaining Mental Models: A Study of Developer Work Habits.” The authors conducted a survey among programmers working at Microsoft. And one of the questions they asked was whether a particular task was seen as a problem.

The problem reported most often by these programmers was understanding the rationale behind a piece of code. How did the programmers try to overcome this?
Mostly, just by reading. Reading took over 40% of the time spent on solving this problem. When this was not enough, they tried running a debugger, adding print statements, and so on. If those also failed, they tried to get to the original author and ask them for an explanation.

-> Readability is crucial for understanding code. It makes a real impact on how we work.

programs must be written for people to read, and only incidentally for machines to execute

Readability Quest

Level 1-1: comments

/// Splits the email into username and domain.
/// - Parameter email: A string that possibly
/// contains the email address value.
/// - Returns: Either:
///     - Tuple with username as first element
///     and domain as second
///     - Nil when passed argument cannot be split
func split(email: String)  (String, String)?

Level 1-2: symbols

typealias SplitEmail = (username: String,
                          domain: String)
                          
struct SplitEmail {
    let username: String
    let domain: String
}

func split(email: String)  SplitEmail?

Level 1-3: wrapper

enum SplitEmail {
    case valid(username: String, domain: String)
    case invalid
    
    init(from email: String) {
        let components = email.components(separatedBy: "@")
        if /* same checks as before */ {
            self = .valid(username: username, domain: domain)
        } else {
            self = .invalid
        }
    }
}

Level 1-4: concepts

protocol Splitter {
    associatedtype Splitting
    associatedtype Splitted
    func split(value: Splitting)  (Splitted, Splitted)?
}

struct EmailSplitter: Splitter {
    func split(value: String)(String, String)? {
        let components = value.components(separatedBy: "@")
        guard /* same checks as before */ else { return nil }
        return (first, second)
    }
}

World 2: Delegation

Level 2-1: Initializer injection

struct Announcing {
    private weak var delegate: Delegate?
    
    init(to delegate: Delegate) {
        self.delegate = delegate
    }
}

let announcing = Announcing(to: delegate)

Level 2-2: Weak closure

struct Announcing {
    private let delegate: ()  Delegate?
    
    init(to delegate: @escaping () → Delegate?) { ... }
}

let announcing = Announcing(to: {
    [weak delegate] in delegate
})

Level 2-3: Weak function

func weak<T: AnyObject>(_ object: T)  ()  T? {
    return { [weak object] in object }
}

struct Announcing {
    private let delegate: () → Delegate?
    init(to delegate: @escaping () → Delegate?) { ... }
}

let announcing = Announcing(to: weak(delegate))

Level 2-4: Weak wrapper

struct Weak<T: AnyObject> {
    private let internalValue: ()  T?
    init(_ value: T) {
        internalValue = { [weak value] in value }
    }
}
struct Announcing {
    private let delegate: Weak<Delegate>
    init(to delegate: Weak<Delegate>) { ... }
}

ref: https://academy.realm.io/posts/a-neatly-typed-message-improving-code-readability/

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions