Вот такие комментарии пишут порой даже опытные разработчики ![]()

Как не надо писать комментарии к коду
Вот такие комментарии пишут порой даже опытные разработчики ![]()

Как не надо писать комментарии к коду
Ни с того ни с сего количество посетителей увеличилось в два раза. А на сайте то абсолютно ничего не менялось: контент не добавлялся, дизайн не менялся, оптимизация не проводилась… Посмотрим сколько это продлится.

Прям хочется добавить чего-нибудь интересненького. Пойду полежу - может желание поработать само пройдет?
Все знают об этом перле уважаемого P.J. Plauger в Visual Studio 2005:
class A
{};
class B
{};
void HalloBug()
{
std::auto_ptr<B> bug(new A());
}
И вы представляете, даже зная об этом, на эти грабли действительно можно наступить
Никому! Не верите?! Не верьте!
Что такое качественный код, определять точно не будем; под этим термином будем понимать “хороший”, “краткий”, “легко читаемый” и “почти оптимальный” код.
Как его получить, описывать тоже не будем. Ибо хороший рецепт еще не гарантирует, что повар тоже будет хорошим… Да и написано про это много.
Займемся вопросом, почему качественный код никому (= основной массе) не нужен. Ответ лежит на поверхности - потому, что массе важны следующие факторы:
1. Надежность кода.
2. Низкая цена.
3. Короткое время разработки.
4. Долговременное сотрудничество с заказчиком.
5. Прозрачность ответственности.
А, как известно, качественный код обладает следующими свойствами:
1. Из качественного кода легко сделать не качественный. Не согласны? Добавтье ложку дёгтя в бочку мёда, и немного размешайте. Получилось?
2.A. Качественный код — дороже на начальном этапе разработки. Что будет при поддержке, интересует не всех и не всегда.
2.B. Качественный код могут писать и поддерживать “только” высококвалифицированные специалисты. Таким образом качественный код дороже на любом этапе разработки. При этом опасность быть испорченным остается всегда.
2.C. Качественный код обычно использует все возможности языка. Что делает его менее изменяемым для новичков.
3. Первые результаты при разработке качественного кода видны позже.
4. Качественный код увеличивает вероятность “удовлетворить клиента раньше, чем из него будет выкачена определенная сумма денег”. Увидеть красоту и читабельность — легко, приэтом осознать сложность практически не возможно.
5. У идеологов/заказчиков/маркетологов нет возможности спихнуть вину на разработчиков.
P.S.: Продаю качественный код. Дорого. Ручная работа.
Когда-то был код:
class XXX
{
private:
size_t m_size;
char* m_data;
public:
ByteArray GetByteArray() const
{
return ByteArray(m_size, m_data);
}
};
Для класса XXX был написан визуализатор:
std::ostream& operator<<(std::ostream& os, const ByteArray& obj);
std::ostream& operator<<(std::ostream& os, const XXX& obj)
{
os << "XXX: ByteArray: " << obj.GetByteArray();
return os;
}
Все прекрасно работало. Решили, что необходимо, чтобы работало еще быстрее — без лишних копирований. Окей, переделываем:
class XXX
{
private:
size_t m_size;
char* m_data;
public:
std::auto_ptr< ByteArray> GetByteArray() const
{
return std::auto_ptr< ByteArray>(new ByteArray(m_size, m_data));
}
};
Компилируем — про визуализатор забыли. Переделываем:
std::ostream& operator<<(std::ostream& os, const XXX& obj)
{
os << "XXX: ByteArray: " << *obj.GetByteArray();
return os;
}
Все прекрасно работает. Решили, что необходимо, чтобы работало еще быстрее — без лишних копирований. Мы же все — опытные велосипедисты, и никогда не забудем освободить память. Окей, переделываем:
class XXX
{
private:
size_t m_size;
char* m_data;
public:
ByteArray* GetByteArray() const
{
return new ByteArray(m_size, m_data);
}
};
Компилируем — все супер!!! И пусть отдел тестирования теперь ищет, почему у них протоколлирование течет в ранее рабочем коде…
Так, что — будем экономить, чего бы нам это не стоило!
Es gibt nur vier Minarette in der Schweiz. Der Bau von Minaretten ist seit Gestern verboten. 57,5 Prozent haben ihren Kreuzchen an der richtigen Stelle platziert. Ungefähr so:

Schweizer! Wehrt Euch!
Так как ODBC давно уже морально устарело, можно и засветиться…
using namespace ODBC3;
try
{
Environment env;
SafeConnection conn(env, "database", "login", "password");
Statement stmt(conn);
stmt.Prepare("select * from test_my");
Types::ULong id;
Types::ULong val;
Types::AString name;
id.BindColTo(stmt, 1);
val.BindColTo(stmt, 2);
name.BindColTo(stmt, 3);
stmt.Execute();
while(stmt.FetchNext())
{
std::cout << id.GetValue() << " "
<< name.GetValue() " "
<< val.GetValue() << std::endl;
}
}
catch(const Exception& e)
{
const std::vector< boost::shared_ptr< DiagRec>>& diagRecs = e.GetDiagRecs();
if(diagRecs().size() == 0)
std::cerr << e.GetMessage() << std::endl
else
{
std::ostringstream msg;
for(size_t i = 0; i < diagRecs.size(); ++i)
{
if(i > 0)
msg << std::endl;
boost::shared_ptr< DiagRec> diagRec(diagRecs[i]);
msg << diagRec->sqlState << " "
<< diagRec->messageText;
}
std::cerr << msg.str() << std::endl
}
}
Предупреждения доступны при подписке по следующему интерфейсу:
template< class Source >
class WarningHandler
{
public:
virtual void OnWarning(const Source& sender,
const std::vector< boost::shared_ptr< DiagRec>>& diagRecs) = 0;
};
Пример:
template< class Source >
class WarningListener
{
public:
virtual void OnWarning(const Source& sender,
const std::vector< boost::shared_ptr< DiagRec>>& diagRecs)
{
for(size_t i = 0; i < diagRecs.size(); ++i)
{
boost::shared_ptr< DiagRec> diagRec(diagRecs[i]);
std::cout << "Warning: " << diagRec->sqlState << " "
<< diagRec->messageText;
}
}
};
WarningListener< Environment > envWarningListener;
WarningListener< Connection > connWarningListener;
Environment env(envWarningListener);
SafeConnection conn(env, "database", "login", "password", connWarningListener);
Казалось бы, исключения существуют уже вечность. Ан нет, сплошь и рядом о них спотыкаешься.
Часть 1: исключения STL
Что выведет следующий код?
try
{
std::fstream fs;
fs.exceptions(std::ios::failbit | std::ios::badbit);
fs.open("No such file!");
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
Я не знаю, чем вы пользуетесь для компиляции и исполнения, но при запуске этого кода из Visual Studio я получаю очень информативное, занимательное и важное сообщение “ios_base::failbit set”.
Часть 2: исключения ODBC
Писали мы как-то клиента базы данных с помощью ODBC. И, как водится у всех уважающих себя вело-любителей c++ программистов, для программы-клиента реализовали удобную c++ обертку ODBC, которая кидалась исключениями в случае ODBC-ошибок. Поразительно, но мы налюбоваться не могли какие классные сообщения об ошибках нам выдавал драйвер всем известного SQL сервера. Например, при удалении строки в какой-нибудь таблице, можно было получить такое сообщение: “Невозможно удалить строку из таблицы “Cities”, потому что таблица “Addresses” содержит на нее ссылки”.
Более того в зависимости от региональных настроек, сообщения выдавались на разных языках. Например, для немецкой операционной системы сообщения выглядит как-то так: “Da die Tabelle “Addresses” mindestens eine Referenz auf die aktuellen Zeile in der Tabelle “Cities” enhält, ist es unmöglich sie zu löschen”.
Пытливый читатель заметит сразу, что имена таблиц переставлены. А опытный разработчик, имевший дело с ODBC, однозначно скажет, что выделить имена таблиц из сообщения об ошибке (например, для того чтобы перевести не понятные “Addresses” и “Cities” в “Адреса” и “Города”) — не возможно, так как даже если удастся найти строки в сообщении, то порядок их следования не известен. При этом сам тип ошибки всегда доступен и однозначен.
Итого: сообщение хорошее, но контекст для последующей обработки не доступен.
Часть 3: как надо
Объекту исключения следует содержать в себе следующее:
1. Короткое сообщение без контекста. Например “Не удалось открыть файл.”
2. Полное сообщение с контекстом. Например “Не удалось открыть файл ($путь) для чтения, так как не достаточно текущих прав пользователя($права).”
3. Типизированный контекст сопутствующих объектов. Например путь как строка, и права как объект представляющий права пользователя.
4. Исключение-первопричина.
Шаблоны и интернационализацию добавить по вкусу.
P.S.: Жаль, что с C++ как надо никогда не будет.
Не могу удержаться не процитировать не безизвестного автора:
An exception of class domain_error is used to report a domain error.
Nicolai M. Josuttis, “The C++ Standard Library: A Tutorial and Reference”.
Раздел 3.3.1 Standard Exception Classes
Страница 28, третья строка сверху.
P.S.: Программирование - как литература: иногда кажется, что платят за количество строчек, а не за их содержание.
Потому, что я не люблю глобальные переменные.
А глобальные переменные — это зло.
Более того:
Статические переменные класса — это зло.
Статические переменные объявленные в методе — это еще большее зло.
А все почему? Потому, что статические переменные суть глобальные с ограниченной областью видимости.
Что такое синглтон? Это эмуляция глобальной переменной. Синглтон — это зло.
Другая цель синглтона — это обеспечение того, что будет создан только один экземпляр класса. Но, позвольте, классов такого рода в природе практические не существует…
Синглтон — это антипаттерн объектно ориентированного программирования.
P.S.: Шаблон программирования monostate — туда же.