![]() |
3. Именование, назначение и использование | ||
Дать наиболее подходящее имя для сущности — очень важная и довольно сложная задача, хотя на первый взгляд может может показаться иначе. | ||
Основная идея | ||
Имя сущности должно давать лишь ту информацию, которая необходима пользователю для того, чтобы работать с этой сущностью в том контексте, в котором она предоставляется. Здесь и далее под сущностью я подразумеваю любое понятие, которым оперирует язык. Функция, класс, переменная, объект, и так далее. | ||
Именование | ||
Если человек решил воспользоваться каким-либо из ваших инструментов, то это значит, что он рассчитывает решить с помощью него какую-то задачу. При этом пользователю ничего кроме решения его задачи не нужно. Его не должно интересовать внутреннее устройство инструмента, из какой библиотеки он пришел, из каких компонент состоит, и так далее. Пользователю вообще не нужна информация, не имеющая прямого отношения к решению его задачи. Напротив, любая лишняя информация будет сбивать с толку, отвлекать, и, что немаловажно, подталкивать пользователя к ошибочным действиям. | ||
Предположим, пользователя интересует некоторое множество объектов. Например, он хочет последовательно проитерировать некоторый контейнер, выполнив какие-то действия над его содержимым, и вы предоставляете ему такую возможность. При этом совершенно не зачем информировать пользователя о том, что же это за контейнер, std::vector, std::list или boost::array. Эта информация является лишней. Она только собьет пользователя с мысли. Ему гораздо важнее что хранится в контейнере, а не то, как оно там хранится. Представьте себе, что вы пришли в ресторан, заказали блюдо из говядины, сидите, ждете заказ, и тут вас вдруг заставляют изучить весь сельскохозяйственный процесс по выращиванию и забою крупного рогатого скота вмето того, чтобы дать спокойно насладиться едой. | ||
Старайтесь брать в typedef все шаблонные типы с явно указанными шаблонными параметрами. Это даст возможность скрыть от пользователя детали реализации и слишком обобщенные имена, позволив вам присвоить сущности более верное с точки зрения семантики имя. | ||
Плохо: |
0 1 2 3 4 5 6 7 8 9 | struct node { boost::shared_ptr<node> next; std::vector<boost::shared_ptr<node> > children; }; node root; std::vector<boost::shared_ptr<node> >::iterator it = root.children.begin(); |
Гораздо лучше: |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | struct node; typedef boost::shared_ptr<node> node_ptr; struct node { typedef std::vector<node_ptr> container; node_ptr next; container children; }; node root; node::container::iterator it = root.children.begin(); |
Назначение | ||
Ваш инструмент готов. Так, по крайней мере, считаете вы. Однако, так ли это на самом деле? Действительно ли полученный инструмент имеет то же назначение, которое было запланировано? Проверить это очень просто — возьмите постороннего человека и задайте ему вопрос, как он считает, какого назначение изготовленного вами инструмента? Если человек ответит, что назначение инструмента очевидно и оно заключается в том же, что и было запланировано вами, то можете быть уверены — вам удалось сохранить смысл не превнеся никакой лишней информации. В противном случае вы либо завалили пользователя ненужной информацией, либо реализовати не ту функциональность, какая была запланирована. В любом случае это говорит о том, что вы ошиблись. | ||
Здесь мы хотели установить заголовок окна, но потеряли назначение по дороге: |
0 1 2 3 | void on_init(window& win) { win.send_message(window::set_title, "My first application"); } |
Гораздо лучше: |
0 1 2 3 | void on_init(window& win) { win.set_title("My first application"); } |
Использование | ||
Старайтесь реализовывать ваши инструменты таким образом, чтобы их использование для решения задач происходило по сценарию «Пришел, увидел, победил». Задача, которую можно объяснить тремя словами человеческого языка, должна решаться в одно действие с точки зрения кода. Ее решение не должно превращаться в детектив с запутанным сюжетом. Одна задача — одно действие. | ||
Запись в лог выглядит ужасно: |
0 1 2 3 4 5 6 7 8 | std::stringstream stream; stream << get_current_date() << get_current_time() << get_current_thread() << "Application was successfuly initialized" << std::endl; log::instanse().write(log::info, stream.str()); |
Уже лучше: |
0 1 | // Сбор контекста спрятан внутри log::write log::instance().write(log::info, "Application was successfuly initialized"); |
Прекрасно: |
0 1 | // Сбор контекста и интерфейс синглтона спрятаны внутри log_message log_message(log::info, "Application was successfuly initialized"); |
Подведем итоги | ||
Если для ярко выраженной задачи вам приходится оперировать несколькими сущностями, то это означает, что вы работаете на слишком низком уровне. Введите новую сущность, которая будет использовать более низкоуровневые сущности и позволять решать вашу задачу в одно действие и без лишних телодвижений. | ||
Если возможности используемой вами сущности шире, нежели ваши потребности в ее использовании, то это означает что вы неправильно выполнили декомпозицию (или попросту ее не закончили). Введите новую сущность, которая будет позволять решать только вашу задачу, и никакую другую, конкретизируя функциональность сущности с более широкими возможностями. | ||
Не создавайте сущностей, решающих сразу несколько задач. Каждая сущность должна решать одну конкретно поставленную задачу. Если на вопрос «Что делает ваша сущность?» вы не можете дать ясный ответ, состоящий их одного глагола и одного существительного, то, скорее всего, сущность нуждается в доработке. | ||
Имя сущности должно четко отражать ее назначение, из которого, в свою очередь, естественным образом должно вытекать ее использование. Иными словами, между понятиями «именование», «назначение» и «использование» должен стоять знак равенства. Соответствие имени сущности ее назначению и способу применения наполняет программный код однозначным смыслом. | ||
Помимо всего прочего, умение правильно именовать сущности вам особенно пригодится, если вам придется работать с языками, не имеющими статической типизации (например php, javascript, visualbasic и так далее). | ||
Напоследок | ||
Не самая удачная функция из Win32 Platform SDK: |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | BOOL AccessCheckByTypeResultListAndAuditAlarmByHandle ( LPCTSTR SubsystemName, LPVOID HandleId, HANDLE ClientToken, LPCTSTR ObjectTypeName, LPCTSTR ObjectName, PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID PrincipalSelfSid, DWORD DesiredAccess, AUDIT_EVENT_TYPE AuditType, DWORD Flags, POBJECT_TYPE_LIST ObjectTypeList, DWORD ObjectTypeListLength, PGENERIC_MAPPING GenericMapping, BOOL ObjectCreation, LPDWORD GrantedAccess, LPDWORD AccessStatusList, LPBOOL pfGenerateOnClose ); |
|
Статистика |
|