Как не надо писать комментарии к коду

November 23rd, 2010

Вот такие комментарии пишут порой даже опытные разработчики :-(

Как не надо писать комментарии к коду

Как не надо писать комментарии к коду

Увеличение количества посетителей

June 17th, 2010

Ни с того ни с сего количество посетителей увеличилось в два раза. А на сайте то абсолютно ничего не менялось: контент не добавлялся, дизайн не менялся, оптимизация не проводилась… Посмотрим сколько это продлится.
Visitors in June 2010
Прям хочется добавить чего-нибудь интересненького. Пойду полежу - может желание поработать само пройдет?

Пользуясь случаем, передаю привет P.J. Plauger

April 29th, 2010

Все знают об этом перле уважаемого P.J. Plauger в Visual Studio 2005:

class A
{};

class B
{};

void HalloBug()
{
	std::auto_ptr<B> bug(new A());
}

И вы представляете, даже зная об этом, на эти грабли действительно можно наступить :-(

Кому нужен качественный код?

December 15th, 2009

Никому! Не верите?! Не верьте!

Что такое качественный код, определять точно не будем; под этим термином будем понимать “хороший”, “краткий”, “легко читаемый” и “почти оптимальный” код.

Как его получить, описывать тоже не будем. Ибо хороший рецепт еще не гарантирует, что повар тоже будет хорошим… Да и написано про это много.

Займемся вопросом, почему качественный код никому (= основной массе) не нужен. Ответ лежит на поверхности - потому, что массе важны следующие факторы:
1. Надежность кода.
2. Низкая цена.
3. Короткое время разработки.
4. Долговременное сотрудничество с заказчиком.
5. Прозрачность ответственности.

А, как известно, качественный код обладает следующими свойствами:
1. Из качественного кода легко сделать не качественный. Не согласны? Добавтье ложку дёгтя в бочку мёда, и немного размешайте. Получилось?

2.A. Качественный код — дороже на начальном этапе разработки. Что будет при поддержке, интересует не всех и не всегда.

2.B. Качественный код могут писать и поддерживать “только” высококвалифицированные специалисты. Таким образом качественный код дороже на любом этапе разработки. При этом опасность быть испорченным остается всегда.

2.C. Качественный код обычно использует все возможности языка. Что делает его менее изменяемым для новичков.

3. Первые результаты при разработке качественного кода видны позже.

4. Качественный код увеличивает вероятность “удовлетворить клиента раньше, чем из него будет выкачена определенная сумма денег”. Увидеть красоту и читабельность — легко, приэтом осознать сложность практически не возможно.

5. У идеологов/заказчиков/маркетологов нет возможности спихнуть вину на разработчиков.

P.S.: Продаю качественный код. Дорого. Ручная работа.

Экономишь на auto_ptr?!

December 10th, 2009

Когда-то был код:

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);
  }
};

Компилируем — все супер!!! И пусть отдел тестирования теперь ищет, почему у них протоколлирование течет в ранее рабочем коде…

Так, что — будем экономить, чего бы нам это не стоило!

И причем тут C++?!

November 30th, 2009

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!

Schweizer! Wehrt Euch!

ODBC — легко!

November 25th, 2009

Так как 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);

О сообщениях в исключениях

November 25th, 2009

Казалось бы, исключения существуют уже вечность. Ан нет, сплошь и рядом о них спотыкаешься.

Часть 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++ как надо никогда не будет.

Цитата дня.

October 14th, 2009

Не могу удержаться не процитировать не безизвестного автора:

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.: Программирование - как литература: иногда кажется, что платят за количество строчек, а не за их содержание.

Почему я не люблю шаблон “одиночка”?

June 21st, 2009

Потому, что я не люблю глобальные переменные.

А глобальные переменные — это зло.

Более того:
Статические переменные класса — это зло.
Статические переменные объявленные в методе — это еще большее зло.

А все почему? Потому, что статические переменные суть глобальные с ограниченной областью видимости.

Что такое синглтон? Это эмуляция глобальной переменной. Синглтон — это зло.

Другая цель синглтона — это обеспечение того, что будет создан только один экземпляр класса. Но, позвольте, классов такого рода в природе практические не существует…

Синглтон — это антипаттерн объектно ориентированного программирования.

P.S.: Шаблон программирования monostate — туда же.



Rambler's Top100 Rating@Mail.ru