ConstructiCat Logo
CodeBust.
Browse section ▾

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

Размещение данных в исходном коде программы

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

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

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

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

Обзор

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

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

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

Бэкдоры

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

Управление цифровыми правами

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

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

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

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

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

Загрузочный диск

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

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

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

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

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

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

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

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

Решение

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

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

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

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

Соревнования по программированию

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

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

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

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

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

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

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

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

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

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

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

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

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