Коротко. Из диалога об UML

"у меня вообще говоря - "своё виденье" UML... я на него смотрю как на "конструктор прецедентов".. некий "шаблонизатор решений" когда "текст это уже крупно", а "код ещё мелко".. "скелет" сделать.."

(+) http://programmingmindstream.blogspot.ru/2015/04/stl.html

пятница, 24 апреля 2015 г.

Коротко. Вдруг. Что такое STL?

Что такое шаблоны (templates) вообще и STL и скажем boost - в частности.

А это такая "микро"-кодогенерация. Только модель не в UML, А в голове разработчика.

И при желании можно сделать template UseCase и из него породить весь остальной код.

Жаль, что в Delphi нет "нормальных" шаблонов.

С разрешением методов по месту инстанцирования. А не в момент "предкомпиляции" Generic'ов.

Например - http://programmingmindstream.blogspot.ru/2015/04/rtti-checking-member-exists-possibly-in.html

"Ах к носу Иван Иваныча да лицо ПетраПетровича". И "построить мост".

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

А то всё "велосипеды" изобретать приходится.

Но!

http://programmingmindstream.blogspot.ru/2015/04/2010.html
http://sergdankov.blogspot.ru/2012/03/2010.html

"Была высказана мечта о создании единого ЯП. Все остальные - "диалекты". Тут у меня почему-то возникли ассоциации с не очень удачными экспериментами с эсперанто и логлан."

И волапюк - https://ru.wikipedia.org/wiki/%D0%92%D0%BE%D0%BB%D0%B0%D0%BF%D1%8E%D0%BA

Не хочу никого критиковать. Но...

Не хочу никого критиковать. Но...

Работаю в Delphi XE8.

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

Ставят скобки там, где мне не надо. Какими-то автозаменами пытаются заниматься.

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

Может я такой один. Ну тогда - и не стоит обращать на меня внимание.

среда, 15 апреля 2015 г.

У меня есть друг...

У меня есть друг... Хороший друг..

Хотя мы всё время "недолюбливали друг друга".. И были друзья и "поближе"...

Потому, что оба "разные" и оба "имеем своё мнение"...

Мы с ним вместе когда-то ходили в горы...

Вместе занимаемся айкидо...

И он когда-то меня из такого говна вытащил, что дай бог каждому....

Мы все можем "иметь своё мнение", но ДАЙ НАМ БОГ оставаться друзьями..

На ДЕЛЕ..

А не на словах...

http://programmingmindstream.blogspot.ru/2015/04/blog-post_2.html

"Какая мораль может на высоте 8000 метров над уровнем море? Тут уж каждый за себя, лишь бы выжить."

Друзей было много.. Всяких разных.. И тех кому доверял свою страховку.... Когда крюк "бац и вылетел"..

И не могу сказать, что он "жизнь спас"... Но из дерьма вытащил - так точно...

За друзей... Почти тост...

И ещё...

http://infoglaz.ru/?p=18080

Про горы... вспомнилось..

Вот... Это "лицо рынка"...

Наш альпинизм (или горный туризм) - всегда был другой... я верю в это...

На Пике Коммунизма нет таких залежей трупов, хотя он "всего" и на километр ниже..

И мы в горы ходили не "за горами", а за "чувством локтя"...

Я бы своего товарища вот так не бросил бы:


"Какая мораль может на высоте 8000 метров над уровнем море? Тут уж каждый за себя, лишь бы выжить."

И ещё.. "По стопам Джоэла"

http://programmingmindstream.blogspot.ru/2015/04/blog-post_14.html

Многим людям СТОИТ один раз сходить в горы... И почувствовать - что это такое - когда крюк под тобой вырывается...

Ну и для пущего эффекта пролететь метров 15... На верёвке.. И затормозить в конце.. Потому что второй крюк - ВЫДЕРЖАЛ.

И люди МОЖЕТ БЫТЬ научаться "бить крюки"... Точнее - "делать дело".. Качественно..

Огонь и движение
Коротко. Чтобы "писать код".... Надо садиться и "писать код"

Две цитаты..

"Математик во мне говорит, что нет лучшего способа проверить, чем провести расчет. Итак, Алгоритм маляра Шлемиэля:

Маляр Шлемиэль подрядился красить пунктирные осевые линии на дорогах. В первый день он получил банку краски, поставил её на дорогу, и к концу дня покрасил 300 метров осевой линии. "Отлично!" сказал прораб, "быстро работаешь!" -- и заплатил ему копейку.
На следующий день Шлемиэль покрасил 150 метров. "Мда, это, конечно, не так здорово, как вчера, но приемлемо." -- сказал прораб и заплатил ему копейку.
На следующий день Шлемиэль покрасил 30 метров. "Всего лишь 30!" заорал прораб. "Это никуда не годится! В первый день было в десять раз больше! В чём дело?"
"Ничего не могу поделать," -- говорит Шлемиэль. "Каждый день я ухожу всё дальше и дальше от банки!"
Предположим, что кол-во закрашиваемых метров за один подход к банке одинаково и равно Dp, тогда в первый день маляр покрыл растояние:
Dp + Dp + 2Dp + 2Dp + 3Dp + 3Dp +... + M*Dp + M*Dp = [где M*Dp = 300] = 2Dp (1+2+3+... +M) .
Проще показать, если принять Dp=1 м, чтобы не писать громоздких формул, тогда
2(1+2+3+...+300) - это первый день
второй день:
(301 + 301 + 302 + 302 + ... + (N-1) + (N-1) + N + N = 2 (301 + 302 + (N-1) + N) = [ т.к. сумма натуряльного ряда 1+2 + 3+ N = N(N+1)/2 - так называемое треугольное число ] =
2* (N(N+1)/2 - 150*301) = N^2 + N - 90300 , А это O(N^2). Это если считать скорость нанесения разметки и скорость движения постоянными величинами. При этом, если отталкиваться от закрашенного расстояния, то время будет также O(N^2). Кстати, цифры приведенные Джоелом Спольски в данной ситуации довольно сильно преувеличены не в пользу маляра, чтобы это выяснить, достаточно решить квадратное уравнение. Как-то так..."

"Да.... Завидую людям, которые знают что такое “сумма натурального ряда“ и которые умеют определять сложность алгоритмов... Мне уже этого не познать, видимо"

Я лично отношусь к последней категории людей...

Сегодня 9 дней как нет бабушки...


Сегодня 9 дней как нет бабушки...

Она ЖЕНА ОФИЦЕРА.. И ВЕТЕРАН ТРУДА..

БССР между прочим...

И это - НЕ Offtopic...

ПОВТОРЮ..

Она ЖЕНА ОФИЦЕРА.. И ВЕТЕРАН ТРУДА..

Жена ОФИЦЕРА СССР.

вторник, 14 апреля 2015 г.

Что я хочу?

http://programmingmindstream.blogspot.ru/2014/11/mindstream.html

НИКТО из идеологов RUP Не ОБЪЯСНИЛ "как и зачем"..‏

а я хочу сделать ИНСТРУМЕНТ - для ремесленников‏...

И я - ЗНАЮ, что и КАК надо делать ДЛЯ ремесленников типа меня‏

"Ну и КОНЕЧНАЯ ЦЕЛЬ проекта - сделать "коробочный продукт" для ВЕДЕНИЯ ИНФРАСТРУКТУРЫ проекта - от ТЗ, модели (UML) и прецедентов, до кода, тестов и "скриптовой автоматизации".

В виде отдельностоящего приложения или плагина к Delphi - я ещё не решил как точно.

Идея примерно такая:

1. Пишем ТЗ.
2. Рисуем прецеденты на модели.
3. Транслируем прецеденты и их детализацию в "скелеты сервисов" - http://programmingmindstream.blogspot.ru/2015/03/blog-post_12.html
4. Реализуем код сервисов.
5. Используем сервисы в приложении.
6. Регистрируем сервисы в скриптовой машине.
7. Пишем тесты (модульные, нагрузочные, регрессионные и GUI) на основе сервисов - http://programmingmindstream.blogspot.ru/2015/02/gui.html.
8. В итоге получаем приложение, которое использует сервисы как для РЕАЛИЗАЦИИ, так и для ТЕСТИРОВНИЯ.
9. В итоге получаем - "хорошо тестируемое приложение" - http://18delphi.blogspot.ru/2014/05/blog-post.html.

И в итоге - моя "дорожная карта" - сойдётся."‏

ну это - вкратце.

Я хочу "построить Храм, а не класть кирпичи".

Я конечно хочу "заработать денег", но это - совсем не главное... Главное "продать идею".. Или подарить... От "ремесленника" к "ремесленнику"...

Offtopic. Мы в то время в горы плотно ходили

Мы в то время в горы плотно ходили.

Я даже "чуть на пик Ленина не залез". А были и те, кто залез - http://programmingmindstream.blogspot.ru/2014/11/offtopic_24.html

https://www.youtube.com/watch?v=tAkbeZX-JsU&feature=youtu.be

"Антураж" - знаком..

"Сублимация"... У всех разная... Но суть- одна..

Но это ЛУЧШЕ, чем "майдан" - Oftopic. Oftopic. Oftopic. Про Украину, Майдан и "недоигравших"


Offtopic. Коротко. О схожести

Занимаюсь айкидо. Просто "потому, что это красиво"...

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

"Календарно" уже десять лет.

Ну а плотно (честно) - лет пять.

Честно и плотно - это так, чтобы "убиваться и падать".. вставать.. "убиваться и падать".. И ОПЯТЬ.. вставать.. "убиваться и падать".. Не чувствуя своего дыхания.. Чтобы сердце зашкаливало.. Чтобы вышел в тренировки и понял - "я всё честно делал"... А не "просто" пришёл и "помахал руками и ногами"...

Как в горах - на вершину взошёл.. И нету ни радости, ни печали... Одна лишь усталость... И понимание - "я сделал это"... Посидел, покурил... и вниз..

И тут на очередном занятии меня "прошибло"... (Я занимаюсь тут по утрам со своим хорошим другом)

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

Руку "сюда", ногу "сюда".. тут "натянул"..тут "недотянул".. Тут надо "чувствовать"...

Примерно как в программировании, когда меня спрашивают - "как ты это делаешь", "почему ты ЗНАЛ, что ошибка там"... "ну и как бы я нашёл эту ошибку"...

Ответ - НИКАК...

Просто я "Миллион раз это делал"... Тупо и нудно..

ОБЪЯСНИТЬ - невозможно.. Надо тупо и нудно - МИЛЛИОН раз упасть..

И ещё МИЛЛИОН раз взмахнуть мечом... ПРАВИЛЬНО.

Я уже МИЛЛИОН раз взмахнул мечом.. НЕПРАВИЛЬНО.

Буду учиться ТЕПЕРЬ это делать ПРАВИЛЬНО.

Так же и в программировании.

Да!...Я ещё в горы ходил.. НО это - отдельная история...

P.S. самые "фундаментальные" разработки я придумал будучи в горах.. Вешая очередную верёвку.. в отрыве от компьютеров...



P.P.S. всегда надо представлять, что у противника в руках нож.

Коротко. Ни о чём. Инверсия зависимостей

Занимаюсь последнее время перетряхиванием наших библиотек на предмет исправления зависимостей.

В библиотеках несколько миллионов строк кода и несколько тысяч модулей.

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

И это не "пустые разговоры" ни о чём.

У нас за долгое время работы было написано:

1. Собственный текстовый редактор на уровне Word 97.
2. Собственная реализация IStorage. Эффективнее, чем у MS.
3. Собственный полнотекстовый индексатор.
4. Расширения к DUnit.
5. Собственная скриптовая машина (FORTH-like) на уровне Python.
6. Собственная реализация тестирования GUI-сценариев - на "естественном языке".
7. Собственный рендеринг RTF-like документов для iOS.
8. Собственная реализация SAX и DOM парадигм.
9. Собственная кодогенерация из UML.
10. Собственная реализация MVC-like фреймворка.

Зависимости показывает лишь рисование всего этого хозяйства на UML с последующей валидацией связей и циклов. А также кодогенерацией.

И уже не раз я применил нехитрый приём "инверсии зависимостей".

Который мне крайне нравится.

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

Приведу пример. БЕЗ шаблона кодогенерации. В БАЗОВЫХ примитивах.

Выглядит примерно так:

Было:

A call B.method

A было связано с B,

стало:

A call C.method
B implements C.method

A связано с C.
B связано с C.

A про B теперь ничего не знает.
B про A - тоже ничего не знает.

A знает про C.
B знает про C.

С выполняет роль "сервиса" с возможностью подмены поведения.

Диаграмма:




Код:

Точка инъекции:

unit l3DispatcherHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Библиотека "L3$AFW"
// Модуль: "w:/common/components/rtl/Garant/L3/l3DispatcherHelper.pas"
// Родные Delphi интерфейсы (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Low Level::L3$AFW::VCMHelpers::Tl3DispatcherHelper
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// ! Полностью генерируется с модели. Править руками - нельзя. !

{$Include ..\L3\l3Define.inc}

interface

uses
  l3ProtoObject
  ;

(*
 Ml3DispatcherHelper = PureMixIn
   procedure ClearHistory;
 end;//Ml3DispatcherHelper
*)

type
 Il3DispatcherHelper = interface(IUnknown)
   ['{41B8F325-9AFB-447E-B3E7-2C433912BC2A}']
  // Ml3DispatcherHelper
   procedure ClearHistory;
 end;//Il3DispatcherHelper

 Tl3DispatcherHelper = class(Tl3ProtoObject)
 private
 // private fields
   f_Alien : Il3DispatcherHelper;
 public
 // realized methods
   procedure ClearHistory;
 protected
 // overridden protected methods
   procedure ClearFields; override;
     {* Сигнатура метода ClearFields }
 public
 // public methods
   procedure SetAlienHelper(const anAlien: Il3DispatcherHelper);
   class function Exists: Boolean;
     {* Проверяет создан экземпляр синглетона или нет }
 public
 // singleton factory method
   class function Instance: Tl3DispatcherHelper;
    {- возвращает экземпляр синглетона. }
 end;//Tl3DispatcherHelper

implementation

uses
  l3Base {a}
  ;


// start class Tl3DispatcherHelper

var g_Tl3DispatcherHelper : Tl3DispatcherHelper = nil;

procedure Tl3DispatcherHelperFree;
begin
 l3Free(g_Tl3DispatcherHelper);
end;

class function Tl3DispatcherHelper.Instance: Tl3DispatcherHelper;
begin
 if (g_Tl3DispatcherHelper = nil) then
 begin
  l3System.AddExitProc(Tl3DispatcherHelperFree);
  g_Tl3DispatcherHelper := Create;
 end;
 Result := g_Tl3DispatcherHelper;
end;


procedure Tl3DispatcherHelper.SetAlienHelper(const anAlien: Il3DispatcherHelper);
//#UC START# *5501A41602E7_5501A3AE02AA_var*
//#UC END# *5501A41602E7_5501A3AE02AA_var*
begin
//#UC START# *5501A41602E7_5501A3AE02AA_impl*
 Assert(f_Alien = nil);
 f_Alien := anAlien;
//#UC END# *5501A41602E7_5501A3AE02AA_impl*
end;//Tl3DispatcherHelper.SetAlienHelper

class function Tl3DispatcherHelper.Exists: Boolean;
 {-}
begin
 Result := g_Tl3DispatcherHelper <> nil;
end;//Tl3DispatcherHelper.Exists

procedure Tl3DispatcherHelper.ClearHistory;
//#UC START# *5501A435019E_5501A3AE02AA_var*
//#UC END# *5501A435019E_5501A3AE02AA_var*
begin
//#UC START# *5501A435019E_5501A3AE02AA_impl*
 if (f_Alien <> nil) then
  f_Alien.ClearHistory;
//#UC END# *5501A435019E_5501A3AE02AA_impl*
end;//Tl3DispatcherHelper.ClearHistory

procedure Tl3DispatcherHelper.ClearFields;
 {-}
begin
 f_Alien := nil;
 inherited;
end;//Tl3DispatcherHelper.ClearFields

end.

Собственно инъекция:

 TvcmDispatcherHelper = class(Tl3ProtoObject, Il3DispatcherHelper)
 public
 // realized methods
   procedure ClearHistory;
 public
 // public methods
   class function Exists: Boolean;
     {* Проверяет создан экземпляр синглетона или нет }
 public
 // singleton factory method
   class function Instance: TvcmDispatcherHelper;
    {- возвращает экземпляр синглетона. }
 end;//TvcmDispatcherHelper
...
// start class TvcmDispatcherHelper

var g_TvcmDispatcherHelper : TvcmDispatcherHelper = nil;

procedure TvcmDispatcherHelperFree;
begin
 l3Free(g_TvcmDispatcherHelper);
end;

class function TvcmDispatcherHelper.Instance: TvcmDispatcherHelper;
begin
 if (g_TvcmDispatcherHelper = nil) then
 begin
  l3System.AddExitProc(TvcmDispatcherHelperFree);
  g_TvcmDispatcherHelper := Create;
 end;
 Result := g_TvcmDispatcherHelper;
end;

class function TvcmDispatcherHelper.Exists: Boolean;
 {-}
begin
 Result := g_TvcmDispatcherHelper <> nil;
end;//TvcmDispatcherHelper.Exists

procedure TvcmDispatcherHelper.ClearHistory;
//#UC START# *5501A435019E_5501A60D002E_var*
//#UC END# *5501A435019E_5501A60D002E_var*
begin
//#UC START# *5501A435019E_5501A60D002E_impl*
 if (vcmDispatcher <> nil) then
  if (vcmDispatcher.History <> nil) then
   vcmDispatcher.History.Clear(false);
//#UC END# *5501A435019E_5501A60D002E_impl*
end;//TvcmDispatcherHelper.ClearHistory

...
 Tl3DispatcherHelper.Instance.SetAlienHelper(TvcmDispatcherHelper.Instance);
...

И вообще говоря подобную технику применяет Embarcadero в FMX.

У них это называется сервисы (Services).

Ну с полноценным Service-Locator'ом.

Ну а в НЕБАЗОВЫХ примитивах это выглядит ПРОЩЕ. Но об этом я напишу в следующий раз. Если будет интерес.

Для любителей "придираться к пробелам и запятым" - ПОДЧЕРКНУ, что это всего лишь - ИДЕЯ, а не руководство к действию.

Ну и понятное дело - ссылку на Spring For Delphi - я уже приводил.

И ещё коллега писал на ту же тему - Коллега написал. Пример Dependency Injection.

И ещё:

Ссылка. Критический взгляд на принцип инверсии зависимостей
Ссылка. Принцип инверсии зависимости

И сходная тема была поднята тут - О тестах и специально оборудованных "контрольных точках"

P.S. Мы за последние несколько недель сделали несколько десятков сервисов. И очень сильно развязали зависимости между библиотеками.

P.P.S. Продолжение - http://programmingmindstream.blogspot.ru/2015/03/blog-post_73.html

Коротко. Продолжение про инверсию зависимостей

Продолжение про инверсию зависимостей.

Исходный пост был тут - Коротко. Ни о чём. Инверсия зависимостей.

Там были две диаграммы:

Диаграмма 1:


Диаграмма 2:

Я немного "поколдовал" над шаблонами генерации и диаграммы стали такими:

Диаграмма 1:

- тут мы фактически определяем сервис DispatcherHelper.

Диаграмма 2:
- тут мы определяем одну из реализаций сервиса DispatcherHelper. С именем TvcmDispatcherHelper.

Код остался ТЕМ ЖЕ.

Реализация шаблонов:

: ServicePrim::Class
= SimpleClass::Class

// Функции стереотипа

%f _st_space_key
 SHD

%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BA9C0354*
//#UC END# *5502C6A200F5for5502BA9C0354*

%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BA9C0354*
//#UC END# *5502CBD4031Efor5502BA9C0354*

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BA9C0354*
 [{%Gx!=true}\
 [{"%{Tl3ProtoObject}N"=""}%f_find_element(Tl3ProtoObject,Tl3ProtoObject)]\
 %S%f_make_accessable(%{Tl3ProtoObject}U)\
 %S%f_add_inheritable(%{Tl3ProtoObject}U)\
 ]\
 %S%f_set_up(singleton,true)\
 %S%f_BeforeClassSpell()\
 %S%[inherited]\
 %S%f_AfterClassSpell()
//#UC END# *4B2A19E3038Bfor5502BA9C0354*


: Service::Class
? Сервис
= ServicePrim::Class

// Параметры стереотипа
a f
/ - тип абстракции

// Функции стереотипа

%f _st_space_key
 SHD

%f _CheckMixin
//#UC START# *5502CBF50065for5502BABC0193*
 [{"%S%{Mixin}N"=""}\
 <{}{%C#f_IsPureMixIn()=true&"%CN"="M%f_cut_prefix(%f_pas_TypeName(%S),T)"}\
 %S%f_set_var(Mixin,C)\
// %f_cycle_break(%S)\
 >\
 ]
//#UC END# *5502CBF50065for5502BABC0193*

%f _CheckFacet
//#UC START# *5502CC07027Efor5502BABC0193*
 [{"%S%{Facet}N"=""}\
 <{}{%t_interface(%C)=true&"%CN"="I%f_cut_prefix(%f_pas_TypeName(%S),T)"}\
 %S%f_set_var(Facet,C)\
// %f_cycle_break(%S)\
 >\
 ]
//#UC END# *5502CC07027Efor5502BABC0193*

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BABC0193*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BABC0193*

// перекрытие базового стереотипа ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BABC0193*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BABC0193*

// перекрытие базового стереотипа ServicePrim::Class
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BABC0193*
 %S%f_CheckMixin()\
 %S%f_CheckFacet()\
// %f_warning(Mixin: %S%{Mixin}N)\
// %f_warning(Facet: %S%{Facet}N)\

 [{"%S%{Facet}N"=""}\
 %S%f_add_class(%SU_Facet,Facet,I%f_cut_prefix(%f_pas_TypeName(%S),T),Facet_Inst)\
 %{Facet_Inst}%f_set_documentation(Интерфейс сервиса %SN)\
 %S%f_set_var(Facet,{Facet_Inst})\
 ]\

 %S%f_add_realized(%S%{Mixin}U)\
 %S%{Facet}%f_add_realized(%S%{Mixin}U)\

 %S%f_add_attribute(%SU_%S%{Facet}U_Alien,writeonly,Alien : %S%{Facet}U,Attr_Inst)\

 %{Attr_Inst}%f_set_link_type(ref)\
 %{Attr_Inst}%f_set_up(pm,true)\
 %{Attr_Inst}%f_set_up(needs field,true)\
 %{Attr_Inst}%f_set_visibility_type(PublicAccess)\
 %{Attr_Inst}%f_set_abstraction_type(final)\
 %{Attr_Inst}%f_set_documentation(Внешняя реализация сервиса %S%{Facet}N)\

 %{Attr_Inst}%f_set_uc_content(intf.pas,_%f_pas_MethodOwnerID(%{Attr_Inst},%S)set_var,\
  {-}\
 )\

 %{Attr_Inst}%f_set_uc_content(intf.pas,_%f_pas_MethodOwnerID(%{Attr_Inst},%S)set_impl,\
  Assert((f_Alien = nil) OR (aValue = nil));
  f_Alien := aValue;\
 )\

 %f_DoSpellField(%{Attr_Inst})\

// %f_warning(%SN need cleanup: %S%f_NeedCleanupFields())\

 %S%[inherited]
//#UC END# *5502C6A200F5for5502BABC0193*

// Вложенные стереотипы

: Service::Class::responsibility::Operation
? Ответственность
= ClassBase::Class::Operation

// Параметры стереотипа
v +
/ - типы видимости
a f
/ - тип абстракции
T 
/ - может не иметь "цели" (типа/результата)
m f
/ - не может быть реализован/иметь перекрытую реализацию

// Генераторы
// Генерация модели в MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BBDB02C9*
//#UC END# *46E6D4BB0339for5502BBDB02C9*

// генератор реализации фабрик интерфейсов на java (.java)
+ fctr.java
//#UC START# *470321C1038Afor5502BBDB02C9*
//#UC END# *470321C1038Afor5502BBDB02C9*

// Вторая интерфейсная секция стереотипа. Например реализация свойств класса.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BBDB02C9*
//#UC END# *477398E501C0for5502BBDB02C9*

// 3-я секция интерфейса. Например поле для свойства.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BBDB02C9*
//#UC END# *4774D2A20372for5502BBDB02C9*

// Генератор файлов форм (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BBDB02C9*
//#UC END# *49F5795900ECfor5502BBDB02C9*

// Скрипты TC (.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BBDB02C9*
//#UC END# *4DE79AFC0030for5502BBDB02C9*

// Хак для [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BBDB02C9*
//#UC END# *4E65F581015Afor5502BBDB02C9*

// Родные Delphi интерфейсы (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BBDB02C9*
//#UC END# *470F1571031Cfor5502BBDB02C9*

// Реализация на Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BBDB02C9*
//#UC END# *470F15B800CBfor5502BBDB02C9*

// Функции стереотипа
%f _st_space_key
 SHD

// Унаследованная реализация

// реализация абстрактного стереотипа Документация::MDAGenerator
// вывод описание авто-генерируемых методов в wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BBDB02C9*
//#UC END# *470484D50138for5502BBDB02C9*


: ServiceImplementation::Class
? Реализация сервиса
= ServicePrim::Class

// Параметры стереотипа
a f
/ - тип абстракции

// Функции стереотипа

%f _st_space_key
 SHD

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BADD01CB*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BADD01CB*

// перекрытие базового стереотипа ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*

// перекрытие базового стереотипа ServicePrim::Class
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BADD01CB*
 <{}{%CC=Dependency&%CS=implements}\
 %C%T#f_CheckFacet()\

// %f_warning(%C%TN)\
// %f_warning(%C%T%{Facet}N)\
// %f_warning(%C%T%{Facet}U)\

 [{"%C%T%{Facet}N"!=""}\
 %S%f_make_accessable(%C%T%{Facet}U)\
 %S%f_add_realized(%C%T%{Facet}U)\
 ]\
 >\

 %S%f_add_operation(%SU_Ini_Reg_Class,ini,bind (),Op_Instance)\
 %{Op_Instance}%f_set_documentation(Регистрация %SN)\
 %{Op_Instance}%f_set_abstraction_type(final)\
 %{Op_Instance}%f_set_visibility_type(PrivateAccess)\
 %{Op_Instance}%f_set_uc_content(intf.pas,,\
 <{\n}{%CC=Dependency&%CS=implements}\
  %f_pas_TypeName(%C%T).Instance.Alien := %f_pas_TypeName(%S).Instance;\
 >\
 )\

 %S%[inherited]
//#UC END# *5502C6A200F5for5502BADD01CB*

// Вложенные стереотипы

: ServiceImplementation::Class::implements::ClassDependency
? Указание, что реализуется
= Delphi интерфейсы и реализация::MDAGenerator

// Генераторы
// Генерация модели в MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BC8E029A*
//#UC END# *46E6D4BB0339for5502BC8E029A*

// Родные Delphi интерфейсы (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BC8E029A*
//#UC END# *470F1571031Cfor5502BC8E029A*

// Реализация на Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BC8E029A*
//#UC END# *470F15B800CBfor5502BC8E029A*

// Вторая интерфейсная секция стереотипа. Например реализация свойств класса.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BC8E029A*
//#UC END# *477398E501C0for5502BC8E029A*

// 3-я секция интерфейса. Например поле для свойства.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BC8E029A*
//#UC END# *4774D2A20372for5502BC8E029A*

// Генератор файлов форм (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BC8E029A*
//#UC END# *49F5795900ECfor5502BC8E029A*

// Скрипты TC (.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BC8E029A*
//#UC END# *4DE79AFC0030for5502BC8E029A*

// Хак для [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BC8E029A*
//#UC END# *4E65F581015Afor5502BC8E029A*

// Функции стереотипа
%f _st_space_key
 SHD

// Унаследованная реализация

// реализация абстрактного стереотипа Документация::MDAGenerator
// проверка ограничений накладываемых на элемент
%t _constraint
//#UC START# *4704C0E30186for5502BC8E029A*
c          {}
r {""=""}: {}
//#UC END# *4704C0E30186for5502BC8E029A*

// реализация абстрактного стереотипа Документация::MDAGenerator
// выводит описание элемента (операция, атрибут) в wiki
%f _wiki_child_kind
//#UC START# *4705CBD6003Efor5502BC8E029A*
//#UC END# *4705CBD6003Efor5502BC8E029A*

// реализация абстрактного стереотипа Документация::MDAGenerator
// вывод описание авто-генерируемых методов в wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BC8E029A*
//#UC END# *470484D50138for5502BC8E029A*


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

Небольшая легенда:

%S - это Self.
\ - это ;
%P - родительский элемент.
%G - это базовые классы.
%R - это реализуемые интерфейсы.
%T - это тип выражения.
%C - это дочерние элементы.
%CN - имя дочернего элемента. Т.е. на "привычном языке" это - Child.Name.
%CS - имя стереотипа дочернего элемента.
%S%{Facet} - значение поля (member) от Self. Т.е. на "привычном языке" это - Self.Facet.
%f _Name - объявление функции с именем Name текущего стереотипа (метод класса).
f _Name - объявление свободной функции.
%t _constraint - объявление трансформатора с именем constraint текущего стереотипа. Аналог Case.

: ServiceImplementation::Class - объявляет стереотип ServiceImplementation.

= ServicePrim::Class - наследует его от ServicePrim.

? Реализация сервиса - задаёт документацию к текущему элементу.

Цикл:

<{}{%CS=Dependency}%CN>
// - перебирает дочерние элементы, которые являются зависимостями и выводит их имена (%CN)

<{}{%t_simple_class(%P)=true}%PN>
// - перебирает родителей, которые являются "простыми классами" и выводит их имена (%PN)

Оператор if:

[{"%S%{Mixin}N"=""}\
<{}{%C#f_IsPureMixIn()=true}\
%S%f_set_var(Mixin,C)>\
]
// - if Self.Mixin.Name = ''
//    for C in Self.Children (if C.IsPureMixIn) do
//     Self.Mixin := C
// т.е. если Self.Mixin не установлено, то ищем среди детей, того который является PureMixIn

Метод стереотипа:

%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*
// procedure Service.AfterClassSpell; override;
//begin
// inherited;
//end;

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

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

Не потому, что люди не знают про инверсию зависимостей (Dependency inversion principle).

А потому, что людям зачастую "лень" писать "всё это хозяйство".

Проще "лишний uses написать".

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

И это - нормально.

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

Пояснение про "Объявление. Ищу сотрудника для реализации проекта"

Пояснение про "Объявление. Ищу сотрудника для реализации проекта"

У меня реально мало свободного времени.

Гораздо меньше, чем идей для реализации.

И идеи я реализую во внерабочее время. И оно крайне ценно.

На работе я реализую, пусть и "схожие" задачи, но другие.

И я всецело занят ими.

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

Я утрирую конечно.

Но как-то так.

И ешё:

Насчёт соглашений о стиле кода - дело такое - смотрите как оформлен код в уже существующих модулях и старайтесь следовать общему стилю.

Ещё два важных момента:

1. Для ЛЮБОЙ задачи отводим СВОЮ ВЕТКУ от Developing. И коммитим и пушим в эту ветку. Обратно в Developing сливаю я.

2. Как только отвели ветку - надо запустить тесты. И посмотреть - прошли они или нет. Если не прошли, то разобраться почему. Ну и далее в процессе переделок запускаем тесты и смотрим на их результат.

Development Case - у меня нет. Если сильно надо, то можно со временем написать.

Но я предпочитаю подход - "задал вопрос, получил объяснение, пишешь документацию" - О коммуникациях и "передаче знаний".

И ещё...

У меня тут некоторые напряги в семье - поэтому ближайшее время могу быть не всегда доступен.

Список задач можно посмотреть тут:
https://bitbucket.org/lulinalex/mindstream/issues?status=new&status=open

Да! И если я кому-то кажусь снобом, то таки я - не сноб. Я просто 20-ть лет на одном месте работаю. Так что - да - несколько зашорен.

И ешё. Сторонние библиотеки мы принципиально не используем. Должна быть очень веская причина, чтобы использовать сторонние библиотеки.

И да. Мы исповедуем MDP.

И ещё - по деньгам - я предельно честен. Вы делаете код, я плачу деньги. НО! Нет кода - нет денег. Все остальные детали - обсуждаемы. Плачу я из своего кармана. Из "подушки".

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

И ещё - не стоит упоминать JSON и XML. У меня на них - аллергия. Я уже лет двадцать занимаюсь обработкой различных форматов данных - Обработка текстов. Генераторы, фильтры, трансформаторы и "SAX на коленке".

В проекте я выполняю роли:

1. Представителя заказчика.
2. Архитектора (и эту "поляну" я обычно НИ С КЕМ не делю).
3. Программиста.
4. Тестировщика.

Ну и КОНЕЧНАЯ ЦЕЛЬ проекта - сделать "коробочный продукт" для ВЕДЕНИЯ ИНФРАСТРУКТУРЫ проекта - от ТЗ, модели (UML) и прецедентов, до кода, тестов и "скриптовой автоматизации".

В виде отдельностоящего приложения или плагина к Delphi - я ещё не решил как точно.

Идея примерно такая:

1. Пишем ТЗ.
2. Рисуем прецеденты на модели.
3. Транслируем прецеденты и их детализацию в "скелеты сервисов" - http://programmingmindstream.blogspot.ru/2015/03/blog-post_12.html
4. Реализуем код сервисов.
5. Используем сервисы в приложении.
6. Регистрируем сервисы в скриптовой машине.
7. Пишем тесты (модульные, нагрузочные, регрессионные и GUI) на основе сервисов - http://programmingmindstream.blogspot.ru/2015/02/gui.html.
8. В итоге получаем приложение, которое использует сервисы как для РЕАЛИЗАЦИИ, так и для ТЕСТИРОВНИЯ.
9. В итоге получаем - "хорошо тестируемое приложение" - http://18delphi.blogspot.ru/2014/05/blog-post.html.

И в итоге - моя "дорожная карта" - сойдётся.

понедельник, 13 апреля 2015 г.

Проект MindStream под Delphi XE8 Win 64 запустился

Проект MindStream под Delphi XE8 Win 64 запустился.

Запустил тесты.

Тесты прошли, с точностью до "всё того же пикселя" - http://programmingmindstream.blogspot.ru/2015/04/delphi-xe8_11.html

суббота, 11 апреля 2015 г.

Поставил Delphi XE8

Поставил Delphi XE8. Собрал приложение. Собралось.

Запустил. Запустилось. Всё работает.

Прогнал тесты. Отличаются эталоны записи в png. Где-то на 1 пиксель.

Коротко. Что такое лямбды?

https://ru.wikipedia.org/wiki/%D0%9B%D1%8F%D0%BC%D0%B1%D0%B4%D0%B0-%D0%B8%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5#.D0.92_.D1.8F.D0.B7.D1.8B.D0.BA.D0.B0.D1.85_.D0.BF.D1.80.D0.BE.D0.B3.D1.80.D0.B0.D0.BC.D0.BC.D0.B8.D1.80.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D1.8F

"В языках программирования под «λ-исчислением» зачастую понимается механизм «анонимных функций» — callback-функций, которые можно определить прямо в том месте, где они используются, и которые имеют доступ к локальным переменным текущей функции."

https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D0%BD%D0%B0%D1%8F_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F


Лямбда на то и ЛЯМБДА, что имеет доступ к ВЫЗЫВАЮЩЕМУ КОНТЕКСТУ.

var
 l_Stream : TFileStream;
begin
 l_Stream := TFileStream.Creat;
TraverseTree(procedure (const aNode: TNode)
 var
  l_T : String;
 begin
  l_T := l_Node.Text;
  l_Stream. // <- l_Stream - ДОСТУПЕН тут
   Write(@l_T, Length(l_T));
 end
)
end;

"Новые записи"от EMBT это - БОМБА

"Новые записи"от EMBT это - БОМБА.

По моему скромному мнению.

Просто посмотрите сюда:

Коротко. Слабая ссылка на интерфейс.
https://bitbucket.org/lulinalex/mindstream/commits/bf726c3a47cc61b1216f0085919f5d3633324356.

Ещё бы деструкторы для записей сделали и можно было бы нормальное RAII использовать.

[dcc32 Error] msInterfaces.pas(193): E2465 A record cannot introduce a destructor

А зря... Можно было бы делать AutoPtr'ы в стиле C++.

И тогда бы Delphi был бы крут. Более чем крут.

Хочешь ARC, хочешь "ручное управление".

Хочешь "чёрта лысого" - тоже можно.

Коротко. Поток сознания про атрибут [Weak]

По мотивам - Коротко. Слабая ссылка на интерфейс.

Поговорим про объекты.

Вот у нас есть ARC.

На "мобильных устройствах".

И там есть атрибут [Weak].

А есть Win-32 и Win-64.

Где ARC по умолчанию - нет.

И как писать реально кросс-платформенный код?

Учитывая тот факт, что на эмуляторе и на устройстве - отлаживаться "долго и нудно".

А вот так - ввести класс (запись) - WeakObjectRef.

Ну и StringObjectRef "до кучи".

Идея понятна? Или довести её до кода?

Ну и ссылки:

Об "опасностях" ARC и прочих "автоматов" (набор ссылок).
Про ARC.

Ну и ещё вам коммит в тему - https://bitbucket.org/lulinalex/mindstream/commits/21ae139f9a346046ce90dbcc056f066f3033edc0

Почему-то без AsRef обойтись не удалось. Ошибка?

Завёл задачу - https://bitbucket.org/lulinalex/mindstream/issue/229/embt-c-implicit

А вот так - работает - И ещё хороший коммит

Поколение пепси

По мотивам - Объявление. Ищу сотрудника для реализации проекта

Пришло тут письмо:

"Здравствуйте, меня зовут Артем. Сейчас проживаю в Кемерово. Мне 24 и я программист)))

Работаю на делфях уже более 3х лет. В универе плотно прогал на С#, поэтому проблем с коллекциями и ооп нет))) хорошее знание Ms SQL сервера, проектирование бд, написание запросов.

Честно скажу, не знаком на практике с юнит тестами и свн, но если нужно разберусь.

Хотелось бы узнать больше о вас, проекте, сколько человек в нем будет работать, какие задачи нужно делать и примерную оплату))"

Читаю...

"прогал"...

"хорошее знание"... Это при 3-х годах работы.

На минуточку - человеку - 24 года.

ОТКУДА хорошее знание - не знаю.

Слово "прогал" - так вообще - "убил бы головой об стену".

Ну думаю - это "ВО МНЕ проблема". Я слишком требователен к людям.

Дальше общаемся.

Пишу (у чтобы всё открыто было):
"Здравствуйте.

Значит смотрите какая штука.
Пишем мы редактор UML. Скажем так - аналог Rational Rose. Но с шаблонной кодогенерацией.

Мотивацию зачем - сейчас объяснять не буду.

Я тут работал с одним человеком с Украины. Не сдельно, а платил ему фиксированный оклад. 400 долл.

Но в итоге меня перестала удовлетворять его качество работы.

Посему - я готов выдать "тестовое задание" ну и обсудить дальнейшие детали.

Фиксированный оклад я платить сейчас наверное не готов. Если сработаемся, то вполне готов.

С уважением: Александр Люлин.

P.S. Удалось посмотреть описание/репозитарий проекта? Вот ссылка - https://bitbucket.org/lulinalex/mindstream/overview".

Далее следует рабочая переписка.

Даю задание:

"Я репозитарий вроде поправил. Можно вытягивать и пробовать собирать. Даже ветку master. Тестовое задание будет после того, как всё соберётся."

Получаю ответ:

"Т.е. с той ссылки весь проект скачать и попробовать у себя скомпилить?)"

Отвечаю (не без иронии конечно):

"Ну да. Какие то другие бывают варианты работы над проектом? "

Ну думаю - человек поймёт иронию. Ответит.

Ответил:

"Эгегей, палехче, я просто спросил. И работы еще никакой не было, не забывай)"

Если честно - "офигеваю"...

"Эгегей, палехче" - это у молодёжи нынче так модно на работу наниматься?

"не забывай" - я как-то пропустил момент где мы на ты перешли?

Или водку вместе пили?

Или верёвки по сложным скалам вешали (http://18delphi.blogspot.ru/2013/04/vcl-3.html?showComment=1388419570830#c5813130760698428954)?

Вроде не пили и не вешали...

Ну да ладно.

Пишу:

"Сразу до свидания."

Ну тоже едко, но вроде "в рамках".

Получаю ответ:

"Давай Хамло покеда=))) Научись сперва норм с людьми работать)))"

О как!

Я = хамло. :-)

Ну да.. Наверное...

Я ведь не вник в то, что мне сей вьюнош донести пытается...

Да - я - Хамло.

Почти как Путин. :-)

Ну что сказать - "человек сразу раскрылся" :-) не пришлось тратить на него время.

Надеюсь, что и я - сразу раскрылся.

Я - не люблю "эгегей" и "тыканья".

Я - требователен - да. Но я - не деспот.

Хотя меня и назвали - "зануда, пребывающий в иллюзии, что он - гениален и шедеврален... а на самом деле обычное серое чмо, причем, хамовитое и озлобленное" - http://programmingmindstream.blogspot.ru/2014/08/mindstream-firemonkey.html?showComment=1407936000707#c4892634008350853276

Я не против "общаться на ты", отнюдь. Но только если обе стороны договорились об этом.

Наверное я старею...

вторник, 7 апреля 2015 г.

Коротко. По-моему - интересный коммит

https://bitbucket.org/lulinalex/mindstream/commits/fbb79262ed8bddc577290e96c01f0da1ce79eeb3

"- добавляем примитив User - чисто для того, чтобы проверить и продемонстрировать подход с "наследованием"."

Ссылка. Кэширование объектов StringBuilder

http://sergeyteplyakov.blogspot.ru/2015/04/cache-for-stringbuilder-objects.html

Цитата:

"В текущем проекте народ очень серьезно подходит к вопросам производительности: куча структур, кастомный внешний кэш, и свой собственный object pool для хранения тяжеловесных объектов. Одним из типов объектов, которые хранятся в пуле и используются повторно являются объекты StringBuilder. И я задался вопросом, насколько это полезно.
Начиная с .NET 4.0 реализация StringBuilder-а была существенно переработана. В первых версиях реализация напоминала классический вектор – для хранения создаваемой строки использовалась изменяемый объект System.String (*), размер которой увеличивался вдвое при ее полном заполнении.
(*) Строки являются неизменяемыми лишь с точки зрения внешних кода, но с точки зрения внутреннего (internal) кода pre-.NET4.0 строки были очень даже изменяемыми.
Кэширование StringBuilder-ов с такой реализацией имело смысл. В этом случае приложение могло прийти к устойчивому состоянию своей работы, когда в памяти хранилось лишь небольшое число объектовStringBuilder с большим внутренним буфером (многопоточное обращение к пулу приведет к тому, что число объектов в пуле будет более одного). Это позволит использовать повторно внутренний буфер строки и не плодить объекты в куче больших объектов."

 (+)
Атомарные (Immutable) строки - это хорошо.
Delphi Language для мобильной разработки.

Коротко. Хочу отсканировать "бумажки"

По мотивам - Бумажки. Бумажки. Надо обязательно написать пост про бумажки

Хочу отсканировать "бумажки". За последние две-три недели. Которые я специально не выкидывал.

Чтобы было понятно "о чём речь".

Что такое "микроменеджмент".

Знали бы вы какие шаблоны кодогенерации я за последние две недели на работе написал...

Знали бы вы какие шаблоны кодогенерации я за последние две недели на работе написал...

Даже и не знаю как их в блоге описать.

Я сделал шаблон, который делает шаблон, который делает шаблон, который делает шаблон ... , который делает код.

На самом деле не совсем так.

На самом деле я сделал шаблон, который порождает элементы модели, которые порождают элементы модели, которые порождают элементы модели ... , которые порождают код.

Но идея именно такая.

Ну и ссылка на старую статью - Пример использования шаблонов генерации.

Прислали ключ к Delphi XE8

Прислали ключ к Delphi XE8.

Вот что написано в сопроводительном письме:

"We will formally announce the general availability of RAD Studio XE8 tomorrow, Tuesday April 7 at 12:01am PDT. A press release will appear and the product pages for RAD Studio, Delphi and C++Builder XE8 will appear. Once the press release appears, feel free to start blogging and promoting XE8."

Буду пробовать.

пятница, 3 апреля 2015 г.

Коротко. Слабая ссылка на интерфейс

Иногда надо хранить СЛАБЫЕ ссылки на интерфейсы (без подсчёта ссылок).

Аналог атрибута [Weak].

Например для publisher/subscriber.

"Определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии."

Так вот вам решение:

type
 TmsWeakInterfaceRef = record
 // Слабая ссылка на интерфейс
  rShape : Pointer;
  constructor Create(const aShape: T);
  function AsShape: ImsShape;
  class operator Equal(const A: TmsWeakInterfaceRef; const B: TmsWeakInterfaceRef): Boolean;
  class operator Equal(const A: TmsWeakInterfaceRef; const B: T): Boolean;
  class operator Implicit(const aShape: T): TmsWeakInterfaceRef;
 end;//TmsWeakInterfaceRef

 TmsWeakShapeRef = TmsWeakInterfaceRef;
...
// TmsWeakInterfaceRef

constructor TmsWeakInterfaceRef.Create(const aShape: T);
begin
 Assert(SizeOf(T) = SizeOf(IUnknown));
 Move(aShape, Self.rShape, SizeOf(T));
end;

function TmsWeakInterfaceRef.AsShape: ImsShape;
begin
 Result := ImsShape(Self.rShape);
end;

class operator TmsWeakInterfaceRef.Equal(const A: TmsWeakInterfaceRef; const B: TmsWeakInterfaceRef): Boolean;
begin
 Result := (A.rShape = B.rShape);
end;

class operator TmsWeakInterfaceRef.Equal(const A: TmsWeakInterfaceRef; const B: T): Boolean;
var
 l_P : Pointer;
begin
 Assert(SizeOf(T) = SizeOf(Pointer));
 Move(B, l_P, SizeOf(T));
 Result := (A.rShape = l_P);
end;

class operator TmsWeakInterfaceRef.Implicit(const aShape: T): TmsWeakInterfaceRef;
begin
 Result := TmsWeakInterfaceRef.Create(aShape);
end;

Ссылка на коммит - https://bitbucket.org/lulinalex/mindstream/commits/825ca7487905ce786aa9f44b6a0d95e570b06b71

Ещё коммит - https://bitbucket.org/lulinalex/mindstream/commits/861e56e0bff2613b652d633f0183c93fde75601e

Окончательная версия:
type
 TmsWeakInterfaceRef = record
 // Слабая ссылка на интерфейс
  rRef : Pointer;
  constructor Create(const aShape: T);
  function AsRef: T; inline;
  class operator Equal(const A: TmsWeakInterfaceRef; const B: TmsWeakInterfaceRef): Boolean;
  class operator Equal(const A: TmsWeakInterfaceRef; const B: T): Boolean;
  class operator Implicit(const aShape: T): TmsWeakInterfaceRef;
  class operator Implicit(const aValue: TmsWeakInterfaceRef): T; inline;
 end;//TmsWeakInterfaceRef

 TmsWeakShapeRef = TmsWeakInterfaceRef;
...
// TmsWeakInterfaceRef

constructor TmsWeakInterfaceRef.Create(const aShape: T);
begin
 Assert(SizeOf(T) = SizeOf(IUnknown));
 Move(aShape, Self.rRef, SizeOf(T));
end;

function TmsWeakInterfaceRef.AsRef: T;
begin
 Result := nil;
 Assert(SizeOf(T) = SizeOf(Result));
 Move(Self.rRef, Result, SizeOf(T));
 Result._AddRef;
end;

class operator TmsWeakInterfaceRef.Implicit(const aValue: TmsWeakInterfaceRef): T;
begin
 Result := aValue.AsRef;
end;

class operator TmsWeakInterfaceRef.Equal(const A: TmsWeakInterfaceRef; const B: TmsWeakInterfaceRef): Boolean;
begin
 Result := (A.rRef = B.rRef);
end;

class operator TmsWeakInterfaceRef.Equal(const A: TmsWeakInterfaceRef; const B: T): Boolean;
var
 l_P : Pointer;
begin
 Assert(SizeOf(T) = SizeOf(Pointer));
 Move(B, l_P, SizeOf(T));
 Result := (A.rRef = l_P);
end;

class operator TmsWeakInterfaceRef.Implicit(const aShape: T): TmsWeakInterfaceRef;
begin
 Result := TmsWeakInterfaceRef.Create(aShape);
end;

четверг, 2 апреля 2015 г.

Смешное про Implicit

Есть класс:

 TmsShapeUID = record
  rValue: Int64;
  public
   class operator Add(anUID: TmsShapeUID; aDelta: Int64): TmsShapeUID;
   class operator Implicit(aValue: Int64): TmsShapeUID;
 end;//TmsShapeUID

Должно было быть так:

class operator TmsShapeUID.Implicit(aValue: Int64): TmsShapeUID;
begin
 Result.rValue := aValue;
end;

Но описался, и написал так:

class operator TmsShapeUID.Implicit(aValue: Int64): TmsShapeUID;
begin
 Result := aValue;
end;

И получил Stack Owerflow.

Что в общем-то - логично.

Но всё равно - смешно.

Я бы лично отсёк бы это на уровне компилятора. Ибо там - "делать нечего".

Есть "дерево разбора" и есть "его бесконечная рекурсия".

Ну и полный коммит - https://bitbucket.org/lulinalex/mindstream/commits/879c8e09bb457061e4fce20e238e9b1e151f387e

Он тоже по-моему - интересен.

среда, 1 апреля 2015 г.

Коротко. JSON, Unmarshal и TInterfacedObject - это "что-то"

Коротко. JSON, Unmarshal и TInterfacedObject - это "что-то".

Надеюсь, что сейчас будет коммит.

Там конечно беда с подсчётом ссылок.

Первый коммит вот - https://bitbucket.org/lulinalex/mindstream/commits/25fe403c08ab76e206b9d6525e786ec0bff327fb

Так - НЕ РАБОТАЕТ.

Второй коммит вот - https://bitbucket.org/lulinalex/mindstream/commits/d10acb6683d2bceaa034e7940e68165e941f539b

Так - РАБОТАЕТ.

Это то же - стыдно.

Реально стыдно. Так писать код.

В чём проблемы - могу теперь описать. "На пальцах".

Если кому-то интересно.

Игорь +Igor Belyh а я вам НЕ РАЗ говорил, что НЕ НАДО связываться с JSON, особенно в реализации от Embarcadero.

Вот ЕЩЁ раз имеем прецедент.

ОЧЕРЕДНОЙ баг для QualityCentral.

Ещё коммит:
https://bitbucket.org/lulinalex/mindstream/commits/86768b2233e1c63f40af0c4503fd9426f7b42ede

И чёрта два я нашёл бы ошибку, если бы не - Коротко. Контроль за созданием/освобождением объектов. Только код. №4.

И никакой бы FastMM не помог бы.

И ещё коммит - https://bitbucket.org/lulinalex/mindstream/commits/9d9d9e1770347a3414f5a2816b3dec37863c5fad

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

Коммит, который приближает нас к цели - https://bitbucket.org/lulinalex/mindstream/commits/dbc9ede9ff4198513a36b6cfdcc382555e918735

Ещё коммит, который подводит нас к пониманию происходящего - https://bitbucket.org/lulinalex/mindstream/commits/89b0af9065df50f86f709941d832de8344533425

А вот тут начинаем решать нашу проблему - https://bitbucket.org/lulinalex/mindstream/commits/7bc0b30c1e16a3386843c397987b4d8209a2a1e0

Добился желаемого (костыль, но иначе - пока не придумал) - https://bitbucket.org/lulinalex/mindstream/commits/272a9c09b9177e38966753c5eabbef7d38e411eb

Ну и это тоже "правильный" коммит - https://bitbucket.org/lulinalex/mindstream/commits/71b1564259e9396f2379329e1103c77652295dc1

Провёл сегодня личную встречу с Денисом Васильевым

Провёл сегодня личную встречу с Денисом Васильевым.

Рассказал ему и показал наши разработки.

Были продемонстрированы:

1. GUI-тесты.
2. Unit-тесты.
3. Регрессионные тесты.
4. Редактор Эверест.
5. Редактор формул.
6. Кодогенерация.
7. Баг-терккинг.
8. MindStream UML.
9. DUnit для FMX.

Почти всё из - Дорожная карта.

Встреча прошла плодотворно.

Я бы на месте Дениса написал бы "краткий очерк" :-) +Денис Васильев

Мне кажется, что Денис увидел, что есть реально большие проекты, написанные на Delphi. И даже часть их работает под Delphi XE7.

И ещё Денис спросил - "как ваше начальство вам позволяет делать всё это". На что я ему ответил - "мы честно делаем своё дело и выполняем все задачи, а это позволяет нам выполнять наши задачи".