суббота, 4 февраля 2012 г.

2012… Год тихой смерти?

И чего же я на Озоне аж 6 лет не появлялся!?! На картинке слева отображена история моих заказов на Озоне… Славный путь, не правда, ли? Только где это я был с 2006-го по 2012-ый?!?

А был я в Books.ru. Как-то случилось, что в далеком 2006-ом мне пришлось заказать книгу именно на books.ru. Уж не помню почему, но какие-то геморройки вышли с Озоном. Ну пришлось, и пришлось. Суть не в этом. В Books.ru я влюбился с первого взгляда. Мне катило абсолютно всё: отличнейший рубрикатор по книгам, возможность полистать книжку перед покупкой, явно “живые” отзывы, гутно работающая служба доставки и много чего другого. Чего только стоила новостная рассылка, это просто слов нет. Можно подписаться не просто на книги, не просто по разделам “детективы”, “про баб-с” и “профессиональная литература” – а выбрать более чем конкретизированные разделы в computer science: что-то вроде “операционные системы” и “языки программирования”, а вот самоучители по Ворду нафиг. Удобно не правда, ли?

Верните кнопку, всё прощу! Но недавно books.ru учинили редизайн сайта. Много чего работало криво, многое и не работало. Ну да ладно, один переезд стоит трех пожаров. Дело-то житейское. И баг-репорты админам писал, и мнения высказывал, в общем помогал любимому магазину как мог.

Но отчасти воз и поныне там. Товар есть – кнопка “В корзину”. Товара нет – картинка “Нет в продаже”. Где нафиг блин епрст полгода прошло кнопка “Сообщить о поступлении” рядом с товаром?  Ведь раньше на старом сайте была же? Так сложно сделать? Робяты! Books.ru! Вы теряете не просто клиентов, вы начинаете терять уже фан-клуб, а это о чем-то да говорит. Ну прям хоть сам иди прикручивай кнопку к вам на сайт. Верните кнопку, черти!!! Нужна помощь? Нивапрос ©! Все что в силах: код, UX-тестирование, UC-анализ. Просто так. Из симпатии к вам.

PS: а попробуйте угадать, откуда на Озоне появился вдруг заказ в 2012-ом? Ага. Точно, вот у них кнопка “Сообщить о поступлении” была. Они  и сообщили. Поэтому заказ и у них же, а не у books.ru. И это при том, что я с-о-о-овсем, мягко говоря, не в восторге от Озона. Ибо где француз прошел, цыг… всем остальным делать нечего!

пятница, 3 февраля 2012 г.

Про сериализацию в MFC

Сегодня про сериализацию, в частности в библиотеке MFC. Описанные ниже приемы — мой личный, опробованный на собственной шкуре опыт. О таком в MSDN, да в книгах не пишут. А зря, мль, зря… Почти все приемы выстраданы в конкретном проекте — в частности в Aml Pages. И большая их часть в ней и реализована. А некоторые нет, и я искренне весьма дюже сожалею о тяом, что допер до них слишком поздно.

На КЫВТ.ру поднимался вопрос о сериализации. Отвечал. А теперь рискну оформить наломанные мною копья в виде поста. Основной посыл этого поста, что человеку свойственно ошибаться. Ошибались, ошибаемся и ошибаться будем. И главное, всего в развитии проекта мы предвидеть не можем. Ну и собственно как можно всевозможные грабли обходить с сериализуемыми объектами.

Итак, MFC поддерживает класс CArchive для сериализации, который позволяет писать-читать из файла (хотя и не только), практически любые типы данных. Все стандартные классы MFC легко читаются\пишутся конструкциями вида CArchive<< и CArchive>>. Грабли начинаются уже потом, при развитии проекта. Именно когда объекты абстрактной софтины получают новые сериализуемые поля, или строковые данные могут быть в разных кодировках, или еще как.

1. Используйте номер версии архива

Используйте версионность CArchive. Смотреть на макрос IMLEMENT_SERIAL+VERSIONABLE_SHEMA. Суть проста: записывайте в CArchive сначала номер формата архива, а только потом сами данные. В дальнейшем это позволит сделать чтение архивов совместимым снизу вверх. Если в первой версии архива (файла), у нас записывались int+CString, а во второй int+CString+еще_int, то сериализация будет выглядеть так:

… Serialize(CArchive& ar)
{
if (CArchive::IsStoring()) {//запись архива
ar<<2;//записали номер формата — в данном случае вторая версия архива
ar<<My_int;//понеслась запись данных
ar<<myString1;
ar<<My_Int2;
}
else {//чтение
int nArchiveFormat;
ar>>nArchiveFormat;//читаем номер архива
ar>>My_int;//первый int
ar>>myString1;//первый CString
if (nArchiveFormat >=2)//если мы читаем архив второй версии, то считываем второй инт. Если архив второй или старше  версии, то читаем второй int — иначе пропускаем.
ar>>My_Int2;
}
}

Надеюсь, идея понятна. В зависимости от номера версии архива на лету решаем, какие данные в нем есть и их нужно читать, а каких нет, т.к. архив старой версии.

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

2. Сериализуйте BOOL-переменные как битовую маску

Если в сериализуемом объекте у Вас есть набор булевых (BOOL)переменных, некоторых флагов, описывающих какое-то состояние, то не стоит их писать в архив последовательно. Не стоит писать нечто вроде CArchive<<boolFlag1<<boolFlag2<<boolFlag3; И дело тут вовсе не в экономии байтов.

Представьте себе, что в следующих версиях какие-то булевые переменные исчезнут из объекта, а какие-то добавятся. Соответственно, должен и измениться формат архива.  Вот блин, досада. И только из-за этой мелочи, как советовал выше, придется городить новый формат архива? Который не прочтут старые версии? Ан фиг! Эту проблему можно обойти. Решение простое: записывайте все флаги единой битовой маской. Нечто вроде такого:

DWORD dwBitMask=0;
enum {FLAG1=1, FLAG2=2… и.т.д.};
if (boolFlag1)
dwBitMask|=FLAG1;
if (boolFlag2)
  dwBitMask|=FLAG2;

и уже именно битовую маску dwBitMask записываем в архив. Какие плюсы? Обратите внимание, что во первых мы обошли проблему версий архивов. Появление или добавление нового флага BOOL не влияет на версию архива — все равно у нас пишется и читается DWORD.

Во-вторых, есть и еще весьма приятный бонус! Старая версия программы, которая не поддерживает каких-либо флагов из новой версии, не только корректно прочтет архив новой версии, но и запишет его обратно неизменным. Для этого необходимо, чтобы битовые маски не создавались и парсились на этапе записи\чтения, а именно в виде подобной маски и хранились в объекте. Тогда старая версия всегда одинаково прочтет битовую маску. Но булевый флаг, который появился у нас в новой версии она оставит неизменным. Как считает, так и запишет.

Согласитесь, движение в сторону совместимости сверху вниз это уже неплохо. У этого приема есть пара деталей, но это уже подробности и если нужно опишу их в другом посте. Как использовать битовую маску для хранения в объекте в runtime писать не буду — не об том пост.

3. Не сериализуйте строки как есть

Не реализуйте сериализацию строк, как предлагает в примерах по MFC. Не используйте в лоб запись и чтение вида CArchive<<myString и CArchive>>myString. Поясню почему. CString в MFC инкапусулирует или Unicode-строку, или ANSI-строку — в зависимости от настроек компиляции (MBCS|Unicode). Поэтому стандартная сериализация полностью полагается на внутренности CString. А оно нам надо? Всё, робяты! 90-ые давно прошли — на дворе 21-век. Нет просто строк, есть последовательности с завершающим нулем. Но вот в какой кодировке могут быть конкретные строки — выбирай на вкус. Хотите ANSI, хотите UTF8, хотите Unicode.

Простой случай: а допустим в CString у нас хранится HTML-код… HTML-код… Он такой… Он вообще может быть в какой угодно кодировке. Так что имеет смысл делать сериализацию CString ручками, записывать и кодировку, и длину, и только потом непосредственно поток байтов. Зато потом прочтете без проблем, в любой версии софтины. Поверьте на слово, то что кажется неважным в начале проекта, потом в развитии может вызвать очень большую головную боль.

Ну вот, собственно, некоторые несложные приемы сериализации. Есть конечно и еще детали, и еще подробности. А деталей хватает. Начиная от корректной реакции софта на попытку прочтения новой версии архива, и заканчивая, ситуцией, когда MFC-программа, скомпилированная как MBCS читает архив записанной UNICODE версией, или наоборот. Есть там нюансы, и именно в них весь дьявол. Но о них как-нибудь в другом посте.

среда, 1 февраля 2012 г.

Google Code Prettifier : Проверка связи

Попробуем-ка новую подсветку синтаксиса онлайл. Руководство здесь

Ну, а теперь код двухплюсовый.

#include «stdio.h»

bool condition=true;
while (condition) {//вечно, нах!
printf(“Hello, Code Prettifier”);//здарова, млин!
}


Сработало?

четверг, 26 января 2012 г.

Юзабилити. Про трей

Эх, давненько я не брал в руки шашки… Но лучше поздно, чем в штаны!

Напишу-ка я про не очень-то очевидную фичу в работе с треем. Для закваски пронзительная история, она же быль. Повадился у меня последнее время падать Проводник Windows. Падает как заведенный, впрочем при определенных обстоятельствах, но ни о них речь. Проводник после креша  сам перезапускается, но по ходу его перезапуска некоторые софтины в трее не восстанавливаются. Если с каким-нить TypeAndRun это пофиг — убил, и запустил заново, то софт с пользовательскими данными убивать через менеджер процессов уже не хочется. "Че-то я ачкую…" ©. Скажем, к примеру, рухнувшая база данных какого-нибудь The Bat может весьма и весьма попортить крови.

Способов решения проблем с упавшим Проводником, и как следствие, пересоздающейся на лету панели задач есть. Как вариант, ловить сообщение TaskBarCreated и восстанавливаться в трее, есть и другие.
Но есть способ элегантнее, надежнее, а главное комфортнее для пользователя. Приложение, свернутое в трей показывается в списке окон по Alt+Tab.

Это решение зарекомендовало себя просто великолепно.

  • Даже после пересозданной панели задач приложение в любом случае показывается в Alt+Tab списке.
  • В штатном режиме – безо всяких падений Проводника – пользователь в любой момент имеет возможность поднять приложение из трея клавиатурой, а не только мышкой. Выбираем окно из списка  Alt+Tab – приложение поднимается из трея. Для законченных гиков, которые при работе касаются мыша разве что чашкой кофе, это весьма и весьма немаловажный нюанс.

Как показал опыт, для приложений оперирующих пользовательскими данными, возможность подняться из трея с помощью клавиатуры почти обязательна для реализации. Сделал такое в Aml Pages. И ох сколько раз оно меня выручало. Нет слов! Про удобство молчу — у меня самого мышь все больше "для комплекту".

PS: кода вставки в список Alt+tab пока не дам. Потому как  жмот я. Потому как, пока доводил до ума добавление окон в список Alt+Tab, такой херни наворотил, что сам уже с превеликой тоской зрю в свой код. Ревьюить его, ревьюить и еще раз ревьюить.

Если в двух словах. Для окон верхнего уровня задача решается элементарно: нужно при прятке окна создать для него дочернее WS_OVERLAPPED-окошко, и задвинуть его за края экрана. А по активизации последнего из Alt+Tab-списка уже поднять из трея основное скрытое окно.

Но заморочки начинаются, когда необходимо добавить в Alt+Tab тул-окно (окно со стилем WS_EX_TOOLWINDOW).Вот пока реализовывал эту возможность и наворотил говно-коду. Теперь сначала причесать код нужно, а уж только потом "в народ". Так что сорсы как-нибудь позже. А уж если кому невмоготу да срочно — стучите в комменты.

среда, 30 ноября 2011 г.

Про BitsDuJour.com: опыт, впечатления, подробности

Поимел опыт сотрудничества с сайтом BitsDuJour.com. Выкладывал там Aml Pages и Aml Maple. В целом очень приятное впечатление, на пять с плюсом! Итак, как это работает: заводим аккаунт на BDJ, предлагаем софтину, указываем скидку и ждем ревью от администратора. В течении пары дней придет ответ от администратора. И если софтинка принята, то назначается дата акции, обычно через недельки полторы.

Ну, а теперь поподробнее о некоторых не столь заметных, но немаловажных деталях. Первое: многие ошибочно считают, что двигать софтину нужно через предложения на BDJ здесь. В принципе да, но это не совсем так. Эта страница предложений, где посетители голосуют за предложенные софтины. Оно, конечно, хорошо, местами даже ахуенно. Но всплеска голосования там особо не видно. И главное, к админам BDJ эта страница имеет мало отношения.

Практически нужно идти несколько иным путем. А именно: топаем на сайт http://www.softwaremarketingresource.com и заводим там девелоперский аккаунт. И уже в этом аккаунте добавляем наши софтинки. Вот этот сайт, как раз имеет отношение к админам BDJ. Поясню: после того, как я запостил свои предложения именно туда, ответ от BDJ пришел буквально в течении пары дней, в отличие от голосовалок. Голосовалки, по моему, вообще мало общего имеют с реальной картиной – нужна ли юзерам конкретная программа. Ну что вы хотите!?! Публичная деятельность она и есть публичная деятельность. Понятно, что раскрученные софтины вроде Total Commander, WinRAR и прочий бренд всегда будут хотеть больше желающих, просто потому, что их знают больше народу.

Теперь подробнее. После того, как предложили софтину, указываем скидку на нее, которая действует в день акции. Имеет смысл не жмотиться, и давать скидку поприличнее в десятки процентов. Все таки BDJ это скорее продвижение продукта, нежели баблостригло, хотя и не без него.

После того, как будет принято ваше предложение, необходимо дать аффилиатскую комиссию BDJ (они точно работают с Plimus`ом, про остальные лучше поинтересоваться  у них). Один момент: комиссия BDJ достаточно большая – 50 процентов. Итого, если, к примеру, даете скидку в 50 процентов, то получите де факто 25 процентов от нормальной цены минус комиссия регистратора. Формула простая: минус 50 процентов скидки изначально, итого остается 50 процентов. От них уже минус 50 процентов самим BDJ, итого в результате вам остается 25 процентов. Так что, обращаем на это внимание, когда начинаем мышленно подсчитывать сказочные барыши.

Отдельно про Плимус: 1) ID аффилиата на Плимусе у BDJ хрен найдешь, называется. А именно Iconico. Хотя в скобках видно, что это именно BDJ. Но поначалу на этом можно малехо поспотыкаться. 2) В админке у BDJ есть отдельная видюха, как организовывать промоушн акции на BDJ в админке Плимуса. Видео старое, но многие вопросы снимает. Рекомендую взглянуть.

Желательно:

  • Иметь для софтины шотбокс (изображение коробочки с продуктом) и отзывы пользователей. У меня как-то так и не оказалось. Но если нет шотбокса, то можно из админки BDJ через веб-сервис сделать (один раз точно на халяву).
  • Стоит внимательно прочесть лицензионные соглашение, которые указываются в админке. Там масса деталей: манибек, активация софтины, политика апгрейдов, ватермарки с железа, возможность копирования софтины на другой комп и.т.д, и главное где-то стоят галки по умолчанию. Как оказалось, судя по комментариям посетителей к акции, для большинства западных пользователей эти лицензионные детали вовсе не пустой звук. Это не наше ворюшканье – на такие вещи там обращают внимание, и не самое последнее. Так что будьте внимательны.

Впечатления и опыт:

  • Работать с BDJ более чем приятно. Админ – Constantin Florea – ахуенский отличный профи. Общаться с ним одно удовольствие. К слову, помогает со скриншотами, которые BDJ берет только в JPEG. Не поленился сам перегнать их из моего GIF. Причем я отправил ему исключительно адрес веб-страницы. Дык Constantin сам все скачал, и перегнал. Это к тому, что не ленивый там народ админы.
  • Описание программки BDJ готовит сам. Безусловно, какие-то материалы ссылки, дать им нужно. Но описание реально новое, с нуля. Рекомендую перечитать его до начала акции, иногда появляются неточности, помарки. Правятся оные быстро – просто отпишите свои замечания.
  • Отдельное впечатление от стиля общения. Здесь вам не сраный Плимус, и тут вы не услышите “sorry, i dont understand You”. И это-то несмотря на мой “рязанский” английский! Могут, когда хочут. Плимус, ау? Когда вы выпиздите с работы своих непонятливых сотрудничков, которые явно наняты по часам. “Как размеренно гребет старый лодочник, особенно если он нанят по часам” (© Дж. К. Джером)
  • Аудитория у BDJ в основном западная. Но не скажу что прямо-таки англоязычная. Конечно, Штатов много. Но был приличный процент покупок и из Европы.
  • Отдельно удобно: по емейлу вас извещают о ходе подготовки акции. Можно посмотреть, как будет выглядеть страница вашей софтины еще до начала. Не беспокойтесь, до старта эта страница будет доступна только вам и админам.
  • Приготовьтесь ко дню акции. В этот день может посыпаться куча комментариев. Я вот первую акцию пробухал пропустил, и отвечал уже пост-фактум. Не лучший вариант с моей стороны.
  • Имеет значение: ваша софтина пойдет отдельной акцией или в виде бандла с кучой других софтин. Моя Aml Pages шла отдельной акцией. Мапля шла в бандле. Профит что так, что эдак. Но, конечно же, для отдельной акции профит был значительно выше.
  • После окончания акции можно просмотреть статистику в админке. Как оно было: кто, откуда, почем конверсия и.т.д.
  • Время действия купона нужно выставлять не буквально на один день. Лучше больше, на пару-тройку дней – просто из-за разницы в часовых поясах. А разница приличная, все-таки Штаты. По московскому времени акции стартуют в 12 часов дня, и заканчиваются опять же в 12 дня.
  • После окончания акции имеет смысл задать “вечный” купон, но со скидкой поменьше . Ну, скажем,  процентов в 25. Страница самой акции остается доступной для посетителей, и в принципе может что-то приносить и после. Главное: как обещает BDJ, в дни когда у них нет запланированной акции, такие уменьшенные акции могут включаться в анонсы. Ну то бишь: в какие-то дни BDJ крутит конкретные акции, а  в какие-то выталкивает старые, с меньшими купонами. Вышеупомянутая 50 процентная комиссия для BDJ также обязательна и для уменьшенного “вечного” купона.
  • Целесообразно задавать вопросы админам, если софтина была отклонена в первый раз. К примеру, мою Маплю в первый раз отклонили, но сразу одобрили Aml Pages. Я так понял, что “Пагесы” произвели лучшее впечатление на BDJ, чем “Мапля”. Но после того, как закончилась первая акция, я поинтересовался у админов, почему отклонили Маплю и предложил варианты. Оп-па и все ОК, согласились. Через неделю, другую запустили в промоушн и Маплю.
  • Аудитория у BDJ достаточно сильно, имхо, отличается от GAOTD. На BDJ – гики и достаточно продвинутые пользователи. На GAOTD, в основном хомячки, частенько малограмотные. Безусловно, есть и исключения. (поклонники GAOTD: не надо матов, и не принимайте близко к сердцу. Такое впечатление от GAOTD складывается из комментов. А сами знаете, кого лучше всех слышно в этих комментах. Проще говоря: кто громче воняет, всем известно).
  • Но на BDJ бывают и тролли. Был один пиздабол в акции про Пагесы. Сам задал вопрос, сам на него ответил, а потом еще врал где ни попадя, включая диспуты на Плимусе, что ему обещали такую-то фичу (именно про нее он спросил, сам себе и ответил, что она может быть есть). Ну что сказать!?! Ну куда ж без этих уёпков? Забейте! В семье ни без уродов. Или отклонить ордер, или отрефайндить его если уже прошел, и не тратить себе нервы. Отдельно про Плимус: спасибо вам и низкий поклон! Вы не только не помогли мне в том диспуте, вы еще и проблем добавили. Не зря вас хуями на RSDN регулярно кроют, и уже откровенно обвиняют в мошенничестве).
  • Вообще BDJ производит значительно более приятное впечатление чем GAOTD. Всегда ответят, всегда помогут. GAOTD это “партнеры” какие-то – отклика от них дожидаться можно весьма долго.

Ну, как-то вот так. Хотелось рассказать об опыте. Впечатлений много, все сразу расписать не могу, т.к. русские буквы помню уже плохо :). А посему и получилось в несколько телеграфном стиле. Ну да ладно, будут вопросы, интерес у народа  – напишется и еще пост.

PS: сори, конечно, за маты в направлении Плимуса. Но а) наболело б) заебали толку от них ноль: поддержка молчит, фрод-чек работает… да никак он не работает (фродов на тыщу баксов в неделю, это как называется?) в) достучаться до них можно только через КЫВТ.ru, когда их там публично кроют г) всерьез задумался, а не послать ли Плимус. А если эмоции в сторону: господа из Плимуса – это не работа! Вы мешаете больше, помощи от Вас ноль. Задумайтесь! Если все, что Вы можете, это процессить кредитки за комиссию, то вы далеко не оригинальны. Это кей-фичей уж точно никогда не будет.

четверг, 17 ноября 2011 г.

Про Плимус

Plimus Навсегда! Чем больше я последнее время работаю с Plumus, тем больше я люблю собак :(.А то …… Во-о-о-от!

PS: © картинки Демотиваторы