Note Bene: особливо на этапе проектирования!
Ярлыки для себя на будущее: Aml Pages, асинхронный импорт рисунков веб-страниц, многопоточный причем, мудренная синхронизация… Ни-и-и-ичче просто не понадобилось.
Блог о shareware и разработке программного обеспечения
Крик души. Ибо больше “не можу”.
Начну с цитаты “Приложения продолжают наполнять нашу жизнь – от утреннего будильника и карты пробок до общения с друзьями и презентаций на работе. Рынок платформ и приложений продолжает расти, а многообразие новых устройств и партнерств между игроками рынка рождает новые тенденции и возможности. И конечно, все это открывает новые пути для успеха разработчиков, в том числе на глобальном уровне…”
Это цитата из MSDN`овской рассылки. Млин, целый абзац какой-то мутной непонятной воды. И это в письмах направленных разработчикам. Мы кагбэ профи!?!
“Приложения продолжают наполнять нашу жизнь – от утреннего будильника и карты пробок …” Охиреть, какая новость. Только сейчас узнал!!!
“Рынок платформ и приложений продолжает расти…” Вот это открытие, какое тонкое наблюдение!
“И конечно, все это открывает новые пути для успеха разработчиков, в том числе на глобальном уровне…” Да ты че? Серьезно? (С)
Блин, ну не могу молчать. И так в каждой рассылке. В каждом письме, прежде чем добраться до сути, я вынужден пролистывать несколько абзацев какой-то откровеннейшей херни. Кому она адресована? Подростковым обитателям Зимбабвийской деревни, которые впервые услышали о hi-tech только вчера? Или профессионалам, которые зачастую побольше авторов подобных письменов понимают.
Для кого это написано? Всерьез подумываю и вовсе отказаться от MSDN`овской рассылки. Ибо Реймонды Чены да Спольски там больше не пишут. Зато ПТУ`ушников набрали новых, но безмозглых, даже не удосужившихся призадуматься на тему к кому они обращаются.
Уже не первый раз пользователи просят написать приложение навроде Aml Pages, но с синхронизацией с облаками – тот же Google Drive или опять же SkyDrive.
В принципе без проблем. И даже наброски есть. Пока в виде прототипа всего лишь. И дописать синхронизацию с каким-нить Evernote не проблема. Уж больно за годы развития самой Aml Pages осознал, сколько труда и времени приходится вгрохать в подобное приложение. Там на один толковый движок уйма сил уйдет. А сколько пользователей – столько и мнений, что нужно, а что нет.
Так стоит ли ввязываться? Может быть здесь и рыбы нет?
Вот у Пастухова в блоге любопытный пост про “эффективность“ vs “правильность”… Навело на мысль, почему у меня никогда не получалось в спорах убедить оппонентов в обоснованности своих взглядов на подходы к локализации приложений. А все просто. Я как-то упускал из виду очевидные (для меня, но видимо не для оппонентов) вещи – эффективность моего подхода.
Все мои доводы направлены на эффективность. А эффективность это соотношение полученных бонусов к затраченным ресурсам. А в таком отношении уже 2 переменные: количество имеющихся ресурсов и прогнозируемый объем бонусов.
Дело в другом. И вот какой фокус. На КЫВТ собеседники начинают как заведенные ссылаться на подходы Microsoft. А им отвечают: “не-а, не пойдетъ“. А все тривиально. Понятно, что чем лучше локализация, тем оно приятственнее. Другой бы спорил. Но фишка в другом. Как ни крути, а ни у кого из нас нет и не предвидится такого количества ресурсов, которые мы можем потратить на локализацию, как у Microsoft. Так что Microsoft`овский подход к локализации у нас с вами попросту не сработает. Ибо как какие бы достижения не оказались бы числителе, но в знаменателе объем потраченных ресурсов будет слишком большим. А посему на выходе будет пшик. Эффективность и именно эффективность будет крайне мала.
Вот и вся загвоздка. Microsoft предалагает “правильно” (причем только для нее правильно). А я “эффективно” :)
Все-таки выложил финальную версию нового проекта – RSSme 1.00. Если вкратце, то это простенький, но визуальный такой редактор RSS-лент. Как-то он не пошел, имхо. Вроде и отзывы в сети попадаются, и качают помаленьку. Однако фидбека практически ноль. Т.е. практически полный ноль.
RSSme писался под себя. Именно для своих нужд. И кстати, именно им и редактирую свои собственные RSS-ленты. Но видимо с затеей RSS-редакторов я немного опоздал. Немного так – лет на 5-7 :). Ну да фиг с ним. Зато освоил HTMLayout с несколько другой стороны. Одно дело простенькое приложение с моднявым интерфейсом настроек – вроде Mouse Hunter. Совсем другое полноценное приложение, где движок HTMLayout не только красивости да рюшечек рисует, а вполне основательно реализует обработку данных.
Чего я только не планировал в RSSme. И встроенный FTP-менеджер, и проверку орфографии, и юзабельнейший поиск, и фильтр постов, и поддержку тегов. Да как-то руки все не доходят. А и фиг с ним. Оставлю на будущие релизы, если к оным будет интерес со стороны “обсчества”.
Вот такой еще один опыт запуска проекта. Который, с таким же подходом как и предыдущем посте – сначала веб-страница, и только потом проект – выхлопа почти не дал. Но с другой стороны, а) академический интерес – вдосталь поковырялся с HTMLayout. И б) проверка в боевых условиях – то бишь нет интереса к проекту, дык фигли в него вбухивать тучу времени? Реализовывать те самые вышеперечисленные вкусности, если профита не предвидится.
Вот такой вот еще один опыт…
Затеял новый проект… TwinkiePaste – вставка часто используемых фрагментов текста, шаблонов и прочей хери куда угодно. Ну не устраивали меня аналоги, и всё тут.
Из любопытного:
Вот такие вот наблюдения, что получается из того, что программа начинает продвигаться, засвечиваться, и вообще как-то обнародоваться еще на ранних стадиях, в бета-, в альфа-версиях…
Предложение работадателя на КЫВТ разработать библиотеку для автоматического обновления программ вызвало небывалое бурление говен…
Еще бы! Только заявленных требований: проверить новую версию, скачать, отправить логи, обновить файлы, забекапить установленные, возможность откатить, режим транзакций, всё кроссплатформенно. И за всё это… 6000 рублёв. По слогам “шесть ты-сяч руб-лей” :). А за это заказчик так и быть выложит всё это в OpenSource да под своим именем. Ага, щаз! Впрочем, я как-то уже писал про авто-обновление.
Только недавно закончил автоматическое обновление для Aml Maple. Большая часть перечисленного выше там есть. Не всё. Но и то вылизывал почти пару недель. Дьявол он в деталях. Что должно быть в информации о версии? Говорить ли пользователю про доступность обновлений? Показывать ли эту инфу прямо сейчас? А вдруг пользователь порнуху кино смотрит, или в блог строчит и не желает отвлекаться? Как проверять обновления в фоне, а показывать информацию несколько позже? Какую крутить рекламу? Добавлять ли новости проекта?
Вот где вся загвоздка, исключительно ориентированная на конкретный проект. А всякая фигня, вроде скачать файл и накатить обновление автоматически – это вообще дописывается за 5 минут. Там-то как раз все просто.
Этот пост всё больше для себя, да и что-то давненько я ни черта не писал и вовсе.
Как-то между делом потихоньку уже больше года разбираюсь с HTMLayout. Презанятнейшая штука! Потихонечку уже два проекта вышли на публику: Mouse Hunter и RSSme.
С Mouse Hunter`ом как раз все просто. Все ж это тулза для мыша, а HTMLayout там только для пробы сил был и применен. На нем написан только интерфейс пользовательских настроек: галки, кнопки, все дела. В самой работе HTMLayout ну никак не используется. Правда, проект тут же ушел в народ: нашлись “умельцы”, которые его локализовали, да и по всей сети самописных статеек про “хантер” начеркано. У самого до локализации руки не доходят, не всё еще продумано.
Ох ну куда ж без этих-то? ?) Конечно же, тут же нарисовались халявщики партнеры. Сраный mail.ru впереди планеты всей! Тут же сперли дистрибутив, подтерлись лицензией и впендюрили в него своих засранных тулбаров. Переписка с мейлрушниками, на предмет “а кто разрешал” как всегда, ничего не дает – переливание из пустого в порожнее. А и ладно! Цыгане – они и в мейл.ру цыгане.
А вот второй проект – RSSme – уже поинтереснее будет. Надоело мне RSS ручками править. А коль так, изваял для себя свой собственный WYSYWYG-редактор. Это уже совершенно другая песня. В RSSme весь редактор постов и управление данными полностью и только реализовано на HTMLayout. Здесь уже не ляпоты ради, а вполне реальные и насущные требования. Но пока проект находится в стадии сугубой альфы. Только создание, редактирование и мимимум возможностей. Но удобство прежде всего. Именно из-за него и начал создавать RSSme. Обшарил всю сеть - абсолютно все RSS-врайтеры просто убили своей убогостью: сплошные модальные диалоги, подтверждения, поля ввода. Больше думаешь, не что писать, а как да куда кликнуть. Больше на заполнение формуляров смахивает. Какое уж тут состояние потока?!? Какой-же это софт для писания хоть и RSS?!?
Сегодня про сериализацию, в частности в библиотеке MFC. Описанные ниже приемы — мой личный, опробованный на собственной шкуре опыт. О таком в MSDN, да в книгах не пишут. А зря, мль, зря… Почти все приемы выстраданы в конкретном проекте — в частности в Aml Pages. И большая их часть в ней и реализована. А некоторые нет, и я искренне весьма дюже сожалею о тяом, что допер до них слишком поздно.
На КЫВТ.ру поднимался вопрос о сериализации. Отвечал. А теперь рискну оформить наломанные мною копья в виде поста. Основной посыл этого поста, что человеку свойственно ошибаться. Ошибались, ошибаемся и ошибаться будем. И главное, всего в развитии проекта мы предвидеть не можем. Ну и собственно как можно всевозможные грабли обходить с сериализуемыми объектами.
Итак, MFC поддерживает класс CArchive для сериализации, который позволяет писать-читать из файла (хотя и не только), практически любые типы данных. Все стандартные классы MFC легко читаются\пишутся конструкциями вида CArchive<< и CArchive>>. Грабли начинаются уже потом, при развитии проекта. Именно когда объекты абстрактной софтины получают новые сериализуемые поля, или строковые данные могут быть в разных кодировках, или еще как.
Используйте версионность 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;
}
}
Надеюсь, идея понятна. В зависимости от номера версии архива на лету решаем, какие данные в нем есть и их нужно читать, а каких нет, т.к. архив старой версии.
По крайней мере, используя этот прием можно гарантировать, что новые версии программы будут корректно читать архивы, созданные старой версией программы. Конечно, старые версии программы не смогут читать архивы новых версий, но хоть совместимость снизу вверх будет обеспечена. Берем с полки пирожок.
Если в сериализуемом объекте у Вас есть набор булевых (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 писать не буду — не об том пост.
Не реализуйте сериализацию строк, как предлагает в примерах по MFC. Не используйте в лоб запись и чтение вида CArchive<<myString и CArchive>>myString. Поясню почему. CString в MFC инкапусулирует или Unicode-строку, или ANSI-строку — в зависимости от настроек компиляции (MBCS|Unicode). Поэтому стандартная сериализация полностью полагается на внутренности CString. А оно нам надо? Всё, робяты! 90-ые давно прошли — на дворе 21-век. Нет просто строк, есть последовательности с завершающим нулем. Но вот в какой кодировке могут быть конкретные строки — выбирай на вкус. Хотите ANSI, хотите UTF8, хотите Unicode.
Простой случай: а допустим в CString у нас хранится HTML-код… HTML-код… Он такой… Он вообще может быть в какой угодно кодировке. Так что имеет смысл делать сериализацию CString ручками, записывать и кодировку, и длину, и только потом непосредственно поток байтов. Зато потом прочтете без проблем, в любой версии софтины. Поверьте на слово, то что кажется неважным в начале проекта, потом в развитии может вызвать очень большую головную боль.
Ну вот, собственно, некоторые несложные приемы сериализации. Есть конечно и еще детали, и еще подробности. А деталей хватает. Начиная от корректной реакции софта на попытку прочтения новой версии архива, и заканчивая, ситуцией, когда MFC-программа, скомпилированная как MBCS читает архив записанной UNICODE версией, или наоборот. Есть там нюансы, и именно в них весь дьявол. Но о них как-нибудь в другом посте.
Попробуем-ка новую подсветку синтаксиса онлайл. Руководство здесь
Ну, а теперь код двухплюсовый.
#include «stdio.h»
bool condition=true;
while (condition) {//вечно, нах!
printf(“Hello, Code Prettifier”);//здарова, млин!
}
Сработало?
Эх, давненько я не брал в руки шашки… Но лучше поздно, чем в штаны!
Напишу-ка я про не очень-то очевидную фичу в работе с треем. Для закваски пронзительная история, она же быль. Повадился у меня последнее время падать Проводник Windows. Падает как заведенный, впрочем при определенных обстоятельствах, но ни о них речь. Проводник после креша сам перезапускается, но по ходу его перезапуска некоторые софтины в трее не восстанавливаются. Если с каким-нить TypeAndRun это пофиг — убил, и запустил заново, то софт с пользовательскими данными убивать через менеджер процессов уже не хочется. "Че-то я ачкую…" ©. Скажем, к примеру, рухнувшая база данных какого-нибудь The Bat может весьма и весьма попортить крови.
Способов решения проблем с упавшим Проводником, и как следствие, пересоздающейся на лету панели задач есть. Как вариант, ловить сообщение TaskBarCreated и восстанавливаться в трее, есть и другие.
Но есть способ элегантнее, надежнее, а главное комфортнее для пользователя. Приложение, свернутое в трей показывается в списке окон по Alt+Tab.
Это решение зарекомендовало себя просто великолепно.
Как показал опыт, для приложений оперирующих пользовательскими данными, возможность подняться из трея с помощью клавиатуры почти обязательна для реализации. Сделал такое в Aml Pages. И ох сколько раз оно меня выручало. Нет слов! Про удобство молчу — у меня самого мышь все больше "для комплекту".
PS: кода вставки в список Alt+tab пока не дам. Потому как жмот я. Потому как, пока доводил до ума добавление окон в список Alt+Tab, такой херни наворотил, что сам уже с превеликой тоской зрю в свой код. Ревьюить его, ревьюить и еще раз ревьюить.
Если в двух словах. Для окон верхнего уровня задача решается элементарно: нужно при прятке окна создать для него дочернее WS_OVERLAPPED-окошко, и задвинуть его за края экрана. А по активизации последнего из Alt+Tab-списка уже поднять из трея основное скрытое окно.
Но заморочки начинаются, когда необходимо добавить в Alt+Tab тул-окно (окно со стилем WS_EX_TOOLWINDOW).Вот пока реализовывал эту возможность и наворотил говно-коду. Теперь сначала причесать код нужно, а уж только потом "в народ". Так что сорсы как-нибудь позже. А уж если кому невмоготу да срочно — стучите в комменты.
На RSDN.ru в форуме по архитектуре программного обеспечения большой аншлаг. Еще бы! Вечные же вопросы задеты: что делать и кто виноват нужны ли плагины в софтине Икс, и как вообще организовать интерфейс плагинов. Всё как-то собирался рассказать, как я проектировал Plugin API для Aml Pages. А главное рассказать миру, какие ошибки допускал, как их исправлял, и на что именно стоит обращать особое внимание.
Но, как водится, если я чего задумал, то выпью обязательно (© В.С. Высоцкий). Выпито достаточно, и естественно, о плагиностроении не написано ни строчки до сих пор. А сказать-то есть чего. Основные архитектурные черты моего Plugin API как раз и описал в посте на RSDN.ru. Но в нем только самые главные черты – взгляд на вещи, а вопросов на самом деле тьма:
В общем, вопросов вагон и маленькая тележка. И все они на 99 процентов будут зависеть от архитектурных решений. Именно их придется продумывать в первую очередь. И неправильные решения в таких вопросах вызовут наибольшие проблемы потом. А проблемы будут! Первая версия моего Plugin API, к примеру, и вовсе ушла в помойку – все пришлось переписать с нуля. Но вот начиная со второй версии, архитектуре Plugin API я уделял максимум внимания – и в той или иной степени она осталась в Aml Pages и поныне. О да, архитектура претерпела ряд весьма значительных изменений. Но все они были пожалуй в сторону развития, а не полного переписания с нуля.
Во-о-о-от, значитъ! Будем считать это первым блин комом. Глядишь, этот пост в последствии и заставит меня все таки рассказать побольше о плагиностроении. Ибо пока сам пишешь, все настолько по полочкам разложишь, что конкретный мозг просветляется Plugin API только улучшается.
Об актуальном. Как-то последнее время начинаю все с большей и большей теплотой относиться к виртуальному режиму списка (ListView). Ощущение полного контроля над списком: что, как и когда он отображает – настолько впечатляет, настолько завораживает, что нет слов. Действительно, код поначалу приходится сильно доводить, продумывать, вникать в детали. Но это только поначалу. Зато потом, возникает устойчивое чувство, что все работает как надо, что код “сверкает всеми гранями и бесконечно совершенен в своей продуманности, последовательности, и определенности”.
А по сути-то, в виртуальном списке всего лишь выполняется старинный программерский завет, она же отчасти первая нормальная форма: “данные должны быть определены единожды и однозначно”. Если задаются какие-то значения, то только в одном единственном месте. Какие данные есть в бизнес-слое приложения, те в ListView и отображаются. А не извечный геморрой: что в конкретный момент времени в ListView де-факто, а что в модели, и в какой момент времени данные должны обновляться в пользовательском интерфейсе, и кем это обновление инициируется...
А уж вкупе с механизмом CustomDraw и вовсе наступает окончательный дзэн. Эмулировать из виртуального ListView дерево-подобный элемент управления, с ветками, и прочей дребеденью, но в довесок со всеми преимуществами списка и вовсе становится элементарно. В общем, буду краток (ц) – прёт!
Все ж прав автор статьи по ссылке выше “Все программисты делятся на тех, кто повсеместно применяет виртуальный режим, и тех…” Попробовав единожды, отказываться от подобных плюшек уже и вовсе не хочется.
А поговорим-ка о резервом копировании. Началось все с поста “Онлайн Backup-сервис” на незабвенном RSDN. Благо проблемы бекапа исходного кода стояли давно. И чтобы более-менее надежно, и не очень дорого, без рутины и быстро. Надежность – без комментариев. Цена само собой вопрос не последний. Быстрота и удобство – последнее по списку, но не по значению. Как только появляется геморрой в создании бекапа, начинаем класть с прибором на этот самый бекап… Со всеми рано или поздно вытекающими последствиями. А посему идеал, это когда клик и готово – бекап сделан.
Заюзал для резервного копирования веб сервис Dropbox.com. Пользуюсь больше месяца. Впечатления отличные: удобно, быстро, надежно и в меру бесплатно.
Схема использования проста как две копейки. 1) Исходный код в архив. 2) Архив в специальную папку синхронизации на диске. 3) А уж специальная тулза от Dropbox.com видит в папке изменения, и закачивает новые данные на сервер. Само собой, особо критичные исходники отправляются в запароленном виде. Приятный сервис, к тому же 2 GB дискового пространства выдаются бесплатно. За большее придется заплатить.
Заодно пришлось поковыряться с этим автоматическим синхронизатором для сервиса. Пользователи давненько просили изваять какой-нибудь плагин для быстрой отправки документов Aml Pages куда-нибудь вовне: е-мейл, внешний сервер и.т.д. А тут все один к одному: и бекап хотелось бы автоматизировать, и пользовательские просьбы, да и всякие фич-реквесты и баг-репорты у меня также и в документах Aml Pages хранятся. Так что в подобном плагине я и сам был заинтересован. Сказано-сделано: изваял плагин Aml2Dropbox. До идеала конечно не доводил: парсинг настроек синхронизатора, архивация в ZIP, да и по мелочам. Но пока работает как часы.
В общем, отличный сервис. Рекомендую.
Ссылка по теме. К вопросу об архивации исходников. Был у меня скрипт для архивации, но больно заточенный под конкретный проект. А вот здесь выложена отличная подборка скриптов для архивации исходников. Скрипты для Windows, но в соседних постах можно найти и для других ОС. Не в качестве рекламы, а дабы каждый раз не гуглить указанный пост заново. Спасибо автору за скрипты. Толково!
Учинил на RSDN голосование “Читаете ли вы диалог "Совет дня" при запуске при запуске приложения”. Результаты вполне репрезентативны – проголосовало уже 132 участника. И вот какая картинка получилась.
| Нет, не читаю | 36% |
| Читаю пару раз, потом выключаю “показывать в дальнейшем” | 23% |
| Закрываю этот диалог “на автомате” | 22% |
| Читаю всегда | 0% (ноль) |
| Читаю иногда, не отключаю | 6% |
| Читаю полностью первый раз, потом отключаю | 5% |
| Читаю очень редко | 1.5% |
| Если есть кнопка следующий, читаю все - потом отключаю | 1.5% |
Результаты я немного округлил. И выкинул некоторые мало интересные, на мой, взгляд, ответы вроде “Я не знаю что такое совет дня” (ответ не в тему, но “слив засчитан” – ибо сам по себе интересен). Но посмотреть точные результаты можно по ссылке выше.
Вот такая вот интересная картина сложилась. 81 (восемьдесят один!!!) процент, условно говоря, вообще не смотрит на диалог совета дня. Или не читает, или пару раз (пока не достал), или закрывает на автомате. Впечатляет, не правда ли? Ходишь в школу, ходишь – бац, вторая смена ©! Как не геморройся с советами дня подавляющее большинство их попросту не читает. Но в любом случае, их никто не читает постоянно. А между тем, подобные советы могут содержать весьма полезную для пользователя инфу, и обучать его ненавязчиво, постепенно показывая ему “рюшечки” в приложении.
А ведь этот пресловутый совет дня должен помогать пользователю, давать ему указания, подсказки. Ан фиг! А почему? Да потому что, не советчик это вовсе, и не заботливый провожатый по приложению – а абсолютно наглый, безмозглый, и совершенно несвоевременный указчик, что делать пользователю да эдак. А пользователь всегда лучше знает, что ему нужно. Обычно затруднения возникают не в цели, а в способах достижения этой цели.
Элементарно, Ватсон. Приложение стартует, и вероятно не само по себе, а по воле пользователя. Разумно предположить, что у пользователя есть свои собственные цели, причем есть прямо сейчас, сию секунду раз уж приложение стартует. А тут на тебе, наставник появился. Да еще и на отвлеченные темы поруководить решился. Совет при запуске не способен угадать цель пользователя, поэтому в 100 из 100 случаев его советы в момент запуска и вовсе не ту степь.
А тем не менее совет дня может быть более чем полезным помощником. Но для этого придется выполнить некоторые условия. Он должен быть ненавязчивым – т.е. не висеть модальным диалогом при запуске, мешая пользователю достичь его сиюсекундной цели. Иначе это не “помощник”, это уже “назойливая поучалка”. Совет должен быть в тему: т.е. быть близким к тематике задачи пользователя – иначе опять не “советчик“, а раздражающий “гуру” на отвлеченные темы. И наконец, совет дня не должен бросаться в глаза, концентрировать внимание пользователя на себе. Это же все таки совет – он не должен отвлекать, он должен помогать.
А бывает ли такое? Ну конечно же, посмотрите на любой солидный веб сайт, к примеру тот же Facebook. Советы расположены рядом с элементами, к которым они и относятся – т.е. ходить далеко за ними нет нужды. Эти подсказки, как правило, сделаны неброским шрифтом. Они не забирают внимание пользователя на себя. Найдется время у пользователя? ОК, прочтет. Нет, так нет – советы ничем и не мешают. И никакой Вам навязчивости, никто не требует закрывать модальное диалоговое окно при входе на сайт!
Немного аж завидно становится обычному советскому десктопному разработчику всем этим веб-два-нольным примочкам. А разве нельзя сделать такое же в десктопе? Варум нихт? Я вот сделал в Aml Pages. А как именно, и главное к каким решениям, почему и как пришел, расскажу в продолжении.
UPDATE: обещанное продолжение здесь
Чего-то в конец достала текучка. Поэтому сегодня об абстрактном, а именно про древовидные представления данных, и вовсе нет. Зачем “деревья” хороши, а зачем и плохи… Потянуло, знаете ли, пофилософствовать.
Вот чем больше смотрю на LeaderTask, тем больше задумываюсь, ну на хрена там деревья проектов!?! А ведь не только смотрю, я ведь еще им и пользуюсь. Причем давно, и вообще говоря с удовольствием. В принципе среди перепробованных органайзеров, LeaderTask, пожалуй, лучший. И чего в LT только нет: и категории, и сроки задач, и напоминания, и контакты. Буду краток (©). LT – это именно органайзер, в смысле слова “организатор” – то бишь софтина для планирования дел и контроля их выполнения.
В LT есть возможность создавать дерево проектов, и подпроектов. К примеру, “софтина такая-то”, “домашние дела” ну и.т.д. Но в подавляющем большинстве случаев, мне, как пользователю, достаточно затруднительно привязать задачу к тому или иному проекту. Скажем, надо мне нечто анонсировать в RSS ленте про “софтину такую-то”. Ну и куда мне сие отнести? К проекту “софтина такая-то” или к проекту “веб сайт”? ОК, конечно, можно привязать задачу к обоим проектам сразу, но тогда становится затруднителен анализ запланированных дел. Копаемся в проекте “софтина такая-то”, а находим записи про RSS для проекта “веб сайт”. А они там явно не ко времени, т.к. вроде как анализировали мы совершенно иное, а вовсе не задачи по работе с веб сайтом... По крайней мере, такой разнобой должен все-таки отвлекать (анализируем же? планируем? а не бардак перебираем?)
К слову, деревья это явно наше родное, программерское изобретение. Чего уж тут лукавить. Ну любит наш брат разбить всё и вся на деревья, на общее и частное, на абстракции и конкретику. Чувствуется что-то до боли знакомое. Это наше всё. Но тут-то всё как раз ясно. На самом деле иерархии помогают нам управляться со сложностью, бороть и побеждать (“лажать, но не сдаваться” если в несколько в другой интерпретации :).
Но вот обычному пользователю частенько все эти шибко ветвистые, вложенные деревья не так уж надобны. Ну не представляю я себе пользователя, у которого в голове выстраивается что-то вроде такого дерева: “шкаф”, “полка вторая”, “папка слева”, “запись об RSS”. Как водится всё несколько зауряднее: папка с делами, и папка с порнухой фотками. И всё! И нет никаких вам “деревьев”. И никакой гипер-пупер-супер вложенности тоже нет. Для анализа, поиска содержимого подобных папок нормальному, широко распространенному пользователю вложенность вовсе не нужна. Ну максимум один-два уровня. А это уже не дерево, максимум “кустарник”.
Тот же Алан Купер неоднократно повторяет, “пользователю чужды деревья, ему скорее ближе списки” (пусть и вложенные). Конечно же, из любого правила есть и исключения. Если пользовательские данные нечто вроде каталога, то все эти иерархические деревья сильно выручают. Но на то оно и исключение, что скорее из ряда вон, чем общий случай. Имхо, каталогизация вообще по сути своей значительно ближе к нашим программерско-админским задачам. Да хотя бы потому, что уж больно они хорошо помогают применять правило “разделяй и властвуй”.
Это вовсе не критика LT как такового. Фиг ли критиковать? Есть старинная поговорка: “не нравится – сделай лучше”. Мне вот лично LT очень сильно помогает. Но проблема деревьев коснулась и его. Повод задуматься.
В чужой софтине, мне, как обычному пользователю, далеко не очевидны все приемы работы. Поэтому и “сбокуприлепленность” деревьев выглядит для меня более “выпукло”. Проблема-то явно остается значительно более общей. Вот в своей собственной Aml Pages я точно также снова задумываюсь: “ну на хрена мне эти деревья”. Но в своей собственной софтине у меня есть и еще вагон и маленькая тележка вариантов использования, поэтому, там я всегда найду способ без деревьев и обойтись. Но ведь должно же существовать и какое-то иное решение подобных проблем? Есть же способ работы с карточками – записали мысль, отложили, и забыли. Задача быстро записать, и с глаз долой, из сердца вон (угу, тот самый мозговой штурм). Уже потом берем стопку карточек и просматриваем, выбирая себе задачки, группируем, оструктуриваем их всеми мыслимыми и немыслимыми способами.
Но ведь должно же быть, какое-то толковое и более менее общее решение!?! Вот его и хочется отыскать! Если с LeaderTask, как с чужой программой, меня в первую очередь волнует решение для себя любимого. То с Aml Pages,приходится задумываться об общих, куда как более абстрактных решениях. Что делать с LT, вроде как понятно: есть API плагинов – время найдется, напишу себе именно то, что именно мою проблему решит. А вот с Aml Pages все не так-то просто. И главное, подобная дилемма занимает голову далеко не первый месяц. И забил бы давно, дык ведь любопытно же решить…
PS: а еще бредилось про графы… Диплом все ж про графы был. А когда-то был умысел написать с-о-о-о-всем иной, то бишь напрочь отличный от всех остальных менеджер контактов (угу, блин, я в курсе, что все девелоперы на определенной стадии писали записные книжки :). Дык в тех “контактах” тоже все на графы было завязано… Уж больно енти “графья” завсегда по жизни рядом “вращаются”. Ну да это уже совсем отдельная песня.
Навеяно постом от AVL: “Отойдите от клавиатуры”. Про то, что иногда нужно давать мозгу отдохнуть, и заняться своими прямыми обязанностями, а не координировать пляску пальцев по клавиатуре.
Буквально сегодня уж очень меня утомили непонятные мемори-лики в OLE. А тут… эта… © такое дело, приспичило мне вот именно сегодня по research`ить, и прикрутить фишку, которую ну очень давно уже хотел сделать. Не первый год-то точно хотел и пробовал. Но все как-то руки не доходили – решения не красивые, зависимости от версий Windows, или какие-нить недопустимые требования (долой использование COM!).
Примочка с виду простая: окна на экране нет, но его иконка есть в списке переключения окон в Alt+Tab. Вообще говоря, это обычное дело: окно свернули в трей, а вот поднять его оттуда в этом случае можно только мышом. А вот с иконкой в Alt+Tab можно уже и клавой. Девелоперы меня поймут: все таки мышь у нас на столе по большому счету только для полной комплектации да чтоб пыль было чем протирать. Все-таки когда неделями, месяцами, годами пишется код, то обращаться с 99 процентами задач хочется именно клавой. Просто потому что так удобнее и привычнее.
А аккурат пару неделек назад образовалось в голове направление куда копать. Причем надо сказать, толковое такое направление: ни вам хаков, ни вам инжектов, ни горячих клавиш. Все кошерно - пара окон, пара стилей - работает как часы от вин95 до XP включительно (выше не проверял).
Ну да суть да дело - как-то все не досуг было покрутить идею. А намедни меня эти мемори-лики уже в тоску вгонять начали. Где течет? С чего течет? Почему движок IE не освобождает память!?! Ни черта непонятно. В общем, упадок сил да депрессия не за горами. Срочно нужна моральная победа! Ну да и давай ковырять эту красивую идею про иконку в Alt+Tab. Куда ведь интереснее ковыряться в системе, чем ловить непонятные и трудноуловимые баги в большом проекте... Проковырялся я аж пол-дня, ни пимши, не емши. Ну ни в какую! Не раскалывается орешек и всё тут - где-то по всему видно косипорю. Более-менее получается понемногу, но все как-то вокруг да около. Кожей ощущаю, что верное направление - но "не выходит каменный цветок".
Ладно, надоело к чертям. На сайте дел не в проворот. Два больших релиза на носу, семейных проблем хватает - а я тут выёгиваюсь, понимаешь. Потянуло, ага, значит на исследования. А ну его это хобби в болото – не досуг, не до примочек. Лапы в гору, проще говоря. Отписываю Кристиану Жислеру (автор Total Commander), в стиле "колись дорогой", как и что (а впервые схожее решение видел именно у него, поэтому ему и отписал). Ну и отваливаю от компа, морду лица сполоснуть да и вообще отдохнуть от кода.
Отхожу - ну, скажем, на кухню за кофейком... Хотя понятно, какое именно заведение попадается на пути на кухню :). Пропадаю в "походе за кофейком" минут так на 10. Посидел значит, подумал значит, перекурил опять же. И у-у-упс… Возвращаюсь, два взмаха кистью, три мазка по коду. Запускаю... Работает! Вот и призадумаешься, что чтобы найти ответ на вопрос нескольких лет, нужно всего лишь просра… тьфу-ты, сходить “за кофейком” минут на 10, но только обязательно без клавы под рукой. Дыбы мысль главенствовала, а не руки стучали по клаве, а мысль за ними суетливо поспевала, разбиваясь об ухабы багов.
PS: Жислер кстати ответил к ночи. Но опоздал. Решение действительно нашлось верное, и самостоятельно, хотя и похожее на его как две капли воды.
PPS: наверное надо бы выложить куда-то пример решения. Не я же первый ломал над ним голову. Дык это ж код причесывать надо, комментариями все описывать, примеры использования приводить. Не царское это дело! :) Выложу видимо попозже, а кому невмоготу стучите в почту или в аську в профиле.