Site icon AppTractor

3 совета для улучшения читабельности кода

В этой статье вы узнаете 3 простых совета, которые помогут сделать вашу кодовую базу более качественной и читабельной.

Используйте ранние возвраты

У людей есть проблемы с пониманием длинного и глубоко вложенного кода. Это не в нашей природе. Мы гораздо лучше понимаем более короткий контекст и легче читаем его.

Один из способов добиться этого — использовать ранние возвраты. Вместо вложенных операторов if-else пишите в них return.

Трудно читать:

fun isPasswordValid(password: String): Result<Unit> =
    if (password.length > 8) {
        if (password.any { it.isUpperCase() }) {
            if (password.any { it.isLowerCase() }) {
                if (password.any { it.isDigit() }) {
                    Result.success(Unit)
                } else {
                    Result.failure(IllegalArgumentException("Password must have a number"))
                }
            } else {
                Result.failure(IllegalArgumentException("Password must have an lower case letter"))
            }
        } else {
            Result.failure(IllegalArgumentException("Password must have an upper case letter"))
        }
    } else {
        Result.failure(IllegalArgumentException("Password is too short"))
    }

Легко читать:

fun isPasswordValid(password: String): Result<Unit> {
    if (password.length < 8) {
        return Result.failure(IllegalArgumentException("Password is too short"))
    }
    if (password.none { it.isUpperCase() }) {
        return Result.failure(IllegalArgumentException("Password must have an upper case letter"))
    }
    if (password.none { it.isLowerCase() }) {
        return Result.failure(IllegalArgumentException("Password must have an lower case letter"))
    }
    if (password.none { it.isDigit() }) {
        return Result.failure(IllegalArgumentException("Password must have a number"))
    }
    return Result.success(Unit)
}

Обе функции логически делают одно и то же, но второй пример гораздо проще для чтения и понимания!

Избегайте отрицаний в условных выражениях

При любом использовании if-else следует избегать отрицаний в условиях. Единственным исключением является правило выше, когда это может уменьшить вложенность кода.

Когда вы используете отрицание в операторе if-else, на самом деле вы создаете двойное отрицание для себя, что гораздо сложнее для понимания.

Трудно читать:

fun updateName(name: String?) {
    if (!name.isNullOrEmpty()) {
        _name.update { name }
    } else {
        _name.update { "" }
    }
}

// Double negation - even worse
private fun notifyUnknownUsers(users: List<User>) {
    users.forEach { user ->
        if (!user.name.isNotEmpty()) {
             sendNoNameNotification(user)
        }
    }
}

Легко читать:

fun updateName(name: String?) {
    if (name.isNullOrEmpty()) {
        _name.update { "" }
    } else {
        _name.update { name }
    }
}

private fun notifyUnknownUsers(users: List<User>) {
    users.forEach { user ->
        if (user.name.isEmpty()) {
            sendNoNameNotification(user)
        }
    }
}

Создавайте значения и переменные как можно позже

Это одна из самых распространенных и самых коварных ошибок, которые загрязняют и увеличивают сложность вашей кодовой базы.

Когда мы ищем проблему в коде, мы стараемся как можно быстрее добраться до места ошибки. Каждое вычисление и значение, которое вам нужно прочитать, и которое бесполезно в данный момент, работает как тормоз. Также нужно больше запоминать, а не делегировать эту работу коду.

Трудно читать:

fun processPayment(payment: Payment) {
    val paymentRequest = if (payment.amount == null) {
        PaymentRequest.Error
    } else {
        PaymentRequest.Data(payment.amount)
    }

    val formattedAmount = AmountFormatter.formatAmount(payment.amount)
    
    val standard = AmountToStandardMapper.map(payment.amount)
    
    sendRequest(paymentRequest)
    displayAmountScreen(formattedAmount)
    displayAmountNotification(formattedAmount)
    displayStandardView(standard)
    displayStandardMessage(standard)
}

Легко читать:

fun processPayment(payment: Payment) {
    val paymentRequest = if (payment.amount == null) {
        PaymentRequest.Error
    } else {
        PaymentRequest.Data(payment.amount)
    }
    sendRequest(paymentRequest)

    val formattedAmount = AmountFormatter.formatAmount(payment.amount)
    displayAmountScreen(formattedAmount)
    displayAmountNotification(formattedAmount)

    val standard = AmountToStandardMapper.map(payment.amount)
    displayStandardView(standard)
    displayStandardMessage(standard)
}

Спасибо за чтение!

Источник

Exit mobile version