Культовый разработчик Кент Бек сформулировал принципы написания ПО, которые в вольном изложении звучат приблизительно так:

1. Заставь код работать.
2. Сделай его понятным.
3. Оптимизируй для лучшей производительности.

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

Причина проста: на проектной работе важно как можно быстрее выйти на рынок и получить деньги. Джуны спешат разобраться с задачей, не тратя времени на рефакторинг и комментарии.

Обычно до оптимизации дело так и не доходит: важные участки кода скорее «заморозят» и запретят вносить в них изменения, чем перепишут. Беда, если именно в них будет крыться экономическое преимущество системы.

Чистый код существует?

Лирическое отступление

Вопрос на экзамене по программированию: «Что такое Clean Code?»

Студент мучается, пыхтит: «Ну-у-у, там, методы без... э... имена не… Простите, профессор, знал, но забыл!»

Профессор встает и торжественно объявляет аудитории: «Друзья, трагедия! Единственный человек знал про Clean Code — и тот забыл!»

В четком виде теории чистого кода не существует: авторы тематических книг опираются на субъективный опыт и порой противоречат друг другу. В конце концов, всё зависит от задач, которые выполняет код. Однако мы можем выделить несколько эффективных принципов, которые применимы в большинстве случаев.

Принципы написания чистого кода

1. Используйте значимые имена. Назначение переменных, функций, классов и других идентификаторов должно быть понятно из их названия. 

Пример (Java):

public void assign(Author author, Book book)
{
  book.setAuthor(author);
  book.save();
}


По названию метода нельзя определить, что в нём происходит. Это плохо. Конкретизируем имена, и код объяснит сам себя:

public void assignAuthorForBook(Author author, Book book) 
{
  book.setAuthor(author);
  book.save();
}

2. Оставляйте комментарии в сложных участках. Пусть они будут нечастыми, но содержательными. Идеальный код можно понять без дополнительной документации.

Пример (Dart):

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

///! category && product открывают одинаковый экран
/// Это нужно для обработки диплинков
/// Так как на вебе в url может быть либо products, либо category
GoRoute(
  path: CatalogueRoutes.productsItem.path,
  name: CatalogueRoutes.productsItem.path,
  builder: (context, state) => CategoryPage(
    key: state.pageKey,
    slug: state.pathParameters['slug']!,
    args: state.extra as CategoryArgsModel?,
  ),
),
GoRoute(
  path: CatalogueRoutes.categoryItem.path,
    name: CatalogueRoutes.categoryItem.path,
    builder: (context, state) => CategoryPage(
      key: state.pageKey,
      slug: state.pathParameters['slug']!,
      args: state.extra as CategoryArgsModel?,
  ),
),

3. Наводите красоту пустотами. Пробелы, табы и отступы помогут разделить код на логические секции и сделать его удобным для чтения.

Пример (Javascript):

function filterPermissions(permissions, searchQuery) {
const q = searchQuery.trim().toLowerCase()
if (!q) return permissions
const searchDeep = (permission) => filterTree(permission, ({title}) => title.toLowerCase().includes(q))
return permissions.map(searchDeep).filter((v) => v)
}

Такими кирпичами только стены строить. Добавим отступы, выстроим лесенку, и наш увесистый блок превращается в прекрасный читабельный код:

function filterPermissions(permissions, searchQuery) {
    const q = searchQuery.trim().toLowerCase()

    if (!q) {
        return permissions
    }

    const searchDeep = (permission) => filterTree(
      permission,
      ({title}) => title.toLowerCase().includes(q)
    )

    return permissions
        .map(searchDeep)
        .filter((v) => v)
}

4. Отбрасывайте ненужное. После рефакторинга сразу удаляйте участки, которые больше не несут практической ценности. Не оставляйте на случай «вдруг пригодится» — удалённый кусок всегда можно отыскать в истории Git-а.

Пример (go):

//test_banner := model.Banner{ID: 1, FeatureId: 45, TagIds: []int32{5, 12, 244}}
  if !banner.IsActive {
    log.Warn("attempt to get inactive banner")
    //return model.Banner{ID: -1, FeatureId: -1, TagIds: []int32{}, content {"forbidden! - empty"}}
    return nil, fmt.Errorf("banner {id:%d, featureId:%d, tagIds:%v} is inactive",
    banner.ID, banner.FeatureId, banner.TagIds)
  }


Тестовые строчки в комментариях засоряют код и мешают нормальному чтению. Их нужно сносить беспощадно.

Подведем итоги

Чистый код не только «легко читается». В первую очередь мы говорим о грамотном проектировании системы, которое дает нам куда большие преимущества:

— Код легко расширить без технических затрат. Сущности не связаны между собой слишком тесно. 

— Код стабилен и предсказуем. Если появляется проблема, мы уже знаем, куда смотреть. 

P.S.

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

Наши источники

Для статьи мы отбирали советы из книг Роберта Сесила Мартина, Стива Макконнелла и Кента Бека, советовались с практикующими программистами и черпали вдохновение на канале ExtremeCode. Для закрепления информации читайте краткое изложение трудов Дяди Боба и похожий материал о принципах чистого кода, где можно подглядеть ещё больше примеров.

Кстати, как вам материал? Если хотите больше таких – пишите в комментах, нам будет приятно :)

Комментарии (5)


  1. dyadyaSerezha
    12.04.2024 17:09
    +2

    В реальной жизни я видел гораздо чаще такие вещи:

    1) огромные методы/функции, до тысячи и более строк кода, со многими десятками многоуровневых if-else со сложными условиями - и это часто в коде, от которого зависят огромные деньги каждый день.

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