пятница, 30 августа 2013 г.

Почитал про Python. Вот ни разу не впечатлён (положа руку на сердце - ОДИН раз впечатлён)

Почитал про Python. В частности вот это - http://rus-linux.net/MyLDP/BOOKS/python.pdf

Вот ни разу не впечатлён.

(положа руку на сердце - ОДИН раз впечатлён, про "ссылки" на объекты, сам - ДОЛГО над этим думал, но так и не "вкурил" НУЖНОСТЬ. А теперь - "вкурил")

Всё там же "стековая машина" со "словарями". Не  более того. А "синтаксис" без ОПЗ. Ну "синтаксис". На вкус и цвет.

Использовать как DSL - не то чтобы прям уж ИДЕАЛЬНОЕ решение. На мой вкус - тоже вполне себе "криптован".

В общем это моё частное мнение. "Уговаривать" меня в обратном - не  стоит :-)

Что касается "словарей" и построения на их основе "классов" - ну "мой FORTH" ровно так и устроен. Только он компилируемый и контроллирующий типы.

Что касается интроспекции - она также - есть. Как и множественное наследование, как и переопределение "методов" что мета-классов, что их экземпляров.

Лямбды - конечно тоже есть. Списки и словари - конечно тоже.

Параллельного присваивания - нету. Но в общем - понятно как его сделать, если сильно хочется. Собственно через "списки" о чём честно и написано в документации к Python.

Unicode - я тоже конечно же умею обрабатывать.

Ну и на закуску:
def __init__(self):
self.__dict__[self.__vdict_name] = {}
def __getattr__(self, name):
return self.__vdict[name]
def __setattr__(self, name, value):
self.__vdict[name] = value

--  подобное не кажется мне прям ИДЕАЛЬНЫМ для DSL.

По-моему вот это - http://18delphi.blogspot.com/2013/07/blog-post_196.html  - сильно веселее.

P.S. Хотя про интеграцию Python и Delphi - был бы рад, что-нибудь стоящее почитать.

P.P.S. Дали ссылку - http://dondublon.livejournal.com/68416.html

"После работы скрипта все объекты типа TPyObject уничтожаюся сами. Если объект представлял собой обертку для вашего рабочего объекта и держал на него ссылку, уничтожение ссылки коректно не делается и вы получите утечки памяти. Я достаточно долго ломал голову, как разрулить этот вопрос, в итоге получил рецепт: сделать у каждого такого TPyObject метод очистки ссылок, вызвать его вручную после работы скрипта, причем - это важно - этот метод должен быть не в деструкторе! Может, есть способ элегантнее, но я его не знаю."

Дьявол то - он как обычно - в деталях :-)

P.P.P.S. Похоже меня не до конца правильно поняли. Концепция ВНУТРЕННЕГО устройства Python - мне вполне БЛИЗКА и понятна. Потому и не впечатлён наверное. Может быть ждал "откровения", а оно - не случилось. А что до "синтаксиса" - тут и обсуждать нечего. Синтаксисы - они разные бывают. На вкус и цвет. Меня вот например SmallTalk - несколько "шокирует". Но это - ровным счётом ничего не значит. ОПЗ - я не то чтобы считаю сильной стороной. Нет конечно. Арифметика в ОПЗ - конечно ужасна. Но в целом - только арифметика.

P.P.P.P.S. Но! Изучая Python - я пришёл к выводу, что у меня допущена архитектурная недоработка. Продиктованная "слепым следованием" парадигме FORTH-машины. Надо помещать в стек и "шитый код" (да и вообще в ЛЮБОЙ контекст вызова) САМО "слово" (объект, в терминах Python), а не результат его выполнения. Тогда не нужно ни ОПЗ, ни "обратное присваивание", ни прочие "трюки".

P.P.P.P.P.S. И ещё я понял - КАК "скрестить ежа ("мой Forth") с ужом (Python)" и задействовать "батарейки в комплекте" от Python'а. В итоге получим ВНУТРИ "стандартность, гибкость и насыщенность" Python и СНАРУЖИ "понятность и гибкость DSL".

четверг, 29 августа 2013 г.

Заказал на Озоне себе книгу Лармана

Заказал на Озоне себе книгу Лармана. Жду когда привезут. Не научился я электронные книги читать. Стоит правда как самолёт. Но это - самая вменяемая книга по UML.

понедельник, 26 августа 2013 г.

Чужая статья. Delphi и предметно-ориентированные языки. Знакомо до "БОЛИ"

http://roman.yankovsky.me/?p=796

Сам - много об этом думал и многое сделал в этом направлении. Те же "скриптовые тесты" - примерно так и устроены.

Рад, что не я один :-)

Я бы правда использовал бы не Lexx/Yacc, а Forth/Lisp-машину.

Но "на вкус и цвет - все фломастеры разные"...

UML позволяет мне лично не "тупить глядя в монитор", а быстро входить в состояние "потока" для решения типовых задач

UML (отображаемый в сквозную базу знаний) позволяет мне лично не "тупить глядя в монитор" (http://18delphi.blogspot.com/2013/08/blog-post_2315.html), а быстро входить в состояние "потока" для решения типовых задач.

Примерно в таком ключе:

Пусть мы собрали некоторое количество требований и нарисовали некоторое количество прецедентов.

И пусть мы определились, что проектируемое приложение должно быть (по Layout'у) похоже на MSWord.

Тогда мы делаем примерно следующее:

Открываем базу знаний.

Вводим поисковый запрос "WordLike" или "OfficeLike".

Находим КЛАСС TWordLikeApplication видим, что он "абстрактный" (т.е. требует наследования и доопределения) и что он со стереотипом <<VCMApplication>>. Смотрим КТО от него наследуется. Может быть находим эти проекты и запускаем их. Чтобы убедиться, что это то, что нам нужно.

Ищем в базе знаний <<VCMApplication>>.

Находим этот стереотип. Понимаем, что он может быть вложен в <<VCMGUI>>, а тот в свою очередь в <<VCMProject>>.

Создаём <<VCMProject>> -> <<VCMGUI>> -> <<VCMApplication>>. Наследуем его от TWordLikeApplication.

Генерируем кода. Генератор генерирует "скелет приложения" и доопределяет абстрактные методы с указанием "вот тут напиши код". Определяем эти методы (в ДОКУМЕНТАЦИИ к ним "обычно" написано - что требуется от этого метода, если не написано, то бьём меня по голове и получаем нормальную документацию). Получаем ПУСТОЕ приложение. С УЖЕ определённой функциональностью.

Далее "вспоминаем", что у нас есть прецеденты.

Ищем по базе знаний стереотип <<UseCase>>. Который собственно у нас уже нарисован в требованиях.

Понимаем, что он может быть РЕАЛИЗОВАН стереотипом <<UseCaseRealization>>.

Смотрим ГДЕ может быть определён стереотип  <<UseCaseRealization>>.

Получаем цепочку <<VCMUseCases>> -> <<VCMUseCaseRealization>>.

Рисуем эту цепочку. Получаем "скелет прецедента". С необходимостью доопределить методы. Если что-то непонятно -  опять же - "бьём меня по голове" и получаем нормальную документацию.

Связываем <<VCMAppliaction>> с <<VCMUseCaseRealization>> связью реализации.

Получаем что наше приложение умеет реализовывать данный прецедент.

Учитывая тот факт, что <<VCMUseCaseRealization>> это ЕДИНСТВЕННОЕ место, где мы можем создавать экземпляры стереотипа <<VCMForm>> - мы с лёгкостью находим место, где мы можем создавать проектные формы с правильной инфраструктурой.

А в формах можно определять <<VCMOperation>>, которые собственно и служат "связующим звеном к пользователю".

Вкратце - как-то так.

P.S. Это я расписал для "стереотипов верхнего уровня", но примерно так же и работает для более "глубоких" проектных стереотипов типа "контейнеров".

воскресенье, 25 августа 2013 г.

Чужая статья. IDE vs текстовый редактор

http://tyvik.blogspot.ru/2013/08/ide-vs.html

Мда... "Особенности мышления".  Я вот например без AutoComplete - вполне живу и радуюсь, а вот без "нумерованных меток" - уже сильно сложнее.

Особенно никогда не понимал - зачем "плюшки". Зачем "ежа с ужом"?

Чужая статья. Мозг программиста

http://habrahabr.ru/post/191242/

"
Тупить в монитор

Самый частый и самый низкопроизводительный случай. Программист сидит и тупит в монитор. Читает тексты на разных языках, ищет что-то, пытается что-то решить. При этом основной используемый ресурс – это абстрактное мышление. Самое затратное, дорогое и низкопроизводительное. Поэтому продукты, действительно, гениальны, но приходят они с огромными временными и энергетическими затратами. Это самый низкоэффективный из всех кейсов.

Как избавиться от проблемы тупления в монитор? 

Весьма просто. Достаточно поместить часы в область зрения, и каждые 20 минут обязательно покидать рабочее место на 10 минут. Хорошая идея – занять это время физическими занятиями или общением. 

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

Нарисовать картинку

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

Есть академические приемы использования этой методики. Во-первых, это прекрасный UML. Во-вторых, это методы XP (экстремального программирования) и SCRUM. Эффективность этих методов неоспорима.

Про XP можно почитать в википедии, а про UML отмечу немедленно некоторые из его замечательных свойств:
  • Легко позволяет управлять уровнями абстрагирования и контролировать детализацию при разработке любого рода решений при программировании. Практически это единственный метод для действительно эффективного решения задач по декомпозиции (“Разделяй и властвуй!”).
  • Единственно эффективный метод для достоверной передачи абстрактной информации между коллегами. Все поймут точно то, что задумал автор схемы, когда видят ее собственными глазами. Удивительно, но когда содержание схемы передается на пальцах – текстом или на слух, качество восприятия существенно снижается! Люди просто не понимают друг друга, или понимают вовсе не то и не так, как было задумано.
  • UML в частности и вообще визуальные методы – известнейший прием менеджмента, когда нужно быстро и достоверно передать информацию между коллегами различной квалификации, различных специальностей, и получать фидбеки, организовать общение и обмен мнениями.
  • UML в частности и другие визуальные методы – один из самых эффективных методов передачи рекламных сообщений.
  • UML очень дешев – нарисовать схему карандашами, фломастерами или в векторном графическом редакторе можно легко и быстро. Эффективно заменяет многие часы тупления в монитор, фактически снижая количество затрачиваемого времени и энергии на решение логических задач.


Вообще визуальные методы – самые эффективные для обучения. Помните девочек-отличниц из средней школы? (Осторожно, сейчас будет разновидность юмора — сарказм) Большинство из них – дуры… Но ничто не мешает им систематически получать пятерки. Если вы заглядывали в их тетради – информация всегда хорошо структурирована, и представлена ЦВЕТНОЙ графикой. Поэтому они отлично запоминают материал, и легко используют его даже для абстрактных выводов. 

Умные не зубрят. Они конспектируют и рисуют.

Повысить качество иллюстраций просто — достаточно проработать цветовые коды (применить цвета, и сделать это осмысленно и системно) и решить задачи декомпозиции именно на этом этапе. Не допускать визуально сложных схем — делить их на фрагменты и выделять больше уровней, если это необходимо.

Понизить качество иллюстраций также несложно — для этого достаточно рисовать все одним цветом, и (или) делать сложные схемы. Так, чтобы они воспринимались медленно и с трудом.

Обсудить с коллегами

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

Что происходит при этом? 

До обсуждения, в умах участников (или хотя бы одного, ключевого участника) уже присутствует визуальное и (или) абстрактное представление задачи.

Обсуждение же, как еще один канал восприятия, задействующий аудиальную память, вне зависимости от того, насколько аудиальное представление прокачано у конкретных участников – создает объемное представление предмета! Поэтому именно при обсуждении рождаются даже более гениальные мысли, чем при исключительно абстрактном анализе задач, при туплении в монитор. 

Яркие примеры многие из читателей сотни раз встречали в курилках и на планерках у талантливых руководителей.

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

Их, идей, много. Они гениальны и цена их низка – обычно за получасовую беседу рождается от 5 до 10 великолепных решений.

Из ТРИЗ. Японские инженеры на внутренних семинарах (планерках, мозговых штурмах – не суть) используют интересный метод. Вначале все участники высказывают как можно более глупые, дикие и сумасбродные идеи. В результате происходит, простите за терминологию, критичное расширение незавершенного гештальта, которое приводит к мгновенному расширению менталитета и получению новых ракурсов восприятия. Таким образом они рождают действительно гениальные, эффективные решения.

Счастье придет, если еще раз пройтись по статье и загуглить термины. Выделить слово, потом нажать правой кнопкой мышки и в открывшемся меню выбрать пункт “Искать...”

Спасибо за внимание и удачи всем!"

Чужая статья. Yii, непрерывная интеграция — как не сломать все

http://habrahabr.ru/post/191210/

Давно думаю о подобном.

"
Юнит-тесты и selenium-тесты

Честно скажу — их мало, очень мало. Их мы добавляем только тогда когда появился повторявшийся баг и в очередной раз тестировщики сказали “ну вот снова не работает!”
Мы никогда не меняем старые, написанные тесты — мы разрабатываем приложение с учетом обратной совместимости. Это нужно не только ради тестов — приложение имеет API для мобилок/десктопов и оно обязано быть обратно совместимым."

"P.S. Прежде чем ругать с фразами “это не тестирование”, “оно покрывает 5% функционала” и подобным: мы не тестируем. Мы именно делаем проверку работоспособности.
Это как проверка того, что лампочка горит в магазине — мы не проверяем её нагрев, не меряем излучаемый свет, не пробуем вкрутить в неподходящий патрон — мы проверяем, просто что она горит. Тоже самое мы делаем и с кодом. Простым, и не требующим поддержки способом."

Читаю Лармана

Читаю Лармана. Точнее оказалось - перечитываю.

Впечатления смешанные - от "ну так это я давно уже знаю", до "ну и зачем это всё".

пятница, 23 августа 2013 г.

Цитата. "Аналитик, непосредственно взаимодействующий с пользователем, только он может быть тестером."

"Аналитик, непосредственно взаимодействующий с пользователем, только он может быть тестером."

Вот нечего добавить. Кроме:

"С точки зрения управления, руководство должно способствовать здоровому антагонизму таких аналитиков с программистами, поскольку в условиях конкуренции и рождается то, что нужно."

Умный человек - подсказал.

среда, 21 августа 2013 г.

Про документацию


Документация - конечно - полезное дело.

Но не в таком виде:

QFont::QFont ( const QFont & font )

Constructs a font that is a copy of font.

- это простите - "масло масляное".

Что реально важно в документации, так это секции типа Discussion, Remarks, ReturnValue или описание "граничных условий".

С документацией для "проектно-зависимых" (а не "коммерческих") библиотек - есть проблемы:

1. Такие библиотеки гораздо чаще меняются.
2. Далеко не все разработчики способны описать принципы работы "на человеческом языке" (это - данность - я сам - такой). Соответственно - нужен "технический писатель". С которым разработчика ещё нужно "как-то договариваться".
3. "Коммерческие" библиотеки не так подвержены "волюнтаризму требований". У "коммерческих" библиотек - СВОИ внешние авторы. Если требования не ложатся в архитектуру коммерческих библиотек - эти требования априори не выполнимы, если конечно ВНЕШНИЕ авторы не согласятся менять архитектуру под "хотелки" конкретных пользователей.

Документация часто не даёт "контекст" использования.

Контекст использования (и примеры) - хорошо дают ТЕСТЫ.

Текстовая документация далеко не всегда показывает СВЯЗИ между проектными классами.

понедельник, 19 августа 2013 г.

"Крупными мазками"


Offtopic. Не менее "интересная" статья

Offtopic. "Супер" статья... Вот что людям интересно...

Второй вопрос к безмолствующей аудитории

Друзья мои!

Хочется задать вопрос.

Вот вы говорите - "UML - вчерашний день", или "UML - тяжело и не нужно".

И ещё говорите - "структурируйте код" и ещё говорите - "документируйте код".

Вам ПРАВДА удаётся так жить?

Вы РЕАЛЬНО можете жить оперируя ТОЛЬКО "голым кодом" и комментариям к нему?

А вот некоторые говорят - "нам и тесты не нужны, мы и так здорово живём".

Может быть вы просветите меня серого - КАК вам удаётся так спокойно жить?

Может быть я РЕАЛЬНО чего-то не понимаю?

"Структурировать" и "документировать" код я пытался. И НЕ РАЗ. И в разных ипостасях. То, что я вижу - "НУ НЕ РАБОТАЕТ".

Всё равно люди либо "плавают в коде", либо "неправильно его используют", либо "изобретают велосипед".

Не надо только говорить, что "мы многое помним". Я сам - МНОГОЕ помню. Я помню, МНОГОЕ, что писалось лет 10-ть назад. И всё равно - "голый код" - ПЛОХО поддаётся управлению. Это моё - УБЕЖДЕНИЕ. Разубедите меня. Может быть - я в чём-то заблуждаюсь.

P.S. Не надо только про XP или Agile. Это - "процесс". А не структурный анализ кода.

P.P.S. Не надо только про "функциональные языки". Ну или поднимаете эту тему - приведите Success Story. Да ТАКУЮ! Чтобы я от зависти умер.

P.P.P.S. Ну и ещё.. Ну поделитесь, ну хоть какими-нибудь метриками! Ну количество строк кода. Количество сущностей. Количество человек в команде. Количество прецедентов (UseCase). Ну или на худой конец количество таблиц в БД. Пожалуйста.

ToDo. Видимо надо начать "с нуля" про VCM

Видимо надо начать "с нуля" про VCM.

Откуда, что, чего.. И зачем это нужно.

Для примера - DevExpress. С его ХОРОШЕЙ реализацией. И УЖАСНОЙ архитектурой. Где ВСЕ "операции" (TAction) лежат в ОДНОЙ "коробке" на MainForm.

Начинаем с ОТДЕЛЬНОЙ формы. Описываем её ОПЕРАЦИИ. Как они публикуются в тулбары и ""меню".

ПОНИМАЕМ для начала тот факт, что "форма" - это активный объект, который умеет ПУБЛИКОВАТЬ операции.

Затем превращаем эту форму в ГЛАВНУЮ ФОРМУ приложения (MainForm).

Далее вставляем в неё подобную же ОДИНОЧНУЮ форму. Опять же с ОПЕРАЦИЯМИ и КОНТРОЛАМИ.

Дальше иллюстрируем FormDataSource. Потому, что "вспомнили", про "данные", которые инстанцируют форму.

Дальше понимаем, что БЫВАЕТ несколько "активных зон".

Вставляемую форму дробим на "активные зоны". Получаем несколько ViewAreaDataSource.

Далее получаем - FormSetDataSource. Как "поставщика" этих самых ViewAreaDataSource.

Далее "понимаем", что FormSetDataSource и есть - ДАННЫЕ прецедента (UseCase).

Далее понимаем, что "активные зоны" могут закрываться и открываться (это к примеру). И тут получаем собственно FormSet (UseCase) - как контроллера собственно бизнес-логики ПРЕЦЕДЕНТА.

В итоге цепочка такая:

По представлению:

FormSet (UseCase) -> ViewArea ("активная зона").

По данным:

FormSetDataSource (UseCaseDataSource) -> ViewAreaDataSource -> Data.

В отличии от MCV - "колен" как минимум - ПЯТЬ - UseCase -UseCaseDataSource, ViewArea - ViewAreaDataSource, Data - это "активные" объекты осуществляющие "выбор" данных из БД и реализующие "первичную бизнес-логику".

P.S. В схеме MVC - мне всегда казалось, что "колен" не хватает.... Хотя я и знаком с ней только в трактовке Apple.

P.P.S. Собственно "контролы" и их "геометрия" тут остались за сценой. Это ещё как минимум ДВА слоя (собственно описание контролов внутри "формы" ("подслой" - место размещения "активных зон" внутри формы) и FormSetFactory (UseCaseFactory)).

P.P.P.S. Далее - добираемся до того факта, что контролы на форме - тоже умеет быть АКТИВНЫМИ объектами, которые умеют ПУБЛИКОВАТЬ операции. Фокусо-зависимые.

P.P.P.P.S. И видимо надо отдельно описать и АКЦЕНТИРОВАТЬ внимание на тот факт, что ИМЕННО UseCaseDataSource и ViewAreaDataSource - служат "связующим звеном" для того, чтобы "формы ничего НАПРЯМУЮ не знали друг про друга".

ToDo. Начать с нуля SandBox, тесты к нему и мета-модель

Начать с нуля SandBox, тесты к нему и мета-модель.

И расписывать по шагам - как оно вырастает "с нуля".

С одиночным "главным" наследованием. Чтобы ВСЕ примитивы мета-модели (и Class и Category) наследовались от абстрактного примитива Base.

И с выделением "примесей" AttrHolder, PropertyHolder, ReadOnlyPropertyHolder, UsesHolder etc.

А может и БЕЗ них. Обойтись ТОЛЬКО "квадратиками". А атрибуты и операции сделать ТОЖЕ "квадратиками". По аналогии с method и ViewArea.

А "операции" оставить ТОЛЬКО для "сигнатур". А "атрибуты" рисовать "квадратиками" с наследованием (как ViewArea) т.е. стрелка "наследования" указывает целевой тип атрибута, а имя "квадратика" указывает имя атрибута. Ну и понятное дело - на "квадратик" можно "навесить" пользовательские свойства.

В "стрелках" есть БОЛЬШАЯ "сермяжная правда" в отличии от "сигнатур" - "стрелки" - НАПРЯМУЮ указывают на тип, а "сигнатуры" - предполагают парсинг и вариативность типа. Стрелки же - вариантивность типов - ИСКЛЮЧАЮТ.

Кстати и для "методов" можно избавится от "сигнатур". По индукции. Вводя внутри методов стереотипы <<Param>> со стрелкой к типу. Это - УНИФИЦИРУЕТ. Но! Может сказаться на производительности рисования диаграмм. Тут - надо ТЩАТЕЛЬНО подумать.

Практически получится "UML без UML". ОЧЕНЬ маленькое подмножество - "стрелки" и "квадратики". На основе которого можно нарисовать ВСЁ, что рисуется и сейчас.

Отдельно выделить - АКСИОМАТИКУ (совсем базовые примитивы) и производные (которые перед генерацией распадаются на базовые примитивы, путём их конструирования перед генерацией).

АКСИОМАТИКА - зависит от целевого языка генерации, а ПРОИЗВОДНЫЕ - не зависят. Они лишь порождают примитивы из АКСИОМАТИКИ.

Единственная языковая зависимость может выражаться либо в применяемых генераторах, либо в ifdef/ifndef.

Таким образом - получаем "компактное" языко-зависимое "ядро" и набор языко-независимых производных стереотипов.

Также надо ОКОНЧАТЕЛЬНО подумать о возможности рисования представления ПРОИЗВОДНЫХ примитивов в виде диаграмм ВНУТРИ данных примитивов. В диаграммах могут использоваться как примитивы из АКСИОМАТИКИ, так и РАНЕЕ определённые ПРОИЗВОДНЫЕ примитивы.

Эти диаграммы достаточно "просто" обрабатывать. Достаточно перебрать все элементы диаграммы и создать такие же (по образу и подобию) уже в конечном экземпляре примитива. Надо лишь учесть возможность подстановки специальных переменных типа SELF, PARENT, PARENT1..PARENTN etc. Это уже надо по месту додумывать. "Сферического коня" - тут ни в коем случае - рождать не нужно.

Также надо подумать о "разрисовывании" вызовов встроенных (и определённых ранее) примитивов DSL ПРЯМО внутри методов генерации. Чтобы в конечном итоге иметь возможность "безболезненно" сменить текстовый DSL. В виде "блок-схем".

Вкратце - может получится, что от мета-мета-модели останутся лишь стереотипы Class, Category и dependency (унаследованные от ЕДИНОГО предка Base). Все остальные - не нужны.

Причём "начать плясать" именно от "контейнерных" примеров в SandBox: Project->Library->SimpleClass. Далее понадобился ExeTarget - вводим его. Понадобился Enum или Pointer - вводим их. etc по индукции. Понадобился TestTarget и TestCase - вводим их. Ну в общем - "в стиле XP". Делаем ТОЛЬКО то, что НУЖНО в данный конкретный момент.

И смотреть на временные срезы этого хозяйства. Как оно растёт.

Там глядишь и до VCM в "новом понимании" можно добраться.

Ну и иметь в виду - http://18delphi.blogspot.com/2013/07/blog-post_24.html

Также надо подумать (в разрезе SandBox) о микро-UseCase'ах и микро-UserNeeds. Чтобы сразу под проектные классы "подкладывать" ТРЕБОВАНИЯ.

воскресенье, 18 августа 2013 г.

Чужая статья. Доказательное планирование

http://habrahabr.ru/post/186410/

"1. Только программист, выполняющий работу, может оценивать необходимое для нее время. Любая система, в которой руководство составляет расписание задач, не подпуская к нему разработчиков, обречена на провал. Только программист, который будет реализовывать конкретную функциональность, может знать, какие шаги нужно будет сделать, чтобы достичь цели.
2. Исправляйте ошибки по мере обнаружения, а затраченное время приписывайте исходной задаче. Вы не можете запланировать исправление каждой ошибки заранее, потому что не знаете, с какими проблемами придется столкнуться. Если в новом коде обнаруживается ошибка, приписывайте временные затраты на ее исправление исходной задаче, которая была реализована некорректно. Это поможет ДП предсказывать время на получение полностью отлаженного не не просторабочего кода.

3. Не позволяйте менеджерам давить на разработчиков с целью сокращения оценок сроков. Часто недостаточно опытные менеджеры программных проектов думают, что смогут «мотивировать» программистов работать быстрее, давая им хорошие, «тугие» (невероятно короткие) планы выполнения задач. Я считаю такой тип мотивации совершенно безмозглым. Когда я не вписываюсь в расписание, я чувствую себя обреченным, угнетенным и лишенным всякой мотивации. Когда же я иду с опережением официального плана, я воодушевлен и продуктивен. Планирование — не место для психологических игр"

Чужая статья. 8 вещей, которых не должен бояться разработчик

http://habrahabr.ru/post/187052/

"Показывать ваш код другим
Вы боитесь когда другие люди просматривают ваш код? Это почему? Написали не так хорошо, как могли бы написать? Что ж, тогда это, возможно, не совсем подходящая для вас работа. Боитесь что вы где-то ошиблись? Так в этом случае не стоит боятся — потому что от каждой найденной ошибке при просмотре кода вы получаете пользу (см. «Совершать ошибки»). Всегда следует писать ваш код настолько продуманно насколько можете. Поэтому вы скорее должны гордиться тем, что написали, а не бояться того, что кто то взглянет на код."

суббота, 17 августа 2013 г.

Offtopic. О "математике"

http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%80%D0%B0%D0%B7%D0%BE%D1%80%D0%B5%D0%BD%D0%B8%D0%B8_%D0%B8%D0%B3%D1%80%D0%BE%D0%BA%D0%B0

Всегда любил подобные текста... И до сих пор удивляюсь - как кто-то в них что-то понимает...

Особенно хорош переход от условия задачи к "методу решения" - "Данная ситуация может быть смоделирована подобным образом: имеется блуждающая частица и коридор [A;B]. Рассматривается вероятность того, что частица выйдет из коридора за n шагов (проскочит через верхнюю или нижнюю стенку)." - НУ ВЕДЬ ВСЁ ОЧЕВИДНО... ага... чувствую себя дебилом...

воскресенье, 11 августа 2013 г.

Ссылка. Это - БОМБА. Использование компилятора Delphi в прикладных программах

Ссылка. ОЧЕНЬ Заслуживает внимания. SDL/DeCAL

http://gurin.tomsknet.ru/delphidecal.html

-- всё уже придумано до нас :-) Ну в общем - как всегда.

Вопрос.IntelliJ IDEA

http://ru.wikipedia.org/wiki/IntelliJ_IDEA

Чем ИМЕННО это так "возбуждает" разработчиков?

пятница, 9 августа 2013 г.

Вот мне интересно.. А как люди ведут "диалог с заказчиком"?

Вот мне интересно.. А как люди ведут "диалог с заказчиком"?

Ну понятно - "крупными мазками" обозначили приоритеты..

А дальше? А ОПЕРАТИВНО - как вопросы решать?

Когда вопрос требует "ответа через 5 минут"...

четверг, 8 августа 2013 г.

Ссылка. ОТЛИЧНАЯ тема. Мы САМИ "примерно" так делали.

Ссылка. ОТЛИЧНАЯ статья. А Вы ещё не используете базовую форму и базовую фрейму в своих Delphi-проектах?

"Текстовый" UML aka DSL

Состоялся разговор - "как можно на UML описать процесс "читатель, читает книгу"".

Что хочу сказать?

"Просто" описать процесс - "я не знаю как". Я знаю, что при разработке системы надо начинать со сбора ТРЕБОВАНИЙ :-)

В результате разговора и "выяснения ТЗ" нарисовалась такая картина:

ЧИТАТЕЛЬ = АКТЁР
 СОСТОЯНИЕ "уровень знаний"
end

КНИГА = ПРЕЦЕДЕНТ
 ОТВЕТСВЕННОСТЬ "возможность быть прочитанной"
end

В первую очередь при разработке системы надо сделать что?

Надо СОБРАТЬ и ОПИСАТЬ требования. И ЗАФИКСИРОВАТЬ их.

to be continued....

Про "MVC". Будем реализовывать дальше прецедент "работа с документом"

Предыдущая серия была тут - http://18delphi.blogspot.com/2013/08/mvc.html

Теперь будем продолжать реализацию прецедента "работа с документом".

У нас остались нереализованные требования:
6. Печать и предварительный просмотр всего документа.
7. Печать и предварительны просмотр выделенных участков документа.
8. Переход по ссылкам. Ссылки бывают - внутренние (внутри данного прецедента) и внешние (между различными прецедентами).
9. Логирование функций работы с документом.
10. Экспорт всего документа в определённые форматы.
11. Экспорт выделенного участка текста в определённые форматы.

Начнём с "Печать и предварительный просмотр всего документа".

Пусть собственно ФУНКЦИОНАЛ печати и предварительного просмотра - УЖЕ "как-то" реализован. А именно ОТДЕЛЬНЫМ классом:

TDocumentPrintMachine = class
 procedure Preview;
 procedure Print;
end;//TDocumentPrintMachine

- это пока только "набросок".

Теперь посмотрим - как этот ПРОЕКТНЫЙ класс связан с прецедентом "работа с документом".

Напомню как выглядит прецедент "просмотр документа":

С точки зрения визуализации:

type
 TDocumentForm = class(TForm)
 
  TDocumentTextViewArea = class(TFrame)
   Text : TDocumentView;
  end;//TDocumentTextViewArea
 
  DocumentTextViewArea : TDocumentTextViewArea; 
 
  TListViewArea = class(TFrame)
   List : TListView;
  end;//TListViewArea 
 
  DocumentContents: DocumentContentsViewArea: TDocumentContentsViewArea = class(TFrame)
 
   DocumentStructureViewArea: TDocumentStructureViewArea = class(TFrame)
    Tree : TTreeView;
   end;//TDocumentStructureViewArea 
 
   DocumentPicturesViewArea: TListViewArea;
 
  end;//TDocumentContentsViewArea 
 
  DocumentIncomingLinksViewArea: TListViewArea;
 
  DocumentOutgoingLinksViewArea: TListViewArea;
 
  DocumentAnnotationViewArea: TDocumentTextViewArea;
 
end;//TDocumentForm

С точки зрения данных:

type
 TDocumentUseCaseData = class(TUseCaseData)
 
  TDocumentTextViewAreaData = class(TViewAreaData)
   property Text: TDocument;
  end;//TDocumentTextViewAreaData
 
  property DocumentText: TDocumentTextViewAreaData;
 
  TListViewAreaData = class(TViewAreaData)
   property List : TList;
  end;//TListViewAreaData
 
  property DocumentContents: TDocumentContentsViewAreaData = class(TViewAreaData)
 
   property DocumentStructure: TDocumentStructureViewAreaData = class(TViewAreaData)
    property DocumentStructure : TTree;
   end;//TDocumentStructureViewAreaData
 
   property DocumentPictures: TListViewAreaData;
 
  end;//TDocumentContentsViewAreaData
 
  property DocumentIncomingLinks: TListViewAreaData;
 
  property DocumentOutgoingLinks: TListViewAreaData;
 
  property DocumentAnnotation: TDocumentTextViewAreaData;
 
 end;//TDocumentUseCaseData

Куда "всунуть" TDocumentPrintMachine?

Стоп!
Тут я забыл про один вопрос - "как данные связываются с визуализацией?"
Сейчас мы рассмотрим этот вопрос.

Пока почитайте вот это - http://www.delphinotes.ru/2013/01/delphi.html#more

Там - ОЧЕНЬ правильные вещи про "базовую форму" и "базовый фрейм" написаны.
СВОЯ "базовая форма" и "базовый фрейм". Николай - там - ОЧЕНЬ верно это описал.

Будем считать, что TForm => TvcmForm, TFrame => TvcmViewArea.

А теперь посмотрим, как преображается наша модель:
type
 TDocumentForm = class(TvcmForm)
 
  f_DocumentData : TDocumentUseCaseData;
 
  TDocumentTextViewArea = class(TvcmViewArea)
   f_TextData : TDocumentTextViewAreaData;
   Text : TDocumentView;
  end;//TDocumentTextViewArea
 
  DocumentTextViewArea : TDocumentTextViewArea; 
 
  TListViewArea = class(TvcmViewArea)
   f_List : TListViewAreaData;
   List : TListView;
  end;//TListViewArea 
 
  DocumentContents: DocumentContentsViewArea: TDocumentContentsViewArea = class(TvcmViewArea)
 
   f_Contents : TDocumentContentsViewAreaData;
 
   DocumentStructureViewArea: TDocumentStructureViewArea = class(TvcmViewArea)
    f_Structure : TDocumentStructureViewAreaData;
    Tree : TTreeView;
   end;//TDocumentStructureViewArea 
 
   DocumentPicturesViewArea: TListViewArea;
 
  end;//TDocumentContentsViewArea 
 
  DocumentIncomingLinksViewArea: TListViewArea;
 
  DocumentOutgoingLinksViewArea: TListViewArea;
 
  DocumentAnnotationViewArea: TDocumentTextViewArea;
 
end;//TDocumentForm

- тут мы видим "данные" и "представление" ОДНОВРЕМЕННО.

(Ещё раз напоминаю! "Геометрию" и Owner/Parent - мы рассмотрим - позже. Потому, что ТУТ - не ВСЁ ТАК ПРОСТО. Например есть TPanel а есть TTabView. ;-) "Активные зоны" могут себя ПО-РАЗНОМУ вести :-))

А где они ("данные" и "представление") в итоге "встречаются"? Сейчас мы это - рассмотрим:

Модель (и фреймворк) дают нам следующее:
type
 TDocumentForm = class(TvcmForm)
 
  f_DocumentData : TDocumentUseCaseData;
 
  TDocumentTextViewArea = class(TvcmViewArea)
   f_TextData : TDocumentTextViewAreaData;
   Text : TDocumentView;
   procedure GotData(aData : TDocumentTextViewAreaData);
   begin
    f_TextData := aData;
    Text.Text := aData.Text;
   end;
  end;//TDocumentTextViewArea
 
  DocumentTextViewArea : TDocumentTextViewArea; 
 
  TListViewArea = class(TvcmViewArea)
   f_List : TListViewAreaData;
   List : TListView;
   procedure GotData(aData : TListViewAreaData);
   begin
    f_List := aData;
    List.List := aData.List;
   end;
  end;//TListViewArea 
 
  DocumentContents: DocumentContentsViewArea: TDocumentContentsViewArea = class(TvcmViewArea)
 
   f_Contents : TDocumentContentsViewAreaData;
 
   DocumentStructureViewArea: TDocumentStructureViewArea = class(TvcmViewArea)
    f_Structure : TDocumentStructureViewAreaData;
    Tree : TTreeView;
    procedure GotData(aData : TDocumentStructureViewAreaData);
    begin
     f_Structure := aData;
     Tree.Tree := aData.Tree;
    end; 
   end;//TDocumentStructureViewArea 
 
   DocumentPicturesViewArea: TListViewArea;
 
   procedure GotData(aData : TDocumentContentsViewAreaData);
   begin
    f_Contents := aData;
    DocumentStructureViewArea.GotData(aData.DocumentStructure);
    DocumentPicturesViewArea.GotData(aData.DocumentPictures);
   end;
 
  end;//TDocumentContentsViewArea 
 
  DocumentIncomingLinksViewArea: TListViewArea;
 
  DocumentOutgoingLinksViewArea: TListViewArea;
 
  DocumentAnnotationViewArea: TDocumentTextViewArea;
 
  procedure GotData(aData : TDocumentUseCaseData);
  begin
   f_DocumentData := aData;
   DocumentTextViewArea.GotData(aData.DocumentText);
   DocumentContentsViewArea.GotData(aData.DocumentContents);
   DocumentIncomingLinksViewArea.GotData(aData.DocumentIncomingLinks);
   DocumentOutgoingLinksViewArea.GotData(aData.DocumentOutgoingLinks);
   DocumentAnnotationViewArea.GotData(aData.DocumentAnnotation);
  end;
 
end;//TDocumentForm


Идея понятна? По-моему - она - ОЧЕВИДНА :-)
И ЭТО ВСЁ - генерируется с модели. Спросите меня - "где модель" и "как оно генерируется"? Я расскажу - чуть позже...

Теперь вернёмся к требованиям и ответственностям.
......

Для начала посмотрим вот сюда:
  TDocumentTextViewArea = class(TvcmViewArea)
   Text : TDocumentView;
  end;//TDocumentTextViewArea
 
  DocumentTextViewArea : TDocumentTextViewArea; 
...
  DocumentAnnotationViewArea: TDocumentTextViewArea;
...

Предположим, что ответственность "Печать и предварительный просмотр всего документа" реализует объект TDocumentTextViewArea. Ну то есть - печатать и просматривать документ позволяют ДВЕ "активных зоны" - DocumentTextViewArea и DocumentAnnotationViewArea.

Для начала - определим пользовательские "точки входа", а именно - операции "Печать" и "Предварительный просмотр".

Предположим, что операции определяет мета-директива operation.

Это аналог procedure, но с ФИКСИРОВАНОЙ сигнатурой и возможностью ПУБЛИКАЦИИ в toolbar'е и всевозможных меню. А также - operation может УПРАВЛЯТЬ видимостью и доступностью этих "пунктов меню". Но об этом - позже.

(<<operation>> это кстати один из СТЕРЕОТИПОВ нашей мета-модели UML, но про UML - тоже позже)

"Ноги" operation - растут из TAction на самом деле :-) (это для любителей Delphi).

продолжим наверное в следующей статье...

.................

to be continued....

Вопрос про UseCase'ы

Задали тут ХОРОШИЙ вопрос, цитирую:

"смотрите

есть "актор" (могу попутать)

мы пишем его с себя, выставляя use case-ы

и все эти use case-ы растут из моего состояния (как юзера)

в момент, когда я системой ПОКА НЕ ОБЛАДАЮ

потом появилась система

и я - уже не "человек умелый", а "человек разумный"

т.е. я как "я с системой" отличаюсь от "меня без системы"

и мое видение системы тоже изменяется

и как тогда насчет ЭВОЛЮЦИИ прецедентов?

как пишут (блин) "классики"

система устаревает в момент её создания

как только она завершена, она тут же устарела

т.к. "пользователь с системой" - уже отличается от "пользователя без системы""

-- я в будущем постараюсь на него ответить. Но может быть кто-нибудь из читателей сам постарается ответить?

"Шаблон" работы с ТЗ

 "проблема пользователя" -> "свойство системы" -> "ответственность программной сущности"

Иногда "проблема" - опускается...

приходит Пользователь и говорит - "хочу красную ленточку" - это СРАЗУ - "свойство системы"
а проблема - "ну так хочет Пользователь"

Читаю всякие разные комментарии и думаю, что многие путают СЛОЖНОСТЬ системы с другими характеристиками

Читаю всякие разные комментарии и думаю, что многие путают СЛОЖНОСТЬ системы с другими характеристиками. Например с ОТКАЗОУСТОЙЧИВОСТЬЮ ил МАСШТАБИРУЕМОСТЬЮ. Или ВРЕМЕНЕМ ОТКЛИКА.

Вот скажем Wikipedia - сложная система?

P.S. если из инструментов есть лишь "молоток", то все проблемы кажутся "гвоздями" :-)

вторник, 6 августа 2013 г.

Ссылка. В поисках самого востребованного языка программирования. Не мог пройти мимо. Сам - прочитаю позже

http://blogerator.ru/page/samij-vostrebovannij-populjarnij-jazyka-programmirovanija-rejting-tiobe-pypl-redmonk-statistika

Не мог пройти мимо. Сам - прочитаю позже. Может быть - выскажу своё мнение. Или воздержусь.

"Синтез" логики форм приложения на тему "MVC". Или "анализ прецедентов сверху вниз". А также - "рефакторинг при проектировании". Пока БЕЗ UML

Предварительная вводная: Говоря о классах "реализации" - будем придерживаться нотации Delphi и будем иметь в виду архитектуру библиотеки VCL. Это необязательно.  Но это - для определённости.

Пусть есть несколько "похожих" прецедентов (http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D1%86%D0%B5%D0%B4%D0%B5%D0%BD%D1%82_(UML)):

1. Работа с документом
2. Работа со словарной статьёй
3. Работа со статьёй энциклопедии
4. Обзор изменений документа
5. Сравнение соседних редакций документа

Прецеденты взяты из реальной системы. Надеюсь - этому никто не расстроится. Просто качественно можно говорить об известном предмете, а не о "коне вакууме".

Надеюсь, что с одной стороны - никто не узрит в этом "выдачу технологических секретов", а с другой - "скрытую рекламу". Если бы не эти два обстоятельства - писать было бы сильно проще.

Этап сбора и описания требований - опускаю. Этой теме можно посвятить отдельную статью (если интересно). Пока предположим, что требования собраны и описаны. И частично - детализированы.

Прецеденты - РАЗНЫЕ, но по функциональности - ПЕРЕСЕКАЮТСЯ.

Что у них общего? Это - "работа с документом" в том или ином виде.

Понятное дело, что в реализации этих прецедентов - есть много общего, но и есть различия.

Понятное дело, все эти прецеденты визуализуются РАЗЛИЧНЫМИ формами отображения.

Понятно, что эти формы - родственны, но при этом - они и различаются.

Что делать? Как будем проектировать функционал этих прецедентов?

Наследование? Визуальное наследование? Агрегация? Выделение бизнес-логики в отдельный слой/слои?

Хочется немножко рассказать на эту тему.

Для начала надо наверное выделить ОБЩИЕ ответственности для данных прецедентов:
1. Отображение документа.
2. Скроллирование документа.
3. Навигация курсором в рамках текста документа.
4. Выделение участков текста документа.
5. Копирование выделенных участков в буфер обмена.
6. Печать и предварительный просмотр всего документа.
7. Печать и предварительны просмотр выделенных участков документа.
8. Переход по ссылкам. Ссылки бывают - внутренние (внутри данного прецедента) и внешние (между различными прецедентами).
9. Логирование функций работы с документом.
10. Экспорт всего документа в определённые форматы.
11. Экспорт выделенного участка текста в определённые форматы.

пока - ограничимся...

Теперь попытаемся выделить функциональные различия данных прецедентов.

Для начала поймём - как эти прецеденты - визуализируются.

На самом деле каждый прецедент (отображаемый для определённости "формой" - наследником от TForm) распадается на несколько "зон активностей" (или "зон пользовательского фокуса"). На самом деле эти "зоны" (забегая вперёд) это отдельные вложенные прецеденты. На эту тему я немножко "закинул удочку" тут - http://18delphi.blogspot.com/2013/08/usecase.html.

Каждая из зон характеризуется тем, что у них у каждой может быть СОБСТВЕННЫЙ набор Toolbar'ов, каждая может принимать ОТДЕЛЬНО фокус ввода, каждая имеет СОБСТВЕННОЕ контекстное меню, каждая может ВЛИЯТЬ на главное (командное) меню приложения.

Каждая из зон может обладать СОБСТВЕННЫМ состоянием, которое может записываться в историю работы приложения.

Предположим, что распадаются они так (в скобках буду указывать имена "реализующих классов"):

1. Работа с документом (TDocumentForm):
а. Собственно "текст документа" (TDocumentTextViewArea).
б. Оглавление документа (TDocumentContentsViewArea):
б.1 Список структурных единиц документа (TDocumentStructureViewArea).
б.2 Список иллюстраций в документе (TDocumentPicturesViewArea).
в. Список входящих ссылок на документ (TDocumentIncomingLinksViewArea).
г. Список исходящих ссылок из документа (TDocumentOutgoingLinksViewArea).
д. Аннотация к документу (TDocumentAnnotationViewArea).

2. Работа со словарной статьёй (TDictionEntryForm):
а. Русский текст статьи (TRussianTextViewArea).
б. Английский текст статьи (TEnglishTextViewArea).
в. Список словарных статей (TDictionEntriesViewArea).

3. Работа со статьёй энциклопедии (TEncyclopediaForm):
а. Собственно "текст статьи" (TArcticleViewArea).
б. Оглавление энциклопедии (TEncyclopediaContentsViewArea).

4. Обзор изменений документа (TDocumentReviewForm):
а. Собственно "текст обзора документа" (TDocumentReviewTextViewArea).

5. Сравнение соседних редакций документа (TEditionsCompareForm):
а. Текст предыдущей редакции документа (TPrevEditionTextViewArea).
б. Текст "актуальной" редакции документа (TActualEditionTextViewArea).

Что это за классы TXXXViewArea и каково их место в иерархии того же VCL - мы поговорим - чуть позже.

Если вы хотите аналогию из "классического" Delphi и VCL, то скажем так, что TXXXViewArea - "похожи" на TFrame. Именно - ПОХОЖИ. Но НЕ ЯВЛЯЮТСЯ таковыми. Но ПОКА - так думать будет понятно (надеюсь).

Далее надо отметить, что каждый прецедент имеет "точку входа". Это нечто, что принимает "данные для конструирования прецедента" и возвращает собственно ЭКЗЕМПЛЯР прецедента.

В терминах "классики" это - конструктор класса (формы). Но если забегать вперёд и думать об "инъекции зависимостей" (http://ru.wikipedia.org/wiki/Dependency_Injection), то это - фабрика. Фабрика прецедента.

Но! ПОКА забудем о фабриках. До поры до времени.

ПОКА будем считать, что "точка входа" в прецедент это конструктор объекта в терминах "классики".

Также ПОКА забудем о сигнатуре конструктора TForm (и TComponent) и что на самом деле он выглядит так - Create(anOwner : TComponent).

Также ПОКА забудем о "геометрии" и размещении форм (визуализующих прецеденты) в пространстве, а также о свойстве Parent.

Об этом мы поговорим чуть позже. Обещаю.

ПОКА будем считать, что "точка входа" выглядит примерно так CreateUseCase(aData : TUseCaseData).

Где TUseCaseData - некоторый базовый (в пределе - шаблонный) класс, обеспечивающий связь данных прецедента и собственно логики и визуализации прецедента.

Забегая вперёд - отметим, что это скорее всего не класс, а - интерфейс. Но на данном этапе - нам ПОКА это не важно.

Почему ИНТЕРФЕЙС? Потому, что - ПОДСЧЁТ ССЫЛОК. Пока - это - не важно. Но позже - я остановлюсь и на этом моменте.

(Для тех немногих, кто знаком с фреймворком VCM скажу, что TUseCaseData - это собственно и есть IsdsXXX).

Пока дело обстоит так. Есть "визизуализация прецедента" - TXXXForm и "данные прецедента" - TXXXUseCaseData.

TXXXForm обладает конструктором CreateUseCase, с сигнатурой - CreateUseCase(aData : TXXXUseCaseData).

Давайте теперь посмотрим - какие "данные прецедентов" нам понадобятся для визуализации описанных выше прецедентов.

Тут ПОКА - всё очень просто. Отображение тут - 1:1. Т.е. "визуализация прецедента" TXXXForm требует "данных прецедента" TXXXUseCaseData.

Хочется отметить тот факт, что в описываемой "модели" - "данные прецедента" - являются КОНСТАНТНЫМИ. Т.е. они не меняют своё состояние с момента своего рождения до момента своей смерти. Это означает, что собственно прецедент (и его визуализация) могут рассматривать эти данные как инвариант на всём времени своей жизни. Если "данные прецедента" надо поменять (например переходим из одного документа в другой), то это означает, что надо СМЕНИТЬ текущий прецедент. Создав НОВЫЙ экземпляр, подав в "точку входа" (конструктор/фабрику) новые "данные прецедента". Этот ВАЖНЫЙ факт - мы тоже - обсудим. Чуть позже.

Тут бы уже можно было бы нарисовать модель прецедентов и их данных в терминах UML, но к сожалению - инструмент у меня недоступен - посему "буду писать текстом". Пока. А модель - нарисую чуть позже.

Итак - посмотрим на описанные выше прецеденты и их данные.
Пусть запись вида - TXXXForm <=| TXXXUseCaseData - означает "данные TXXXUseCaseData - могут порождать экземпляр прецедента TXXXForm". Т.е. что данные совместимы с входным параметром соответствующего прецедента.

Итак - прецеденты и их данные:

1. Работа с документом - TDocumentForm <=| TDocumentUseCaseData
2. Работа со словарной статьёй - TDictionEntryForm <=| TDictionEntryUseCaseData
3. Работа со статьёй энциклопедии - TEncyclopediaForm <=| TEncyclopediaUseCaseData
4. Обзор изменений документа - TDocumentReviewForm <=| TDocumentReviewUseCaseData
5. Сравнение соседних редакций документа - TEditionsCompareForm <=| TEditionsCompareUseCaseData

Теперь собственно рассмотрим - "что же такое эти TXXXUseCaseData":
Как мы уже "договорились" - они все наследуются от TUseCaseData.

Т.е. как-то так (ПОКА):
1. Работа с документом - TDocumentForm <=| TDocumentUseCaseData = class(TUseCaseData)
2. Работа со словарной статьёй - TDictionEntryForm <=| TDictionEntryUseCaseData = class(TUseCaseData)
3. Работа со статьёй энциклопедии - TEncyclopediaForm <=| TEncyclopediaUseCaseData = class(TUseCaseData)
4. Обзор изменений документа - TDocumentReviewForm <=| TDocumentReviewUseCaseData = class(TUseCaseData)
5. Сравнение соседних редакций документа - TEditionsCompareForm <=| TEditionsCompareUseCaseData = class(TUseCaseData)

Это - "крупными мазками".

Теперь поговорим об их наполнении.

Мы уже говорили о TXXXViewArea. "Активных зонах".
И "по индукции" было бы логично раз TXXXUseCaseData порождает TXXXForm, то должен найтись TXXXViewAreaData, который порождает TXXXViewArea.

Про "геометрию", Owner'ов и Parent'ов - опять же - ПОКА - не говорим.

Считаем, что TXXXViewArea имеет "конструктор" CreateViewArea(aData : TXXXViewAreaData).

Откуда берутся эти самые TXXXViewAreaData?

В описываемой модели - они "висят" в виде read-only-property на TXXXUseCaseData. И наследуются (забегая вперёд) от TViewAreaData.

(Для тех немногих, кто знаком с VCM скажу TXXXViewAreaData это ни что иное как IdsXXX)

И тогда картина описываемых прецедентов приобретает следующий вид:

1. Работа с документом - TDocumentForm <=|
TDocumentUseCaseData = class(TUseCaseData)
 property DocumentText: TDocumentTextViewAreaData;
 property DocumentContents: TDocumentContentsViewAreaData = class(TViewAreaData)
  property DocumentStructure: TDocumentStructureViewAreaData;
  property DocumentPictures: TDocumentPicturesViewAreaData;
 end;//TDocumentContentsViewAreaData
 property DocumentIncomingLinks: TDocumentIncomingLinksViewAreaData;
 property DocumentOutgoingLinks: TDocumentOutgoingLinksViewAreaData;
 property DocumentAnnotation: TDocumentAnnotationViewAreaData;
end;//TDocumentUseCaseData

2. Работа со словарной статьёй - TDictionEntryForm <=|
TDictionEntryUseCaseData = class(TUseCaseData)
 property RussianText: TRussianTextViewAreaData;
 property EnglishText: TEnglishTextViewAreaData;
 property DictionEntries: TDictionEntriesViewAreaData;
end;//TDictionEntry 

3. Работа со статьёй энциклопедии - TEncyclopediaForm <=|
TEncyclopediaUseCaseData = class(TUseCaseData)
 property Arcticle: TArcticleViewAreaData;
 property EncyclopediaContents: TEncyclopediaContentsViewAreaData;
end;//TEncyclopediaUseCaseData

4. Обзор изменений документа - TDocumentReviewForm <=|
TDocumentReviewUseCaseData = class(TUseCaseData)
 property DocumentReviewText: TDocumentReviewTextViewAreaData;
end;//TDocumentReviewUseCaseData 

5. Сравнение соседних редакций документа - TEditionsCompareForm <=|
TEditionsCompareUseCaseData = class(TUseCaseData)
 property PrevEditionText: TPrevEditionTextViewAreaData;
 property ActualEditionText: TActualEditionTextViewAreaData;
end;//TEditionsCompareUseCaseData

Итак - мы ПОКА имеем ЧЕТЫРЕ основных понятия - TXXXForm (прецедент), TXXXViewArea (активная зона/вложенный прецедент), TXXXUseCaseData (данные прецедента) и TXXXViewAreaData (данные активной зоны).

Теперь давайте более детально спроектируем один прецедент. Самый "большой". Первый. "Работа с документом":

Ранее мы ПОКА договорились, что TXXXViewArea это "нечто вроде TFrame". Пока этих знаний - нам достаточно.

Но кто же реально визуализирует данные и осуществляет интерактив с пользователем?

Этот момент - мы сейчас более-менее подробно - разберём.

Итак - наш прецедент "работа с документом" с точки зрения представления пользователю ПОКА выглядит вот так:

1. Работа с документом (TDocumentForm):
а. Собственно "текст документа" (TDocumentTextViewArea).
б. Оглавление документа (TDocumentContentsViewArea):
б.1 Список структурных единиц документа (TDocumentStructureViewArea).
б.2 Список иллюстраций в документе (TDocumentPicturesViewArea).
в. Список входящих ссылок на документ (TDocumentIncomingLinksViewArea).
г. Список исходящих ссылок из документа (TDocumentOutgoingLinksViewArea).
д. Аннотация к документу (TDocumentAnnotationViewArea).

Давайте разберёмся - какие конечные компоненты визуализируют те или иные "активные зоны".

Пусть из требований следует что:
а. Собственно "текст документа" (TDocumentTextViewArea) - отображается в виде "текста с гиперссылками и прочим оформлением".
б. Оглавление документа (TDocumentContentsViewArea):
б.1 Список структурных единиц документа (TDocumentStructureViewArea) - отображается в виде "древесной структуры".
б.2 Список иллюстраций в документе (TDocumentPicturesViewArea) - отображается в виде "одноуровневого списка".
в. Список входящих ссылок на документ (TDocumentIncomingLinksViewArea) - отображается в виде "одноуровневого списка".
г. Список исходящих ссылок из документа (TDocumentOutgoingLinksViewArea) - отображается в виде "одноуровневого списка".
д. Аннотация к документу (TDocumentAnnotationViewArea)- отображается в виде "текста с гиперссылками и прочим оформлением" (как и сам текст документа).

Итак мы ПОКА имеем три вида отображения данных:
1. "текст с гиперссылками и прочим оформлением".
2. "древесная структура".
3. "список".

(Не могу не отметить, что для БОЛЬШИНСТВА бизнес-приложений этих способов представления данных - БОЛЕЕ чем достаточно)

Пусть у нас УЖЕ ЕСТЬ компоненты, которые умеет отображать структуры данных в заданном виде:
1. "текст с гиперссылками и прочим оформлением" - TDocumentView.
2. "древесная структура" - TTreeView.
3. "список" - TListView.

Тогда - будем ПОКА считать, что в каждую TXXXViewArea (которая ПОКА по договорённости является TFrame) - вставлен - соответствующий компонент. Например как alClient (это для любителе Delphi). Больше про "геометрию", Owner'а и Parent'а - опять же - ПОКА не говорим.

Теперь как выглядит описание прецедента с точки зрения представления?

А вот так:

type
 TDocumentForm = class(TForm)
 
  DocumentTextViewArea : TDocumentTextViewArea = class(TFrame)
   Text : TDocumentView;
  end;//TDocumentTextViewArea 
 
  DocumentContentsViewArea: TDocumentContentsViewArea = class(TFrame)
 
   DocumentStructureViewArea: TDocumentStructureViewArea = class(TFrame)
    Tree : TTreeView;
   end;//TDocumentStructureViewArea 
 
   DocumentPicturesViewArea: TDocumentPicturesViewArea = class(TFrame)
    List : TListView;
   end;//TDocumentPicturesViewArea
 
  end;//TDocumentContentsViewArea 
 
  DocumentIncomingLinksViewArea: TDocumentIncomingLinksViewArea = class(TFrame)
   List : TListView;
  end;//TDocumentIncomingLinksViewArea
 
  DocumentOutgoingLinksViewArea: TDocumentOutgoingLinksViewArea = class(TFrame)
   List : TListView;
  end;//TDocumentOutgoingLinksViewArea
 
  DocumentAnnotationViewArea: TDocumentAnnotationViewArea = class(TFrame)
   Text : TDocumentView;
  end;//TDocumentAnnotationViewArea
 
end;//TDocumentForm

Проведём предварительный рефакторинг получившейся картины путём выделения "похожих" классов:

type
 TDocumentForm = class(TForm)
 
  TDocumentTextViewArea = class(TFrame)
   Text : TDocumentView;
  end;//TDocumentTextViewArea
 
  DocumentTextViewArea : TDocumentTextViewArea; 
 
  TListViewArea = class(TFrame)
   List : TListView;
  end;//TListViewArea 
 
  DocumentContentsViewArea: TDocumentContentsViewArea = class(TFrame)
 
   DocumentStructureViewArea: TDocumentStructureViewArea = class(TFrame)
    Tree : TTreeView;
   end;//TDocumentStructureViewArea 
 
   DocumentPicturesViewArea: TListViewArea;
 
  end;//TDocumentContentsViewArea 
 
  DocumentIncomingLinksViewArea: TListViewArea;
 
  DocumentOutgoingLinksViewArea: TListViewArea;
 
  DocumentAnnotationViewArea: TDocumentTextViewArea;
 
end;//TDocumentForm

Но теперь встаёт вопрос - "откуда же берутся данные для соответствующих компонент"? Как TXXXUseCaseData и TXXXViewAreaData коррелируют с данными для конечных компонентов?

Это вопрос - мы сейчас и разберём.

В общем - всё - по индукции.
TXXXUseCaseData - содержит в себе TXXXViewAreaData в виде read-only-property, значит - логично предположить, что TXXXViewAreaData содержит в себе TXXXViewData в виде всё тех же read-only-property.

В общем - так оно и есть.

Картина приобретает следующий вид:
type
 TDocumentUseCaseData = class(TUseCaseData)
 
  property DocumentText: TDocumentTextViewAreaData = class(TViewAreaData)
   property Text: TDocument;
  end;//TDocumentTextViewAreaData
 
  property DocumentContents: TDocumentContentsViewAreaData = class(TViewAreaData)
 
   property DocumentStructure: TDocumentStructureViewAreaData = class(TViewAreaData)
    property DocumentStructure : TTree;
   end;//TDocumentStructureViewAreaData
 
   property DocumentPictures: TDocumentPicturesViewAreaData = class(TViewAreaData)
    property Pictures : TList;
   end;//TDocumentPicturesViewAreaData
 
  end;//TDocumentContentsViewAreaData
 
  property DocumentIncomingLinks: TDocumentIncomingLinksViewAreaData = class(TViewAreaData)
   property IncomningLinks : TList;
  end;//TDocumentIncomingLinksViewAreaData
 
  property DocumentOutgoingLinks: TDocumentOutgoingLinksViewAreaData = class(TViewAreaData)
   property OutgoingLinks : TList;
  end;//TDocumentOutgoingLinksViewAreaData
 
  property DocumentAnnotation: TDocumentAnnotationViewAreaData = class(TViewAreaData)
   property Annotation: TDocument;
  end;//TDocumentAnnotationViewAreaData
 
 end;//TDocumentUseCaseData

(Для тех кто в курсе про VCM: TDocument это и есть TXXXDocumentContainer)

И ОПЯТЬ! Проведём предварительный рефакторинг получившейся картины путём выделения "похожих" классов:

type
 TDocumentUseCaseData = class(TUseCaseData)
 
  TDocumentTextViewAreaData = class(TViewAreaData)
   property Text: TDocument;
  end;//TDocumentTextViewAreaData
 
  property DocumentText: TDocumentTextViewAreaData;
 
  TListViewAreaData = class(TViewAreaData)
   property List : TList;
  end;//TListViewAreaData
 
  property DocumentContents: TDocumentContentsViewAreaData = class(TViewAreaData)
 
   property DocumentStructure: TDocumentStructureViewAreaData = class(TViewAreaData)
    property DocumentStructure : TTree;
   end;//TDocumentStructureViewAreaData
 
   property DocumentPictures: TListViewAreaData;
 
  end;//TDocumentContentsViewAreaData
 
  property DocumentIncomingLinks: TListViewAreaData;
 
  property DocumentOutgoingLinks: TListViewAreaData;
 
  property DocumentAnnotation: TDocumentTextViewAreaData;
 
 end;//TDocumentUseCaseData

Идея понятна?

Вот тут наверное подходящий момент, чтобы остановиться и спросить - "а зачем так сложно?"

Я сейчас постараюсь это пояснить.

Во-первых - мне кажется, что в общем - НИЧУТЬ не сложно. Процедура - ФОРМАЛЬНАЯ. И устроена - как "матрёшка", что само по себе (меня лично - радует).

Выделяем прецеденты, потом описываем вложенные прецеденты, потом описываем данные прецедентов и вложенных прецедентов. Потом - детализируем прецеденты и получаем компоненты, которые взаимодействуют с пользователем, потом - описываем - данные для компонентов. Процедура - ФОРМАЛЬНАЯ и рекурсивная.

А во-вторых - вся эта "сложность" во-первых направлена на взаимозаменяемость и гибкость архитектуры, а во вторых - на упрощение рефакторинга и повышение ПОВТОРНОГО использования.

Как? Поясню - чуть позже.

Собственно это станет видно - когда мы перейдём к оставшимся прецедентам.

(Тут "синергия" видна ИМЕННО для СЛОЖНЫХ систем и для систем в которых есть МНОЖЕСТВО "похожих", но в то же время "не похожих" прецедентов)
.....

Теперь вернёмся к списку ответственностей (требований) наших прецедентов.

ПРЕДПОЛОЖИМ, что указанные ответственности:
1. Отображение документа.
2. Скроллирование документа.
3. Навигация курсором в рамках текста документа.
4. Выделение участков текста документа.
5. Копирование выделенных участков в буфер обмена.
-- ПОЛНОСТЬЮ реализуются компонентом TDocumentView (ну - ПОВЕЗЛО нам так с указанным компонентом).

Соответственно эти ответственности - мы смело можем считать реализованными (ну по крайней мере - пока требования не поменяются). И мы СМЕЛО можем их вычеркнуть из списка ответственностей, которые нам надо реализовать. Считаем их - УЖЕ реализованными.

Как быть с ОСТАЛЬНЫМИ ответственностями? А именно:
6. Печать и предварительный просмотр всего документа.
7. Печать и предварительны просмотр выделенных участков документа.
8. Переход по ссылкам. Ссылки бывают - внутренние (внутри данного прецедента) и внешние (между различными прецедентами).
9. Логирование функций работы с документом.
10. Экспорт всего документа в определённые форматы.
11. Экспорт выделенного участка текста в определённые форматы.

На этот вопрос - мы сейчас попробуем ответить. Реализуя далее наш "большой" прецедент - "работа с документом":

Делать мы это будем тут - http://18delphi.blogspot.com/2013/08/mvc_8.html

to be continued...