The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Создание библиотек многократного использования (lib gcc share)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: lib, gcc, share,  (найти похожие документы)
From: Андрей Киселев <kis_an at mail.ru> Newsgroups: http://gazette.linux.ru.net/ Date: Mon, 25 Dec 2003 14:31:37 +0000 (UTC) Subject: Создание библиотек многократного использования Оригинал: http://gazette.linux.ru.net/lg81/tougher.html Создание библиотек многократного использования Автор: Rob Tougher Перевод: Андрей Киселев _________________________________________________________________ 1. Введение ]2. Библиотека должна быть простой в использовании 2.1 Простота 2.2 Непротиворечивость 2.3 Интуитивность 3. Тщательное тестирование 4. Детализация сообщений об ошибках 5. Заключение 1. Введение ------------- Библиотеки расширяют возможности разработчиков программного обеспечения. Они содержат код, который разработчики могут использовать в своих проектах. Программные библиотеки, предназначенные для Linux, обычно доступны как в исходных текстах, так и в виде бинарных файлов. Хорошо проработанная библиотека: * проста в использовании * безупречна в работе * дает подробную информацию об ошибках, возникающих во время выполнения В этой статье описываются все вышеупомянутые принципы создания библиотек и приводятся примеры на C++ Эта статья для вас? Прежде чем заняться разработкой новой библиотеки задайте себе пару вопросов: * Понадобится ли кому-нибудь (включая и вас самого) эта библиотека? * Если да, то не существует ли подобная библиотека? Нет смысла разрабатывать библиотеку, если она никому не нужна или, если подобная библиотека уже существует. 2. Библиотека должна быть простой в использовании. ---------------------------------------------------- Создание любой библиотеки должно начинаться с тщательной проработки интерфейса. Интерфейсы, написанные на процедурно-ориентированных языках, подобных C, представляют собой функции. В объектно-ориентированных языках, таких как C++ или Python, интерфейсы могут быть как функциями так и классами. Основное правило при проработке интерфейса: * Чем проще, тем лучше Как разработчику, мне часто приходится сталкиваться с необходимостью поиска правильного баланса между функциональностью и простотой в использовании. Вышеприведенное правило помогает мне в этом. Придерживайтесь следующих рекомендаций и успех вам будет обеспечен. 2.1 Простота ---------------- Чем сложнее библиотека, тем труднее ею пользоваться. * Простота не хуже воровства! Недавно я столкнулся с библиотекой, написанной на C++, которая содержала один единственный класс. В этом классе было определено 150 методов. 150 методов! Разработчик, по всей видимости, был ветераном языка C и использовал класс C++ как обычный сишный модуль. Класс получился настолько сложным, что разобраться в нем оказалось очень непростой задачей. Избегайте построения сложных интерфейсов в своих разработках, тогда они будут легче восприниматься. 2.2 Непротиворечивость. --------------------------- Непротиворечивый интерфейс воспринимается и запоминается намного легче. Запомнив правила работы с интерфейсом, пользователи довольно легко применяют их при работе со всеми классами и методами в библиотеке, даже если ранее пользоваться ими не приходилось. Давайте рассотрим пример использования методов, предоставляющих доступ к скрытым (приватным) полям класса: class point { public: int get_x() { return m_x; } int set_x ( int x ) { m_x = x; } int y() { return m_y; } private: int m_x, m_y; }; Видите несоответствия? Доступ к полю m_x выполняется через метод с именем "get_x()", а к полю m_y -- через "y()". Такая несогласованность вынуждает пользователя всякий раз обращаться к определениям методов перед тем как использовать их. Еще один пример неудачной реализации интерфейса: class DataBase { public: recordset get_recordset ( const std::string sql ); void RunSQLQuery ( std::string query, std::string connection ); std::string connectionString() { return m_connection_string; } long m_sError; private: std::string m_connection_string; }; Вы можете самостоятельно найти ошибки? По-крайней мере, я заметил следующие: * Разработчик не старался придерживаться единого стиля именования. * Для обозначения строки с SQL-запросом используются два различных имени -- sql и query * Не определен метод доступа к полю m_sError * В списке аргументов метода get_recordset() отсутствует параметр connection Вот пересмотренная версия класса с исправленными ошибками: class database { public: recordset get_recordset ( const std::string sql ); void run_sql_query ( std::string sql ); std::string connection_string() { return m_connection_string; } long error() { return m_error; } private: std::string m_connection_string; long m_error; }; Разрабатывайте интерфейсы настолько непротиворечивыми, насколько это возможно - такие интерфейсы запоминаются намного легче. 2.3 Интуитивность --------------------- Подходите к разработке интерфейса с точки зрения пользователя, а не с точки зрения внутреннего устройства. Самый простой способ разработки интуитивно понятного интерфейса состоит в том, чтобы попробовать записать код, который будет использовать библиотечные вызовы прежде, чем фактически переходить к написанию кода библиотеки. Это позволяет взглянуть на будущую библиотеку с точки зрения пользователя. Давайте разберем небольшой пример. Недавно, размышляя о создании криптографической библиотеки, основанной на OpenSSL, я написал такой код: crypto::message msg ( "My data" ); crypto::key k ( "my key" ); // blowfish algorithm msg.encrypt ( k, crypto::blowfish ); msg.decrypt ( k, crypto::blowfish ): // rijndael algorithm msg.encrypt ( k, crypto::rijndael ); msg.decrypt ( k, crypto::rijndael ): Это помогло мне взглянуть на будущую библиотеку глазами пользователя. Если я решусь на создание такой библиотеки, то эти идеи будут для меня отправной точкой при ее реализации. 3. Тщательное тестирование ---------------------------- Код библиотеки должен быть безупречен. Хорошо, пусть не безупречен, но, по крайней мере, он должен быть настолько близок к безупречному, насколько это возможно. Пользователю необходима уверенность в том, что библиотека безошибочно выполняет возложенные на нее задачи. * Зачем пользоваться библиотекой, если она работает с ошибками? При создании своих библиотек я стараюсь автоматизировать процесс отладки. Для каждой библиотеки создается соответствующее тестовое приложение, которое проверяет ее функциональность. А теперь допустим, что я решил написать криптографическую библиотеку, которую упоминал выше. Тогда тестовое приложение, для ее проверки, будет выглядеть примерно так: #include "crypto.hpp" int main ( int argc, int argv[] ) { // // 1. Зашифровать, расшифровать и проверить // crypto::message msg ( "Hello there" ); crypto::key k ( "my key" ); msg.encrypt ( k, crypto::blowfish ); msg.decrypt ( k, crypto::blowfish ); if ( msg.data() != "Hello there" ) { // Ошибка! } // // 2. Зашифровать по одному алгоритму, // расшифровать по другому алгоритму // и проверить. // // и т.д.... } В процессе разработки, время от времени, я запускаю тестовое приложение, чтобы убедиться, что библиотека не содержит ошибок. 4. Детализация сообщений об ошибках ------------------------------------- Пользователь всегда должен предупреждаться о ситуациях, когда библиотека не может выполнить тот или иной запрос. * Предупреждайте пользователя всегда, когда возникают проблемы Библиотеки, написанные на C++, как правило, используют механизм исключений для передачи сообщения об ошибке. Рассмотрим следующий пример: #include <string> #include <iostream> class car { public: void accelerate() { throw error ( "Could not accelerate" ); } }; class error { public: Error ( std::string text ) : m_text ( text ) {} std::string text() { return m_text; } private: std::string m_text; }; int main ( int argc, int argv[] ) { car my_car; try { my_car.accelerate(); } catch ( error& e ) { std::cout << e.text() << "\n"; } } Класс car использует ключевое слово throw для возбуждения исключительной ситуации и передачи сообщения об ошибке в вызвавшую функцию. Вызывающая функция "ловит" исключение с помощью конструкции try ... catch и обрабатывает его. 5. Заключение --------------- В этой статье я постарался рассказать о важных правилах написания хорошего кода библиотек. Надеюсь, что мне удалось это сделать в достаточной степени, чтобы вы могли воспользоваться ими при создании своих библиотек. Rob Tougher Copyright (C) 2002, Rob Tougher. Copying license http://www.linuxgazette.com/copying.html Published in Issue 81 of Linux Gazette, August 2002

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

 Добавить комментарий
Имя:
E-Mail:
Заголовок:
Текст:




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру