Логотип ConstructiCat
CodeBust.
Навигация по разделу ▾

Жёсткое кодирование.

Жёсткое кодирование — встраивание путей, учётных данных или ставок прямо в исходный код, из-за чего для их изменения приходится править и пересобирать программу.

Жёсткое кодирование — это практика разработки программного обеспечения, при которой данные встраиваются непосредственно в исходный код программы или другого исполняемого объекта, в отличие от получения данных из внешних источников или их генерации во время выполнения.

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

Жёстко закодированные данные лучше всего подходят для неизменяемых фрагментов информации, таких как физические константы, номера версий и статические текстовые элементы.

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

Обзор

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

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

Термин «жёстко закодированный» изначально использовался по аналогии с жёсткой коммутацией электрических цепей и был призван передать негибкость, возникающую при его применении в проектировании и реализации программного обеспечения. В контексте расширяемых во время выполнения сред совместной разработки, таких как MUD, жёсткое кодирование также означает разработку ядра системы, отвечающего за низкоуровневые задачи и выполнение скриптов, в отличие от мягкого кодирования, представляющего собой разработку высокоуровневых скриптов, которые интерпретируются системой во время выполнения, со значениями из внешних источников, таких как текстовые файлы, INI-файлы, базы данных, аргументы командной строки, ответы HTTP-сервера, файлы конфигурации и пользовательский ввод. В этом случае термин не имеет уничижительного оттенка и относится к разработке в целом, а не конкретно к встраиванию выходных данных.

Бэкдоры

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

Фиксированный путь установки

Если программа для Windows запрограммирована исходить из того, что она всегда устанавливается в C:\Program Files\Appname и кто-то пытается установить её на другой диск из соображений места или организации, она может не установиться или не запуститься после установки. Эта проблема может не выявиться в процессе тестирования, поскольку средний пользователь устанавливает на диск и в каталог по умолчанию, а тестирование может не включать вариант изменения каталога установки. Тем не менее программистам и разработчикам рекомендуется не фиксировать путь установки программы, поскольку путь установки по умолчанию зависит от операционной системы, её версии и решений системного администратора. Например, многие установки Microsoft Windows используют диск C: в качестве основного жёсткого диска, но это не гарантируется.

Специальные папки

Некоторые операционные системы Windows имеют так называемые специальные папки, которые логически упорядочивают файлы на жёстком диске. При жёстком кодировании могут возникать следующие проблемы:

Путь к профилю

Некоторые программы Windows жёстко кодируют путь к профилю в заданные разработчиком расположения, такие как C:\Documents and Settings\Username (путь по умолчанию в Windows 2000 и Windows XP) или C:\Users\Username (путь по умолчанию начиная с Windows Vista). Такой путь перестаёт работать, если программа запускается в другой версии Windows или если профиль хранится в сети либо перемещён иным образом. Правильный способ получить его — вызвать функцию GetUserProfileDirectory или развернуть переменную окружения %userprofile%. Ещё одно предположение, которое часто делают разработчики, — что профиль находится на локальном жёстком диске.

Путь к папке «Мои документы»

Некоторые программы Windows жёстко кодируют путь к Мои документы как ProfilePath\My Documents. Эти программы работали бы на машинах с английской версией, но на локализованных версиях Windows эта папка обычно имеет другое имя. Например, в итальянских версиях папка My Documents называется Documenti. My Documents также может быть перемещена с помощью перенаправления папок в групповой политике в Windows 2000 и выше. Правильный способ получить её — вызвать функцию SHGetKnownFolderPath (в версиях до Windows Vista — SHGetFolderPath).

Решение

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

Жёсткое кодирование особенно проблематично при подготовке программного обеспечения к переводу на другие языки.

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

Один важный случай жёсткого кодирования — когда строки помещаются непосредственно в файл, что вынуждает переводчиков редактировать исходный код для перевода программы. (Существует инструмент под названием gettext, который позволяет оставлять строки в файлах, но даёт переводчикам возможность переводить их без изменения исходного кода; по сути, он отменяет жёсткое кодирование строк.)

Мягкое кодирование

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

Практика программирования

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

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

Потенциальные проблемы

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

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

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

Достижение гибкости

Существует несколько обоснованных паттернов проектирования для достижения гибкости, которую пытается обеспечить мягкое кодирование. Приложению, требующему большей гибкости, чем уместно для файла конфигурации, может пойти на пользу включение скриптового языка. Во многих случаях подходящим решением является предметно-ориентированный язык, интегрированный в устоявшийся скриптовый язык. Другой подход — перенести большую часть функциональности приложения в библиотеку, предоставив API для быстрого написания связанных приложений.

Пример

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

def connect():
    return Database(host="10.0.0.12", user="admin", password="s3cr3t!")


def price_with_vat(amount):
    return amount * 1.2

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

import os
from dataclasses import dataclass


@dataclass(frozen=True)
class Settings:
    db_host: str
    db_user: str
    db_password: str
    vat_rate: float

    @classmethod
    def from_env(cls) -> "Settings":
        return cls(
            db_host=os.environ["DB_HOST"],
            db_user=os.environ["DB_USER"],
            db_password=os.environ["DB_PASSWORD"],
            vat_rate=float(os.environ["VAT_RATE"]),
        )


def connect(settings: Settings):
    return Database(host=settings.db_host, user=settings.db_user, password=settings.db_password)


def price_with_vat(amount, settings: Settings):
    return amount * (1 + settings.vat_rate)

Адаптировано по статье Википедии “Hard coding” (версия 1355219913), распространяется по лицензии CC BY-SA 4.0; текст переведён и отредактирован, добавлены примеры.