суббота, 17 марта 2012 г.
[prog] Маленькое дополнение к недавней заметке о читабельности кода
В комментарии к недавней заметке о читабельности кода прозвучала мысль о том, что хорошо было бы сделать возвращаемое методом make_and_send_packages значение именованным. Безотносительно к моему собственному мнению на сей счет, это хороший повод вспомнить принцип Command/Query Separation, который лежит в основе идеологии языка Eiffel.
Если следовать этому принципу, то в моем прикладном агенте не должно было бы быть метода make_and_send_packages. Вместо него потребовался бы вспомогательный класс package_maker_and_sender_t с методом-командой make_and_send и методом-запросом number_of_packages_sent. Который бы использовался следующим образом:
if( !messages->empty() ) { package_maker_and_sender_t sender( *messages, /* плюс еще какие-то параметры */ ); sender.make_and_send(); m_load_batcher.increment_current_load( sender.number_of_packages_sent() ); } |
В Eiffel-е принцип разделения методов на команды и запросы является одним из краеугольных. Мне же представляется, что такое жесткое разделение не всегда разумно. Может из-за того, что я учился программировать на процедурных языках, где функция могла производить побочный эффект (открывать файл, например) и возвращать значение. Поэтому я не вижу в таком подходе ничего плохого. Может из-за того, что command/query separation principle ведет к распуханию кода – туча мелких вспомогательных классов + выполнение самих действий удваивается в объеме: сначала вызов command-метода, затем query-метода. Upd. Забыл про еще один негативный момент: в таких вспомогательных методах появляется лишняя забота о том, чтобы методы вызывались в должном порядке. Так, объект класса package_maker_and_sender_t должен бить программиста по рукам, если тот вызывает number_of_packages_sent до вызова make_and_send. Что так же увеличивает объем работы программиста.
С другой стороны, принцип весьма простой, местами удобный. Особенно в ОО-языках, где нет понятия константности объектов и их методов (т.е. Java, C#, Eiffel, Ruby и пр.). Поэтому вполне может использоваться на практике. В частности, в упомянутой заметке на таком принципе работает класс load_batcher_t, который обладает методами-командами check_for_new_period и increment_current_load, а так же методом-запросом remaining_load.
PS. При следовании принципу Command/Query Separation методы-запросы начинают выступать в роли “чистых функций”, т.е. не меняющих состояние объекта и, по идее, всегда возвращающих одинаковый результат (если только они обращаются к каким-то изменяющимся из-вне объектам). Что может вносить в обычные ОО-языки некоторое подобие функциональщины, где функции не имеют побочных эффектов. Но только подобие, очень бледное ;)
пятница, 16 марта 2012 г.
[life] Магазин одежды б/у премиум класса
Большую вывеску с таким содержанием я увидел сегодня на одном из магазинов нашего города. Как по мне, так вещи премиум класса не могут быть бывшими в употреблении в принципе. И данное вывеска – пример оксюморона вроде “светлая тьма” или “живой труп”.
Хотя, может это магазин премиум класса, просто торгует он б/у-шной одеждой, а не сантехникой или мобильными телефонами :)
вторник, 13 марта 2012 г.
[prog] На тему читабельности кода
Написал несколько недель назад фрагмент кода. Отладил. Пошел писать другой код. Через какое-то время пришлось вернутся к нему еще раз. И тут наступили тормоза – не могу увидеть, где делается самое важное действие. Нет его в коде и все. Хотя программа работает и я точно знаю, это действие я писал и что ничего не менял.
Коротко: нужно определить, сколько готовых к отсылке пакетов сообщений можно поднять из БД, вычитать их из БД и отослать. Попутно логируя выполняемые действия.
Все это я в коде видел за исключением самой отсылки пакетов :)
Вот сей фрагмент в первозданном виде:
void a_out_pkg_sender_t::try_send_or_resend_packages() { const ACE_Time_Value current_time = ACE_OS::gettimeofday(); m_load_batcher.check_for_new_period( current_time ); const unsigned int max_packages_to_send = m_load_batcher.remaining_load(); if( 0 != max_packages_to_send ) { if( m_cfg.m_diagnostic_logging.m_rescan_db_for_resending ) so_log_msg_same_ns( outgoing_package, load_started ) .max_package_count( max_packages_to_send ) .finish( *this ); std::auto_ptr< db::out_message_info_list_t > messages = m_db->select_out_pkg_for_sending( max_packages_to_send, date_time_in_past( current_time, m_cfg.m_notifies.m_out_pkg_throughput.m_resend_timeout ), ACE_Date_Time( current_time ) ); if( m_cfg.m_diagnostic_logging.m_rescan_db_for_resending ) so_log_msg_same_ns( outgoing_package, load_finished ) .messages_loaded( messages->size() ) .finish( *this ); if( !messages->empty() ) m_load_batcher.increment_current_load( make_and_send_packages( *messages ) ); } } |
В конце-концов все нашлось, сказалась, полагаю, общая усталость от работы в авральном режиме. Но от греха подальше переписал “проблемное” место так:
[work.doc] Большая бесплатная книга по LaTeX-у на русском
Из-за работы с опозданием узнал о публикации в Интернете еще одной большой книги по LaTeX-у на русском языке: Е.М.Балдин, Компьютерная типография LaTeX. Автору книги огромный респект и уважуха.
Сам я не большой спец по LaTeX-у, но для написания документации использую именно его. На мой взгляд, для разработчика это намного более удобный инструмент, чем Word. Поскольку написание текста документа происходит почти как программирование, с использованием макросов, подпрограмм и рефакторингом повторяющихся фрагментов ;)
Плюс к тому текстовые LaTeX-овые исходные файлы, имхо, намного лучше приспособлены для совместной работы над документом посредством системы контроля версий, чем Word-овские файлы или какие-нибудь XML-ные DocBook-и.
PS. Пишу LaTeX-овые тексты в ViM-е, использую какую-то версию MikTeX-а, орфографию не проверяю ;)