Approved Final Committee Draft (FCD) for C++0x - Ура, товарищи!!!
Теперь ожидаются только багфиксы и редакторские правки (займёт около года). Так что у нас будет стандарт C++0xB.
P.S.
А CodeBubbles показывают как будет выглядеть IDE в будущем.
воскресенье, 14 марта 2010 г.
среда, 10 марта 2010 г.
Working Effectively with Legacy Code - впечатления от книги
Наконец-то прочитал Working Effectively with Legacy Code - дождался таки её выхода на русском и прочитал. Общее впечатление от книги - "must read" для тех, кто работает с maintanence.
"Красной нитю через всё произведение проходит" идея о необходимости покрытия кода юнит-тестами. С этой идеей я целиком и полностью согласен, т.к. не так давно приняли LC систему, у которой нет каких-либо тестов (только ручные по сценариям) и с знанием только по общей логике работы программы у предыдущего разработчика - проблема классическая для LC системы - время проверки правильности изменений может занимать до 3-х рабочих дней просто из-за того, что все проверки проходятся вручную.
Что ещё приятно в этой книге, так это то, что автор не навязывает какой-то подход (чем часто грешат метологи аджайла - "юнит тесты ВСЕГДА перед кодом" - блин, это же гибкие методологии разработки! ну как так можно?), он просто показывает как эффективно работать с унаследованным кодом.
Т.е. плюсы книги не заканчиваются на описании TDD, как можно было бы понять из вступления и 1-х глав. Для меня разбор следующих тем является большим плюсом в этой книге:
Ну а то, что Майкл Физерс является автором CppUnit, является приятной фенечкой этой книги ;)
Слабым минусом этой книги является её перевод. Хотя разница по времени между выпуском английского оригинала и русским переводом составила почти 5 лет, качество перевода не блестящее - иногда (но не часто) приходилось делать обратный перевод на английский, чтобы понять мысль автора (использовались немного не очевидные термины), раза два или три лезть в английский оригинал за замыслом автора, и несколько раз были переведены имена переменных в тексте. Но в целом перевод хороший - по крайней мере таких ляпов как в переводе программиста-прагматика, я не нашёл.
Я бы посоветовал её читать тем кто работает с унаследованными системами где-то через полгода после прочтения Рефакторинга Фаулера и Паттернов Банды Четырёх, по следующим причинам:
Я читал её значительно позже чем советую - об этом сейчас сожалею. Прочитал бы вовремя - сэкономили бы командой кучу времени/нервов на изобретение велосипедов и избежали бы части просчётов в разработке.
Очень бы советовал прочитать "Refactoring to Patterns" by Joshua kirievski на том же этапе, что и Working Effectively with Legacy Code - они прекрасно дополняют друг друга и освещают работу с уже работающими системами с разных точек : Working Effectively with Legacy Code - это больше тактика внесения изменений(изменения в коде), а "Refactoring to Patterns" - это больше стратегия низкого уровня внесения изменений в системы (изменения в дизайне на уровне классов).
ЗЫ
а стратегия высокого уровня внесения изменений в системы - это уже просто перепроектирование системы :p
"Красной нитю через всё произведение проходит" идея о необходимости покрытия кода юнит-тестами. С этой идеей я целиком и полностью согласен, т.к. не так давно приняли LC систему, у которой нет каких-либо тестов (только ручные по сценариям) и с знанием только по общей логике работы программы у предыдущего разработчика - проблема классическая для LC системы - время проверки правильности изменений может занимать до 3-х рабочих дней просто из-за того, что все проверки проходятся вручную.
Что ещё приятно в этой книге, так это то, что автор не навязывает какой-то подход (чем часто грешат метологи аджайла - "юнит тесты ВСЕГДА перед кодом" - блин, это же гибкие методологии разработки! ну как так можно?), он просто показывает как эффективно работать с унаследованным кодом.
Т.е. плюсы книги не заканчиваются на описании TDD, как можно было бы понять из вступления и 1-х глав. Для меня разбор следующих тем является большим плюсом в этой книге:
- описываются способы внесения изменений, которые позволяют снизить риск внесения ошибки практически до 0, в случае если нельзя прикрепить тесты к системе из-за каких-то ограничений (архитектурных, например).
- какие тесты лучше иметь перед внесением своих изменений и как их лучше подсунуть в систему
- какие изменения понадобятся в архитектуре системы для добавления тестов в такой-то области и к чему они приведут
- плюсы и минусы различных способов реализации заглушечных функций и объектов для тестов.
Ну а то, что Майкл Физерс является автором CppUnit, является приятной фенечкой этой книги ;)
Слабым минусом этой книги является её перевод. Хотя разница по времени между выпуском английского оригинала и русским переводом составила почти 5 лет, качество перевода не блестящее - иногда (но не часто) приходилось делать обратный перевод на английский, чтобы понять мысль автора (использовались немного не очевидные термины), раза два или три лезть в английский оригинал за замыслом автора, и несколько раз были переведены имена переменных в тексте. Но в целом перевод хороший - по крайней мере таких ляпов как в переводе программиста-прагматика, я не нашёл.
Я бы посоветовал её читать тем кто работает с унаследованными системами где-то через полгода после прочтения Рефакторинга Фаулера и Паттернов Банды Четырёх, по следующим причинам:
- читать надо после них, т.к. терминология из них активно используется,
- читать надо с задержкой, чтобы сформировался свой собственный взгляд и понимание maintanence - т.к. чтение "потому что дядя сказал" даст значительно меньше пользы.
Я читал её значительно позже чем советую - об этом сейчас сожалею. Прочитал бы вовремя - сэкономили бы командой кучу времени/нервов на изобретение велосипедов и избежали бы части просчётов в разработке.
Очень бы советовал прочитать "Refactoring to Patterns" by Joshua kirievski на том же этапе, что и Working Effectively with Legacy Code - они прекрасно дополняют друг друга и освещают работу с уже работающими системами с разных точек : Working Effectively with Legacy Code - это больше тактика внесения изменений(изменения в коде), а "Refactoring to Patterns" - это больше стратегия низкого уровня внесения изменений в системы (изменения в дизайне на уровне классов).
ЗЫ
а стратегия высокого уровня внесения изменений в системы - это уже просто перепроектирование системы :p
Labels:
книга,
умные мысли?
понедельник, 22 февраля 2010 г.
WPF в Visual Studio 2010: причины
Здесь рассказали о причинах, по которым в Visual Studio 2010 был использован WPF. Если опускать всю воду, то получается следующий список (в порядке описания разработчиком Visual Studio):
- надо было использовать WPF в каком-то известном приложении MS по маркетинговым причинам;
- архитектура Visual Studio, продолжашая эволюционировать с Visual C++6, начала мешать добавлению новых возможностей в студию.
Если 2-ю причину я могу принять и понять - нужно отбрасывать старое и развязывать логику и пользовательский интерфейс, чтобы удобней было жить потом. То 1-я причина (использование студии для раскрутки WPF) вызывает некоторый дискомфорт в мозгах - "Юзают мой любимый инстумент для раскрутки какой-то технологии, которую я из c++ и попробовать-то не могу!".
А дальнейшее разъяснение, что использование WPF в студии, так и не было доведено до конца, начинает уже ставить большие знаки вопроса - зачем браться и делать на условных "62%".
В целом странные ощущения от студии 2010 - реализация части функционала из C++0x, унифицированая система сборки проектов, и в то же время странное решение о использовании WPF для IDE.
Labels:
умные мысли?
суббота, 6 февраля 2010 г.
Статья Саттера об асинхронном API
Недавно вышла новая статья Herb Sutter'а "Prefer Futures to Baked-In "Async APIs" , в которой он анализирует различные варианты как предоставлять асинхронность операций API. В конце статьи Саттер приходит к выводу, что лучше такого не предоставлять отдельное асинхронное API, т.к. любая реализация будет мешать пользователю библиотеки, и тогда разработчик, который пользуется этой библиотекой, сможет сделать асинхронность так, как удобно именно ему, а не какому-то стороннему дяде (привет Adobe с их C++ PDF API), и только для тех функций, которые нужны ему в асинхронном виде. Как один из плюсов такого подхода, Саттер приводит остановку бессмысленного раздувания программных библиотек.
Вот интересно, а сам Саттер понимал, что его статья подтолкнёт программистов, которые используют сторонние библиотеки, к удобной им реализации асинхронности функций, даже в ущерб уже доступному асинхронному API? И зная Саттера с его стремлением к concurrent коду и эффективной реализации многопоточности, можно сказать, что он сознательно провоцирует на это.
Читайте Саттера, кто этого ещё не делает, и обдумывайте прочитанное - возможно самое вкусное вы пока не заметили.
Labels:
умные мысли,
c++
воскресенье, 27 декабря 2009 г.
Обработка событий - что и как получать?
Варианты именно реализации подписки и обработки в самих потребителях событий здесь не буду рассматривать: все эти наследования реализации, наследования интерфейсов, утиные типизации, - все их плюсы и минусы уже неоднократно обсуждались и потому не вижу особого смысла обговаривать эти аспекты снова.
В этом же посте хочу сосредоточится на таком небольшом пункте, как аргументы в функциях-обработчиках событий. Вещь-то сейчас кажется тривиальной, но надо посмотреть на грабли, которые заложили для нас предшественники. Итак поехали:
При обработке событий можно выделить 2 аспекта: как мы получаем событие и что мы получаем с событием вместе.
При получении событий от источника сообщений возможны следующие варианты:
В этом же посте хочу сосредоточится на таком небольшом пункте, как аргументы в функциях-обработчиках событий. Вещь-то сейчас кажется тривиальной, но надо посмотреть на грабли, которые заложили для нас предшественники. Итак поехали:
При обработке событий можно выделить 2 аспекта: как мы получаем событие и что мы получаем с событием вместе.
При получении событий от источника сообщений возможны следующие варианты:
- мы подписываемся отдельными потребителями на сообщения от соответствующих объектов источника
- мы подписываемся на сообщения от всей системы-источника сообщений(при этом можно указать, что такие-то события нам нужны, а такие-то нет, но источником событий у нас служит система целиком)
В варианте с целевой подпиской мы не тратим время на фильтрацию сообщений и не ломаем голову, что мы что-то куда-то не туда отправили на обработку. В варианте с общей подпиской мы твёрдо уверены что ничего не пропустили. Т.е. у каждого подхода есть свои плюсы и минусы, впрочем как всегда...
Причины приведённые выше будут влиять на архитектурные решения, какой из вариантов выбирать: вариант с целевой подпиской выгоден в пределах одной системы и нескольких подсистем(продукты одной фирмы будут прекрасным примером реализации доставки сообщений), вариант с общей подпиской выгоден при стыковке сильно разнородных систем (практически все стандартные протоколы: MAPI, TAPI и т.п.)
Но, в целом, особой разницы между ними нет, скорее это разграничение на количество каналов, по которым общаются система источник событий и система потребитель событий - если канал 1, то у нас вариант с общей подпиской, если несколько, то мы скорее всего имеем вариант с целевой подпиской. И выбор какой из этих 2-х вариантов реализовывать больше дело вкуса.
Примером варианта с целевой подпиской может служить реализация доставки событий в COM, а примером с общей подпиской - WinAPI.
При предоставлении дополнительной информации сейчас наибольшее распространение получили два подхода:
Причины приведённые выше будут влиять на архитектурные решения, какой из вариантов выбирать: вариант с целевой подпиской выгоден в пределах одной системы и нескольких подсистем(продукты одной фирмы будут прекрасным примером реализации доставки сообщений), вариант с общей подпиской выгоден при стыковке сильно разнородных систем (практически все стандартные протоколы: MAPI, TAPI и т.п.)
Но, в целом, особой разницы между ними нет, скорее это разграничение на количество каналов, по которым общаются система источник событий и система потребитель событий - если канал 1, то у нас вариант с общей подпиской, если несколько, то мы скорее всего имеем вариант с целевой подпиской. И выбор какой из этих 2-х вариантов реализовывать больше дело вкуса.
Примером варианта с целевой подпиской может служить реализация доставки событий в COM, а примером с общей подпиской - WinAPI.
При предоставлении дополнительной информации сейчас наибольшее распространение получили два подхода:
- мы передаём все данные о произошедшем событии в функцию обработчик события, надеясь, что разработчику будет в дальнейшем этого достаточно.
- мы ничего не передаём, кроме собственно самого извещения, что событие произошло - с надеждой что разработчик получит всю нужную ему информацию сам.
А вот в этих-то зарослях и спрятаны основные грабли:
В варианте №1 ОЧЕНЬ часто забывают добавить константность для передаваемых параметров. И тогда следующий зарегистрированый обработчик может получить отнюдь не то, что ожидалось. И вообще, строить механизм вычислений с помощью обработчиков событий - не совсем хорошая идея ;)
Ещё одни тщательно разбросанные грабли (особенно их часто можно увидеть в КОМе) - это параметр, который контролирует будет ли отправлено сообщение следующему обработчику. Единственный вариант, когда это необходимо - это ситуация когда, событие в системе должно быть обработано не больше 1-го раза. В общем же случае, когда разработчик не знает кто зарегистрировался до/после него для обработки события, этот аргумент становится бесполезным или даже вредным - ибо становится возможным поломать поведение не только своей системы или системы источников событий, а и сторонних систем (на такие случаи мне везло в плагинах к Ворду :( ).
А самые заботливо укрытые грабли лежат в в варианте №2, когда общение между системой источником и системой потребителем идёт по 1-му каналу - заботливо укрывает эти грабли тот факт, что их не видно в однопоточном приложении. Но вот если в системе крутится несколько потоков, причём два и больше потоков могут отправлять события, то тут всё и начинается.
Пример:
В варианте №1 ОЧЕНЬ часто забывают добавить константность для передаваемых параметров. И тогда следующий зарегистрированый обработчик может получить отнюдь не то, что ожидалось. И вообще, строить механизм вычислений с помощью обработчиков событий - не совсем хорошая идея ;)
Ещё одни тщательно разбросанные грабли (особенно их часто можно увидеть в КОМе) - это параметр, который контролирует будет ли отправлено сообщение следующему обработчику. Единственный вариант, когда это необходимо - это ситуация когда, событие в системе должно быть обработано не больше 1-го раза. В общем же случае, когда разработчик не знает кто зарегистрировался до/после него для обработки события, этот аргумент становится бесполезным или даже вредным - ибо становится возможным поломать поведение не только своей системы или системы источников событий, а и сторонних систем (на такие случаи мне везло в плагинах к Ворду :( ).
А самые заботливо укрытые грабли лежат в в варианте №2, когда общение между системой источником и системой потребителем идёт по 1-му каналу - заботливо укрывает эти грабли тот факт, что их не видно в однопоточном приложении. Но вот если в системе крутится несколько потоков, причём два и больше потоков могут отправлять события, то тут всё и начинается.
Пример:
Есть система с 2-я потоками, каждый из которых изменяет некоторую структуру данных в памяти, в целях потокобезопасности доступ к структуре закрыт критическими секциями, события отправляются после каждого изменения, но в целях быстродействия отправка событий сделана асинхронно. Потребитель событий должен забрать данные из этой же структуры данных - доступ опять же организован безопасно. На события подписан только 1 потребитель. В определённый момент времени происходит следующая ситуация: поток1 получил доступ к данным, успешно их поменял и отправил извещение, что он закончил работу; поток2 со спокойной цифровой душой получает доступ к данным, тоже их изменяет и тоже отправляет сообщение "всё ок - принимайте данные". Потребитель событий начинает забирать даныые по 1-му отправленому извещению, но то ли такт процессорный неудачно лёг, то ли sleep студент поставил, ну в общем не успел забрать данные до того как поток2 их изменил. И вот что делать в такой ситуации? - событие мы обрабатываем мы ещё 1-е, а данные уже лежат для 2-го события.
Т.е. у нас классический Data Race заботливо подготовленный системой, которая отправляет события.
Решить эту ситуацию можно сделав структуру данных, к которой имеют доступ источник событий и их потребитель, неизменной для потребителя пока он не закончит обработку события - это либо передавать в виде параметра в функцию обработчик (на что никто не пойдёт, т.к. сигнатура функций не менялась уже лет 10), либо блокировать доступ к структуре данных пока все обработчики не закончат, на что опять же никто не пойдёт - т.к. это существенно замедлит работу основной системы.
Уменьшить вероятность проблем можно запустив отдельный поток, который будет обрабатывать сообщение и копировать структуру данных как можно ближе к моменту запуска сообщения. А функции-обработчики событий будут работать как в варианте №1. Но это не решит саму проблему с подходом №2 - просто уменьшит вероятность возникновения Data Race.
Выглядит описанная ситуация довольно надуманной, но это описание работы с реализацией TAPI от Cisco. :(
Как общее итого
не лениться и гонять всю необходимую инфу через параметры события - граблей меньше и они значительно менее опасны.
Уменьшить вероятность проблем можно запустив отдельный поток, который будет обрабатывать сообщение и копировать структуру данных как можно ближе к моменту запуска сообщения. А функции-обработчики событий будут работать как в варианте №1. Но это не решит саму проблему с подходом №2 - просто уменьшит вероятность возникновения Data Race.
Выглядит описанная ситуация довольно надуманной, но это описание работы с реализацией TAPI от Cisco. :(
Как общее итого
не лениться и гонять всю необходимую инфу через параметры события - граблей меньше и они значительно менее опасны.
Labels:
умные мысли
пятница, 13 ноября 2009 г.
Результаты October 2009 ISO C++ Standards Meeting
Общее итого: Афигеть!
Теперь по пунктам:
1. Стандарт так и не был не утверждён, и большая часть встречи была посвящена закрытию "тёмных углов". - Это понять можно. При этом, опять же, закрыли не все проблемные места. - А вот это уже понять сложно, т.к. разработчики C++ компиляторов уже начали наступать на эти грабли (для примера можно посмотреть объяснения от MS VC++ Team - почему они в срочном порядке доделывали null_ptr в своей бете2 студии 2010).
2. Следующая встреча в марте 2010 года. Посвящена будет оставшимся проблемным местам в стандарте. Вот не понял, зачем было откладывать на полгода - что ещё осталось шлифовать? Ладно, я ещё могу понять Python с их PEP3003, ибо надо чтобы альтернативные реализации догнали основную и наиболее популярные библиотеки вышли уже с поддержкой Python3. Но что хочет дождаться комитет для C++ - просто не понимаю...
3. Они умудрились потерять главного, по их же словам, организатора и текущего председателя комитета P.J. Plauger, который к тому же был самым опытным среди них во взаимодействии с ISO. При этом он не выдержал обычного 3-хлетнего срока - вот это понять даже сложнее, чем просто уход с поста председателя из-за перевыборов. О замене даже не договорились, хотя вызывается добровольцем Саттер, как председательствовавший предыдущие 2 срока. Но это немного не тот человека из-за того, что активная фаза создания стандарта уже закончена и надо заниматься политикой, а не разработкой.
С учётом вышеизложенного, текущих темпов, того, что на мартовской встрече понадобится закрыть баги и неясности, которые остались открыты после этой встречи, и если будет предложение очередной "новой маленькой" фичи, то как бы стандарт не стал C++0xB или даже C++0xC. Хотя в последнем есть своя суровая гармония. :(
P.S.
В этом свете, хорошо, что выбросили концепты. Плохо, что их не выбросили раньше и потратили на них время, которое могло быть потрачено с большей пользой на что-то другое. Хотя концепты, конечно, очень жаль именно как идею и то, что за ней стоит.
Labels:
c++
среда, 21 октября 2009 г.
Блог Саттера: Опрос
Герб Саттер проводит опрос на тему: какие темы в конкурентном программировании на C++ осветить в дальнейших постах. You're welcome to participate.
В целом его блог для программистов на C++ из набора "очень желательны к ознакомлению". А цикл статей "Effective Concurrency" - это уже из набора "обязательных к прочтению", - 90% вопросов, которые возникают в процессе работы и на собеседованиях уже освещены.
Очень советую к прочтению.
P.S.
Вот и как на русский перевести правильно concurrency programming?.. Многопоточное и конкурентное программирование это всё же другие оттенки смысла.
В целом его блог для программистов на C++ из набора "очень желательны к ознакомлению". А цикл статей "Effective Concurrency" - это уже из набора "обязательных к прочтению", - 90% вопросов, которые возникают в процессе работы и на собеседованиях уже освещены.
Очень советую к прочтению.
P.S.
Вот и как на русский перевести правильно concurrency programming?.. Многопоточное и конкурентное программирование это всё же другие оттенки смысла.
Labels:
c++
четверг, 15 октября 2009 г.
Сортировки и сборки...
В http://www.reddit.com/r/programming/comments/9jj5z/vladimir_yaroslavskiys_dualpivot_quicksort/ прочитал об улучшении классического quicksort'а при помощи добавления второго опорного элемента. Автор показывает, что для худшего случая время работы получается на 20% лучше, чем у стандартной реализации.
Меня это заинтересовало. Да и захотелось сравнить с другими сортировками, а то использую в рабочем коде только обощённый метод из стандартной библиотеки C++, а в быстрых поделках на колене - шеловскую сортировку (настолько к этому сочетанию уже привык, что кажется - подними с кровати, напишу использование на полном автомате, не просыпаясь).
Для сравнения были выбраны следующие сортировки: реализация quicksort'а в лоб без каких-либо улучшений, реализация quicksort'а с использованием сортировки вставкой на малых массивах, dual pivot quicksort, sort из стандартной библиотеки C++ (чтобы был наглядней результат), quicksort из C runtime(насколько я понимаю, тут используется реализация из стандартной библиотеки C) и сортировка Шела с шагами 2^n -1.
Измерения проводились на векторе в 5 миллионов int'ов. Использование обощенного контейнера было основано на необходимости использовать в сравнении обобщённый sort из стандартной библиотеки C++. Среди контейнеров же был выбран вектор, т.к. хотелось посмотреть на результат qsort из C Runtime Library.
Измерения выполнялись в MS VC++2005.
Результаты получились, мягко говоря, странными.
Labels:
c++
понедельник, 28 сентября 2009 г.
Unicode - Питон, PyQt, XML
В процессе написания небольшой тулзы для себя столкнулся с граблями при чтении/записи unicode строк полученых из QT-ишного элемента управления в xml и назад. Полдня потратил на раскапывание причин и борьбу с ними.
Labels:
python
суббота, 26 сентября 2009 г.
No Time for JAVA
Конечно, вещь известная, но не могу удержаться :)
Lyrics by Herb Sutter
I've tried Pascal, time after time
I've done my COBOL but committed no crime
C pointer mistakes, I've made a few
I've had my share of Lisp and Haskel and Scheme but I still haven't a Clu
(and on and on and on and on)
We are the champions, O Bjarne!
And we'll keep compiling till the end
You've made us champions, we are the champions
No time for Java 'cause we are the champions
Of the world!
I've taken my macros, and my function calls
I've enjoyed speed and performance and everything that goes with C, I love them all
But C's been no bed of roses, and Ada's no pleasure cruise
I want abstraction and optimization both, so I ain't gonna use...
(and on and on and on and on)
I've tried Pascal, time after time
I've done my COBOL but committed no crime
C pointer mistakes, I've made a few
I've had my share of Lisp and Haskel and Scheme but I still haven't a Clu
(and on and on and on and on)
We are the champions, O Bjarne!
And we'll keep compiling till the end
You've made us champions, we are the champions
No time for Java 'cause we are the champions
Of the world!
I've taken my macros, and my function calls
I've enjoyed speed and performance and everything that goes with C, I love them all
But C's been no bed of roses, and Ada's no pleasure cruise
I want abstraction and optimization both, so I ain't gonna use...
(and on and on and on and on)
Labels:
c++
Подписаться на:
Сообщения (Atom)