Перейти к содержанию

Как проектировать хорошие функции и классы

Проектирование хороших функций

Функции являются одной из наиболее важных частей написания кода. Они делают код многоразовым и простым для чтения и обслуживания. Функции делают код организованным.

Хорошая функция должна обладать следующими свойствами:

  • Должен быть небольшим
  • Должен делать только одну вещь
  • Должно быть меньше аргументов
  • Не должно иметь побочных эффектов

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

Хорошая функция позволяет понять ее, не вдаваясь в детали более низкого уровня, если это не требуется.

Должен быть небольшим

Насколько маленький?

Функции должны быть очень маленькими. Их длина не должна превышать 20 строк.

Как уменьшить размер функций?

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

Однострочные блоки кода

Вложенные структуры, такие как if, else, while, for, try и т.д., в идеале должны вызывать другую функцию в своем блоке кода. Это облегчает чтение и понимание кода.

Должен делать только одну вещь

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

Если из функции можно извлечь другую функцию, значит, она выполняет не одну задачу. Мы должны извлекать функции для достижения того же уровня абстракции,

Функции, которые можно разделить на несколько разделов, выполняют не одну задачу.

Должно быть меньше аргументов

Идеальное количество аргументов для функции равно нулю (niladic). Далее следует один (monadic), за которым следуют два (diadic). По возможности следует избегать трех аргументов (triadic). Более трех (полиадических) требует особого обоснования — и тогда их все равно не следует использовать.

- Роберт К. Мартин (дядя Боб)

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

Выходные аргументы - это аргументы, которые требуются функции только для изменения, чтобы содержать выходные данные. Выходные аргументы усложняют понимание функции, и их следует избегать.

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

Не должно иметь побочных эффектов

Функция не должна обещать одно, а делать что-то другое в качестве побочного эффекта.

Пример: Изменение параметров / свойств класса в методе get / query.

Функция set / update (command) в идеале не должна обновлять параметры. Однако они могут обновлять свойства класса, к которому принадлежит функция.

Как писать хорошие функции?

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

Проектирование хороших классов

Классы связывают связанные данные и предоставляют функции, которые работают с этими данными. Это помогает сделать код более организованным.

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

  • Организованный и инкапсулированный
  • Должен быть небольшим и должен выполнять только одну вещь
  • Небольшое количество переменных экземпляра

Организованный и инкапсулированный

Класс должен сохранять все атрибуты данных и служебные функции закрытыми. Общедоступными должны быть только те функции, которые должны быть доступны.

Класс должен быть упорядочен следующим образом:

Начните с переменных:

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

Должен быть небольшим и должен выполнять только одну вещь

Класс должен быть очень маленьким. У разных экспертов разные взгляды на то, "насколько маленький?". Исходя из большинства мнений, класс должен быть достаточно маленьким, чтобы он выполнял только одну вещь. В общем, в нем должно быть менее 20 функций.

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

Небольшое количество переменных экземпляра

Класс должен обладать сильной связностью, то есть функции класса должны быть тесно связаны для поддержки единой центральной цели.

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

Список литературы: Чистый код: руководство по разработке гибкого программного обеспечения Роберта К. Мартина (дяди Боба)