/ clean_code_recommendations.md
clean_code_recommendations.md
  1  # Рекомендации по созданию читаемого и качественного кода
  2  
  3  Этот документ обобщает ключевые принципы и практики для написания "чистого" (clean code), читаемого и поддерживаемого кода, основанные на анализе научных статей с ресурса arXiv.
  4  
  5  ## 1. Что такое "идеальный" код?
  6  
  7  Идеальный, или "чистый", код — это не просто код, который работает. Это код, который **легко понять, модифицировать и поддерживать** другим людям (и вам самим в будущем). Ключевые характеристики:
  8  
  9  - **Читаемость (Readability):** Код должен читаться как хорошо написанный текст. Его логика и намерения должны быть ясны без необходимости запуска и отладки.
 10  - **Предсказуемость:** Поведение кода соответствует ожиданиям.
 11  - **Простота:** Решает задачу самым прямым и эффективным способом, без лишних усложнений.
 12  - **Поддерживаемость (Maintainability):** Внесение изменений не требует титанических усилий и не ломает другие части системы.
 13  
 14  ---
 15  
 16  ## 2. Ключевые практики для чистого кода
 17  
 18  ### 2.1. Осмысленные имена (Meaningful Names)
 19  
 20  **Проблема:** "Загадочные имена" и "непоследовательные соглашения" являются одними из главных барьеров для понимания кода. (Из статьи `2501.10037v1`)
 21  
 22  **Рекомендации:**
 23  
 24  - **Используйте описательные имена:** Имя переменной, функции или класса должно четко отражать его суть и предназначение.
 25  
 26    *Плохо (из-за кратких и неочевидных имен):*
 27    ```python
 28    # data - это список температур, crit - порог
 29    def proc(data, crit):
 30        res = []
 31        for val in data:
 32            if val > crit:
 33                res.append(val)
 34        return res
 35    ```
 36  
 37    *Хорошо (имена отражают суть):*
 38    ```python
 39    def filter_high_temperatures(temperatures, threshold):
 40        """Отбирает температуры, превышающие заданный порог."""
 41        high_temperatures = []
 42        for temp in temperatures:
 43            if temp > threshold:
 44                high_temperatures.append(temp)
 45        return high_temperatures
 46    ```
 47  
 48  - **Придерживайтесь единого стиля:** Выберите и используйте один стиль именования во всем проекте (например, `camelCase` для переменных и `PascalCase` для классов, или `snake_case` для всего). Это делает код визуально опрятным и предсказуемым.
 49  
 50  - **Избегайте сокращений:** Не используйте сокращения, которые могут быть непонятны другим (например, `calc_int` вместо `calculate_interest`).
 51  
 52  ### 2.2. Комментарии и документация
 53  
 54  **Проблема:** Отсутствие или неадекватность документации — основная причина, по которой код становится сложным для повторного использования и воспроизводимости научных результатов. (Из статьи `2501.10037v1`)
 55  
 56  **Рекомендации:**
 57  
 58  - **Комментируйте "почему", а не "что":** Код сам по себе должен объяснять, *что* он делает. Комментарии нужны, чтобы объяснить, *почему* было принято то или иное неочевидное решение.
 59  
 60    *Плохо (комментарий дублирует код):*
 61    ```python
 62    # Проверяем, больше ли баланс нуля
 63    if balance > 0:
 64        ...
 65    ```
 66  
 67    *Хорошо (комментарий объясняет бизнес-логику):*
 68    ```python
 69    # Клиенты с положительным балансом получают бонус,
 70    # это требование из маркетинговой кампании Q3.
 71    if balance > 0:
 72        ...
 73    ```
 74  
 75  - **Используйте Docstrings и аннотации типов:** Для функций и классов пишите документацию (docstrings), описывающую их назначение, параметры и возвращаемое значение. В современных языках используйте аннотации типов.
 76  
 77    *Плохо (непонятно, что принимает и возвращает функция):*
 78    ```python
 79    def get_users(data, min_log):
 80        # ...
 81    ```
 82  
 83    *Хорошо (понятные типы и документация):*
 84    ```python
 85    from typing import List
 86  
 87    class User:
 88        # ...
 89  
 90    def get_active_users(users: List[User], min_logins: int) -> List[User]:
 91        """
 92        Фильтрует список пользователей, оставляя только активных.
 93  
 94        Args:
 95            users: Список объектов пользователей.
 96            min_logins: Минимальное количество логинов для статуса "активный".
 97  
 98        Returns:
 99            Список активных пользователей.
100        """
101        # ...
102    ```
103  
104  ### 2.3. Структура кода и паттерны
105  
106  **Проблема:** Качество кода можно измерять через "использование обобщений, наследования, переиспользования и других объектно-ориентированных концепций". (Из статьи `1106.6159v1`)
107  
108  **Рекомендации:**
109  
110  - **Принцип единственной ответственности (Single Responsibility Principle):** Каждая функция или класс должны делать что-то одно, но делать это хорошо. Не создавайте "швейцарские ножи".
111  
112  - **Не повторяйтесь (Don't Repeat Yourself - DRY):** Если вы копируете и вставляете код, вероятно, его можно вынести в отдельную функцию или класс.
113  
114  - **Используйте паттерны проектирования:** Для решения типовых архитектурных задач используйте общепринятые паттерны (например, "Фабрика", "Стратегия", "Декоратор"). Это делает ваш код более понятным для тех, кто знаком с этими паттернами.
115  
116  ### 2.4. Автоматизация и инструменты
117  
118  **Проблема:** Многие разработчики не используют инструменты для проверки качества кода, хотя такие инструменты могут автоматически находить проблемы. (Из статьи `2501.10037v1`)
119  
120  **Рекомендации:**
121  
122  - **Интегрируйте статические анализаторы и линтеры:** Инструменты, такие как ESLint (для JavaScript), Pylint (для Python), или SonarLint, могут находить потенциальные ошибки, "запахи" в коде и нарушения стиля еще до его запуска.
123  
124  - **Автоматизируйте форматирование:** Используйте инструменты вроде Prettier или `black`, чтобы автоматически форматировать код по единому стандарту. Это избавляет от споров о стиле и делает код единообразным.
125  
126  ---
127  
128  ## 3. Психология восприятия кода: Не доверяйте слепо метрикам
129  
130  **Проблема:** Статические анализаторы и IDE часто показывают метрики качества кода (например, "читаемость", "сложность"). Однако, как показывает исследование `2012.09590v2`, эти цифры могут вводить в заблуждение.
131  
132  **Ключевая идея: Эффект якоря (Anchoring Effect)**
133  
134  - **Суть эксперимента:** Разработчикам показывали фрагменты кода и рядом выводили случайное число, якобы представляющее "метрику читаемости".
135  - **Результат:** Оценка читаемости, которую давали разработчики, сильно зависела от показанного им "якоря". Если им показывали высокий балл, они оценивали код как более понятный, и наоборот, даже если сам код был одинаковым.
136  - **Вывод:** Наше восприятие качества кода очень субъективно и легко поддается влиянию внешних, даже бессмысленных, факторов.
137  
138  **Рекомендации:**
139  
140  - **Относитесь к метрикам скептически:** Используйте числовые показатели (цикломатическая сложность, индекс поддерживаемости) как отправную точку для анализа, а не как окончательный вердикт.
141  - **Доверяйте своей команде:** Лучший способ оценить читаемость кода — это code review. Если ваши коллеги не могут понять код, он нечитаемый, какой бы высокий балл ему ни ставил анализатор.
142  
143  ## 4. Академический взгляд на измерение качества
144  
145  **Проблема:** Многие общепринятые метрики качества кода не имеют под собой строгой научной валидации. Мы *верим*, что они работают, но это не всегда так. (Из статьи `2012.09590v2`)
146  
147  **Рекомендации:**
148  
149  - **Фокусируйтесь на конкретных характеристиках:** Вместо абстрактной "читаемости" оценивайте более конкретные вещи:
150      - **Время на понимание:** Сколько времени у нового человека в команде займет понимание этого модуля?
151      - **Легкость внесения изменений:** Насколько сложно добавить новую функциональность в этот класс?
152      - **Количество потенциальных ошибок:** Насколько легко допустить ошибку при работе с этим кодом?
153  - **Вклад в научное сообщество:** Если вы разрабатываете инструменты анализа, основывайте свои метрики на эмпирических исследованиях, а не только на интуиции.
154  
155  ---
156  
157  ## 5. Структура кода и паттерны
158  
159  Качество кода определяется не только именами переменных, но и его общей структурой. Хорошо структурированный код интуитивно понятен и легко расширяем.
160  
161  **Рекомендации:**
162  
163  ### 5.1. Принцип единственной ответственности (Single Responsibility Principle - SRP)
164  
165  Каждый класс или функция должны отвечать за что-то одно. Это делает их проще для понимания, тестирования и повторного использования.
166  
167  *Плохо (класс отвечает и за данные, и за их сохранение):*
168  ```python
169  class Report:
170      def __init__(self, title, content):
171          self.title = title
172          self.content = content
173  
174      def get_content(self):
175          return f"Отчет: {self.title}\n{self.content}"
176  
177      def save_to_file(self, path):
178          """Этот метод нарушает SRP, т.к. класс отчета не должен заниматься сохранением."""
179          with open(path, 'w') as f:
180              f.write(self.get_content())
181  
182  # Использование:
183  # report = Report("Итоги месяца", "Продажи выросли.")
184  # report.save_to_file("report.txt") # Класс сам себя сохраняет
185  ```
186  
187  *Хорошо (ответственность разделена):*
188  ```python
189  class Report:
190      """Класс отвечает только за структуру и форматирование отчета."""
191      def __init__(self, title, content):
192          self.title = title
193          self.content = content
194  
195      def get_content(self):
196          return f"Отчет: {self.title}\n{self.content}"
197  
198  class ReportSaver:
199      """Этот класс отвечает только за сохранение отчета."""
200      def save(self, report, path):
201          with open(path, 'w') as f:
202              f.write(report.get_content())
203  
204  # Использование:
205  # report = Report("Итоги месяца", "Продажи выросли.")
206  # saver = ReportSaver()
207  # saver.save(report, "report.txt") # Разные объекты для разных задач
208  ```
209  
210  ### 5.2. Не повторяйтесь (Don't Repeat Yourself - DRY)
211  
212  Если вы видите повторяющиеся блоки кода, вынесите их в отдельную функцию. Это уменьшает количество кода, упрощает внесение изменений (менять нужно в одном месте) и снижает риск ошибок.
213  
214  *Плохо (логика расчета скидки дублируется):*
215  ```python
216  def process_order_for_vip_client(order_total):
217      # Расчет 10% скидки
218      discount = order_total * 0.10
219      final_price = order_total - discount
220      print(f"Цена для VIP-клиента: {final_price}")
221      # ... какая-то еще логика
222  
223  def process_order_for_promo_code(order_total):
224      # Расчет 10% скидки
225      discount = order_total * 0.10
226      final_price = order_total - discount
227      print(f"Цена по промокоду: {final_price}")
228      # ... другая логика
229  ```
230  
231  *Хорошо (логика вынесена в функцию):*
232  ```python
233  def calculate_discounted_price(order_total, discount_percentage):
234      """Рассчитывает и возвращает цену после применения скидки."""
235      discount = order_total * (discount_percentage / 100)
236      return order_total - discount
237  
238  def process_order_for_vip_client(order_total):
239      final_price = calculate_discounted_price(order_total, 10)
240      print(f"Цена для VIP-клиента: {final_price}")
241      # ... какая-то еще логика
242  
243  def process_order_for_promo_code(order_total):
244      final_price = calculate_discounted_price(order_total, 10)
245      print(f"Цена по промокоду: {final_price}")
246      # ... другая логика
247  ```
248  
249  ---
250  
251  ## 6. Инструменты и автоматизация
252  
253  Человеческий глаз несовершенен. Автоматизированные инструменты помогают поддерживать качество кода на высоком уровне, обнаруживая проблемы, которые легко пропустить при ручной проверке.
254  
255  **Рекомендации:**
256  
257  Используйте следующие инструменты в своих Python-проектах:
258  
259  - **Линтеры (Linters):**
260    - **`Pylint`** или **`Flake8`**: Проверяют код на соответствие стандартам стиля (PEP 8), находят потенциальные ошибки (например, неиспользуемые переменные) и оценивают сложность кода.
261  
262  - **Форматтеры (Formatters):**
263    - **`black`**: "Бескомпромиссный" форматтер кода. Автоматически переформатирует ваш код в едином стиле. Устраняет все споры о форматировании в команде.
264    - **`isort`**: Автоматически сортирует импорты в алфавитном порядке и группирует их.
265  
266  - **Проверка типов (Type Checking):**
267    - **`mypy`**: Статический анализатор типов. Проверяет, что вы передаете в функции и возвращаете из них данные правильных типов, что помогает отловить множество ошибок еще до запуска программы.
268  
269  **Пример рабочего процесса (workflow):**
270  
271  1. Вы пишете код, используя аннотации типов.
272  2. Перед коммитом вы запускаете `black` и `isort`, чтобы автоматически отформатировать код.
273  3. Затем запускаете `mypy` для проверки типов.
274  4. Наконец, запускаете `Flake8` или `Pylint` для поиска оставшихся проблем.
275  5. Только после этого отправляете код на code review.
276  
277  Этот подход позволяет передавать на проверку коллегам уже очищенный и стандартизированный код, чтобы они могли сосредоточиться на логике, а не на стиле.
278  
279  ---
280  
281  ## 7. Источники и использованные материалы
282  
283  При подготовке этого документа были использованы следующие научные работы:
284  
285  1.  **A Guideline for Writing Clean, Understandable, and Reproducible Scientific Code** (arXiv:2501.10037v1)
286      *   *Ключевые идеи:* Важность документации, осмысленных имен и использования инструментов для воспроизводимости кода.
287      *   *Ссылка:* [https://arxiv.org/abs/2501.10037v1](https://arxiv.org/abs/2501.10037v1)
288  
289  2.  **The Anchoring Effect in Code Readability Assessments** (arXiv:2012.09590v2)
290      *   *Ключевые идеи:* Психологический "эффект якоря", который показывает, что числовые метрики читаемости могут вводить разработчиков в заблуждение.
291      *   *Ссылка:* [https://arxiv.org/abs/2012.09590v2](https://arxiv.org/abs/2012.09590v2)
292  
293  3.  **A Metrics-suite for Code Readability** (arXiv:1106.6159v1)
294      *   *Ключевые идеи:* Анализ того, как объектно-ориентированные концепции (наследование, полиморфизм) влияют на метрики качества кода.
295      *   *Ссылка:* [https://arxiv.org/abs/1106.6159v1](https://arxiv.org/abs/1106.6159v1)
296  
297  ---
298  
299  ## 8. Продвинутые темы и современные исследования (2023-2025)
300  
301  Сообщество разработчиков и исследователей постоянно ищет новые способы улучшения качества кода. Последние работы (2023-2025 гг.) фокусируются на производительности идиоматичного кода, управлении техническим долгом и использовании больших языковых моделей (LLM) для автоматизации рефакторинга.
302  
303  ### 8.1. "Пайтонический" код: не только красиво, но и быстро
304  
305  **Проблема:** Часто считается, что "пайтонический" (идиоматичный) код, следующий заветам "The Zen of Python", в первую очередь нацелен на читаемость, а не на скорость. Однако исследования показывают, что это не всегда так.
306  
307  **Рекомендации (из статьи 2203.14484v1):** Использование встроенных идиом Python может значительно повысить производительность и уменьшить потребление памяти.
308  
309  *   *Плохо (использование традиционного цикла для фильтрации):*
310      ```python
311      # Отфильтровать список, оставив только четные числа
312      numbers = list(range(1000000))
313      even_numbers = []
314      for num in numbers:
315          if num % 2 == 0:
316              even_numbers.append(num)
317      ```
318  
319  *   *Хорошо (использование list comprehension):*
320      ```python
321      # List comprehension работает быстрее, так как выполняется на более низком уровне (в CPython),
322      # и код становится более декларативным и читаемым.
323      numbers = list(range(1000000))
324      even_numbers = [num for num in numbers if num % 2 == 0]
325      ```
326      **Вывод:** Идиоматичный код часто является не компромиссом, а выигрышем как в читаемости, так и в производительности.
327  
328  ### 8.2. Технический долг в эпоху AI: от `TODO` до `PromptDebt`
329  
330  **Проблема:** Технический долг — это не просто плохой код. Это осознанный компромисс, когда разработчики оставляют неоптимальное решение, чтобы сэкономить время сейчас, но с намерением исправить это позже. Часто это проявляется как "самопризнанный технический долг" (Self-Admitted Technical Debt - SATD) в комментариях.
331  
332  **Рекомендации (из статей 2501.09888v1, 2409.11826v1):**
333  
334  *   **Фиксируйте SATD явно:** Комментарии `TODO` или `FIXME` — это первый шаг. Они делают проблему видимой.
335  *   **Автоматизируйте возврат долга:** Современные исследования показывают, что LLM можно обучить находить и даже автоматически исправлять такие участки кода.
336  
337  *   *Плохо (долг оставлен и может быть забыт):*
338      ```python
339      def calculate_tax(amount, region):
340          # TODO: реализовать правильный расчет налогов для каждого региона.
341          # Пока что используем заглушку 10% для всех.
342          if region == "EU":
343              return amount * 0.20 # Временное решение для EU
344          return amount * 0.10
345      ```
346  
347  *   *Хорошо (долг устранен с использованием паттерна "Стратегия"):*
348      ```python
349      from abc import ABC, abstractmethod
350  
351      # Определяем интерфейс для стратегий
352      class TaxStrategy(ABC):
353          @abstractmethod
354          def calculate(self, amount: float) -> float:
355              pass
356  
357      # Реализуем конкретные стратегии для каждого региона
358      class EUTaxStrategy(TaxStrategy):
359          def calculate(self, amount: float) -> float:
360              # ... сложная логика для EU
361              return amount * 0.20
362  
363      class USTaxStrategy(TaxStrategy):
364          def calculate(self, amount: float) -> float:
365              # ... сложная логика для US
366              return amount * 0.07
367      
368      # Контекст, который использует стратегию
369      class TaxCalculator:
370          def __init__(self, strategy: TaxStrategy):
371              self._strategy = strategy
372  
373          def calculate(self, amount: float) -> float:
374              return self._strategy.calculate(amount)
375  
376      # Использование:
377      # calculator = TaxCalculator(EUTaxStrategy())
378      # tax = calculator.calculate(100)
379      ```
380  
381  **Новый вид долга: `PromptDebt` (из статьи 2509.20497v1)**
382  
383  С появлением LLM возник новый тип технического долга — **PromptDebt**. Он возникает, когда разработчики используют неоптимальные, слишком общие или плохо протестированные промпты для взаимодействия с AI.
384  
385  *   *Пример PromptDebt:*
386      ```python
387      # Промпт слишком общий и может давать нестабильные результаты
388      prompt = f"Summarize this text: {user_text}"
389      # summary = openai.Completion.create(prompt=prompt) # Пример вызова
390      ```
391      Такой промпт может работать по-разному для разных текстов. "Хороший" промпт был бы более детальным, с примерами и четкими инструкциями (техника few-shot prompting), что снижает риск непредсказуемого поведения модели.
392  
393  **Вывод:** Управление техническим долгом становится более комплексной задачей, требующей внимания не только к коду, но и к компонентам на базе AI.
394  
395  ### 8.3. LLM как ассистент по рефакторингу: автоматическое улучшение качества
396  
397  **Проблема:** Ручной рефакторинг — трудоемкий процесс. Разработчики часто откладывают его из-за нехватки времени, что ведет к накоплению технического долга.
398  
399  **Рекомендации (из статей 2502.07399v1, 2309.12938v1):** Используйте LLM-ассистенты (такие как GitHub Copilot или специализированные инструменты) для автоматического анализа и рефакторинга кода. Эти инструменты могут находить "запахи" в коде и предлагать конкретные исправления.
400  
401  Исследовательские фреймворки, такие как **CodeQUEST**, показывают, что LLM могут итеративно улучшать код, повышая его читаемость, поддерживаемость и даже безопасность.
402  
403  *   *Плохо (функция делает слишком много: загружает, обрабатывает и сохраняет данные):*
404      ```python
405      import json
406      import pandas as pd
407  
408      def process_data_from_json(file_path):
409          """Загружает данные, фильтрует пользователей старше 30 и сохраняет результат."""
410          # 1. Загрузка данных
411          with open(file_path, 'r') as f:
412              data = json.load(f)
413          
414          df = pd.DataFrame(data)
415  
416          # 2. Обработка данных
417          df_filtered = df[df['age'] > 30]
418  
419          # 3. Сохранение результата
420          output_path = file_path.replace('.json', '_processed.csv')
421          df_filtered.to_csv(output_path, index=False)
422          print(f"Processed data saved to {output_path}")
423      ```
424  
425  *   *Хорошо (рефакторинг, предложенный LLM-ассистентом, разделяет логику):*
426      ```python
427      import json
428      import pandas as pd
429      from typing import List, Dict
430  
431      def load_users_from_json(file_path: str) -> pd.DataFrame:
432          """Отвечает только за загрузку данных из JSON в DataFrame."""
433          with open(file_path, 'r') as f:
434              data = json.load(f)
435          return pd.DataFrame(data)
436  
437      def filter_users_by_age(df: pd.DataFrame, min_age: int) -> pd.DataFrame:
438          """Отвечает только за фильтрацию пользователей по возрасту."""
439          return df[df['age'] > min_age]
440  
441      def save_df_to_csv(df: pd.DataFrame, output_path: str):
442          """Отвечает только за сохранение DataFrame в CSV."""
443          df.to_csv(output_path, index=False)
444          print(f"Data saved to {output_path}")
445  
446      # Использование:
447      # source_file = 'users.json'
448      # users_df = load_users_from_json(source_file)
449      # adult_users_df = filter_users_by_age(users_df, 30)
450      # save_df_to_csv(adult_users_df, 'adult_users.csv')
451      ```
452  **Вывод:** LLM-инструменты становятся мощными партнерами в поддержке чистоты кода, беря на себя рутинные задачи рефакторинга и позволяя разработчикам сосредоточиться на более сложных проблемах.
453  
454  ---
455  
456  ## 9. Обновленный список источников
457  
458  В этот раздел добавлены работы, рассмотренные в секции 8.
459  
460  4.  **Does Coding in Pythonic Zen Peak Performance?** (arXiv:2203.14484v1)
461      *   *Ключевые идеи:* Исследование производительности идиоматичного Python-кода. Показывает, что "пайтонические" конструкции часто не только более читаемы, но и более эффективны.
462      *   *Ссылка:* [https://arxiv.org/abs/2203.14484v1](https://arxiv.org/abs/2203.14484v1)
463  
464  5.  **Understanding the Effectiveness of LLMs in Automated Self-Admitted Technical Debt Repayment** (arXiv:2501.09888v1)
465      *   *Ключевые идеи:* Анализ способности LLM автоматически находить и исправлять "самопризнанный технический долг" (комментарии `TODO`).
466      *   *Ссылка:* [https://arxiv.org/abs/2501.09888v1](https://arxiv.org/abs/2501.09888v1)
467  
468  6.  **PromptDebt: A Comprehensive Study of Technical Debt Across LLM Projects** (arXiv:2509.20497v1)
469      *   *Ключевые идеи:* Введение и анализ концепции "PromptDebt" — нового вида технического долга, возникающего из-за некачественных промптов к LLM.
470      *   *Ссылка:* [https://arxiv.org/abs/2509.20497v1](https://arxiv.org/abs/2509.20497v1)
471  
472  7.  **On Iterative Evaluation and Enhancement of Code Quality Using GPT-4o** (arXiv:2502.07399v1)
473      *   *Ключевые идеи:* Представление фреймворка `CodeQUEST`, использующего LLM для итеративной оценки и улучшения качества кода по множеству параметров.
474      *   *Ссылка:* [https://arxiv.org/abs/2502.07399v1](https://arxiv.org/abs/2502.07399v1)