понедельник, 30 декабря 2013 г.

Ссылка. DelphiSpec неделю спустя



РЕАЛЬНО завидую...

четверг, 26 декабря 2013 г.

Как я решаю проблему "ленивой инициализации" у "себя"

Как я решаю проблему "ленивой инициализации" у "себя".

По мотивам  - http://programmingmindstream.blogspot.ru/2013/12/blog-post_3160.html

Есть СИСТЕМНЫЙ МЕТОД - l3SystemDown (исходники тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/L3/l3Base.pas).

Используется он так:

class function TafwImplementation.Application: IafwApplication;
//#UC START# *4775153A0006_47764F3F0064_var*
 l_AC : TafwApplicationClass;
//#UC END# *4775153A0006_47764F3F0064_var*
//#UC START# *4775153A0006_47764F3F0064_impl*
{$IfNDef DesignTimeLibrary}
 l_AC := GetApplicationClass;
 if (g_Application <> nil) AND not l3SystemDown then
  if not g_Application.InheritsFrom(l_AC) then
   g_Application := l_AC.Create;
  end;//not g_Application.InheritsFrom(l_AC)
 end;//g_Application <> nil
 if (g_Application = nil) AND not l3SystemDown then
  g_Application := l_AC.Create;
 end;//g_Application = nil
 Result := g_Application;
 Result := nil;
{$EndIf  DesignTimeLibrary}
//#UC END# *4775153A0006_47764F3F0064_impl*
procedure RemoveContainer(aCont: Tl3IEBitmapContainer);
 if not l3SystemDown then
 // - не надо ничего удалять в процессе завершения работы, т.к. может оказаться, что и удалять неоткуда 
  if Tl3IEBitmapContainerStack.Exists then
function _l3UnknownPrim_.CheckStamp(const aGUID: TGUID): Boolean;
 {$IfDef _UnknownNeedL3}
 if l3SystemDown then
  Result := false
  Result := IsEqualGUID(l3System.GetStamp, aGUID);
 {$Else _UnknownNeedL3}
 Result := false;
 {$EndIf _UnknownNeedL3}
procedure RemoveResource(const AObject: TvgObject);
  Idx: integer;
  if (g_ResourceList <> nil) then
     Idx := g_ResourceList.IndexOf(AObject);
     on E : Exception do
      if not l3SystemDown then
       g_ResourceList := nil;
     end;//on E : Exception
    if (Idx >= 0) then
     //g_ResourceList[Idx] := nil;
  end;//g_ResourceList <> nil
function vtVGSceneResources: TvtVGSceneResources;
 Assert(not l3SystemDown);
 if (vtStdVGSceneResources = nil) then
  vtStdVGSceneResources := TvtVGSceneResources.Create(nil);
 end;//vtStdVGSceneResources = nil
 Result := vtStdVGSceneResources;

И никакого "шаманства"...

Ссылка. Язык на "закорючках"


Не ну круто наверное... Но не для таких "как я"...

Я дальше "линейной алгебры" - не продвинулся...

У меня проблема в ДНК? Может быть кто-нибудь объяснит мне "что хотел сказать автор"?

В обсуждении (http://18delphi.blogspot.ru/2013/04/vcl-3.html?showComment=1388007562534#c746555596336886486) дали мне ссылку на текст.

Ссылка на текст тут - http://blogs.embarcadero.com/abauer/2010/02/16/38916

Я РЕАЛЬНО НЕ ПОНЯЛ ни ОДНОГО ПРЕДЛОЖЕНИЯ. Проблема у меня в ДНК? Или в тексте?

Может быть кто-нибудь расскажет мне о том - "что там написано"? ОГРОМНОЕ ПОЖАЛУЙСТА! (Ну не хочется "быть идиотом" и "отставать от мейнстрима").


"It seems that my previous post about FreeAndNil sparked a little controversy. Some of you jumped right on board and flat agreed with my assertion. Others took a very defensive approach. Still others, kept an “arms-length” view. Actually, the whole discussion in the comments was very enjoyable to read. There were some very excellent cases on both sides. Whether or not you agreed with my assertion, it was very clear that an example of why I felt the need to make that post was in order.

I wanted to include an example in my first draft of the original post, but I felt that it would come across as too contrived. This time, instead of including some contrived hunk of code that only serves to cloud the issue at hand, I’m going to try a narrative approach and let the reader decide if this is something they need to consider. I may fall flat on my face with this, but I want to try and be as descriptive as I can without the code itself getting in the way. It’s an experiment. Since many of my readers are, presumably, Delphi or C++Builder developers and have some working knowledge of the VCL framework, I will try and present some of the problems and potential solutions in terms of the services that VCL provides.

To start off, the most common case I’ve seen where FreeAndNil can lead to strange behaviors or even memory leaks is when you have a component with a object reference field that is allocated “lazily.” What I mean is that you decide you don’t need burn the memory this object takes up all the time so you leave the field nil and don’t create the instance in the constructor. You rely on the fact that it is nil to know that you need to allocate it. This may seem like the perfect case where you should use FreeAndNil! That is in-fact the very problem. There are cases where you should FreeAndNil in this scenario. The scenario I’m about to describe is not such a case.

If you recall from the previous post, I was specifically referring to using FreeAndNil in the destructor. This is where a very careful dance has to happen. A common scenario in VCL code is to hold references to other component from a given component. Because you are holding a reference there is a built-in mechanism that allows you coordinate the interactions between the components by knowing when a given component is being destroyed. There is the Notification virtual method you can override to know if the component being destroyed is the one to which you have a reference. The general pattern here is to simply nil out your reference.

The problem comes in when you decide that you need to grab some more information out of the object while it is in the throes of destruction. This is where things get dangerous. Just the act of referencing the instance can have dire consequences. Where this can actually cause a memory leak was if the field, property, or method accessed caused the object to lazily allocate that instance I just talked about above. What if the code to destroy that instance was already run in the destructor by the time the Notification method was called? Now you’ve just allocated an instance which has no way to be freed. It’s a leak. It’s also a case where a nil field will never actually cause a crash because you were sooo careful to check for nil and allocate the field if needed. You’ve traded a crash for a memory leak. I’ll let you decide whether or not that is right for your case. My opinion is that leak or crash, it is simply not good design to access an instance that is in the process of being destroyed.

“Oh, I never do that!” That’s probably true, however what about the user’s of your component? Do they understand the internal workings of your component and know that accessing the instance while it is in the throes of destruction is bad? What if it “worked” in v1 of your component and v2 changed some of the internals? Do they even know that the the instance is being destroyed? Luckily, VCL has provided a solution to this by way of the ComponentState. Before the destructor is called that starts the whole destruction process, the virtual method, BeforeDestruction is called which sets the csDestroying flag. This can now be used as a cue for any given component instance whether or not it is being destroyed.

While my post indicting FreeAndNil as not being your friend may have come across as a blanket statement decrying its wanton use, I was clearly not articulating as well as I should that blindly using FreeAndNil without understanding the consequences of its effect on the system as a whole, is likely to bite you. My above example is but one case where you should be very careful about accessing an object in the process of destruction. My point was that using FreeAndNil can sometimes appear to solve the actual problem, when in fact if has merely traded it for another, more insidious, hard to find problem. A problem that doesn’t bite immediately."

Самое что смешное, что я САМ перевёл его примерно так же как и автоматический переводчик:

"Кажется, что мой предыдущий пост о FreeAndNil вызвало небольшой спор. Некоторые из вас прыгнул прямо на борту и помещения согласился с моим утверждением. Другие взяли очень оборонительный подход. Третьи, бдительно "руки длины" вид. На самом деле, вся дискуссия в комментариях было очень приятно читать. Были некоторые очень отличные случаи с обеих сторон. Или вы не согласился с моим утверждением, это было очень ясно, что пример того, почему я чувствовал необходимость сделать этот пост было в порядке.

Я хотел включить пример в моем первом проекте исходное сообщение, но я чувствовал, что это было бы встретить, как слишком надуманный. На этот раз, вместо того, чтобы в том числе некоторые надуманный кусок кода, который только служит для облачных вопрос под рукой, я собираюсь попробовать повествовательный подход и пусть читатель решить, если это то, что они должны рассмотреть. Я может не иметь успеха на моем лице с этим, но я хочу попробовать и быть максимально информативным могу без кода сам получать в пути. Это эксперимент. Так как многие из моих читателей, надо полагать, Delphi или C + + разработчики Builder и есть практическое знание рамках VCL, я постараюсь и представить некоторые из проблем и потенциальных решений с точки зрения услуг, которые предоставляет VCL.

Для начала, самый распространенный случай я видел, где FreeAndNil может привести к странного поведения или даже утечек памяти, когда у вас есть компонент с опорным полем объекта, который выделяется "лениво". Я имею в виду, что вы решите вы не 'т нужно сжечь память этот объект принимает все время, так что вы оставьте поле ноль и не создают экземпляр в конструкторе. Вы полагаться на то, что это ноль, чтобы знать, что вам нужно передать его. Это может показаться идеальным случае, когда вы должны использовать FreeAndNil! То есть в-то, сама проблема. Есть случаи, когда вы должны FreeAndNil в этом сценарии. Сценарий, который я собираюсь описать не такой случай.

Если вы помните из предыдущего поста, я, непосредственно относящиеся к использованию FreeAndNil в деструкторе. Это где очень осторожны танец должно произойти. Обычный сценарий в VCL код провести упоминание другого компонента из данного компонента. Потому что вы держите ссылку существует встроенный механизм, который позволяет координировать взаимодействие между компонентами, зная, когда данный компонент разрушается. Существует Уведомление виртуальный метод можно переопределить, чтобы узнать, если компонент разрушается является тот, на который у вас есть ссылка. Общая картина здесь, чтобы просто ноль ваш ссылку.

Проблема возникает, когда вы решите, что вам нужно, чтобы захватить еще немного информации из объекта пока он находится в муках уничтожения. Это где все становится опасно. Сам факт того, чтобы представить экземпляр может иметь ужасные последствия. Там, где это может вызвать утечка памяти был, если поле, свойство или метод доступны вызвало объект, лениво выделить этот экземпляр я просто говорил о выше. Что делать, если код, уничтожить этот экземпляр уже запущен в деструкторе к тому времени, метод Уведомление назывался? Теперь вы только что выделил экземпляр, который не имеет никакой возможности, чтобы освободиться. Это утечка. Это также случай, когда ноль поле никогда не будет на самом деле привести к аварии, потому что вы были так осторожны, чтобы проверить на ноль и выделить поле, если это необходимо. Вы торгуются обвал на утечки памяти. Я дам вам решить, является ли, что подходит для вашего случая. Мое мнение, что утечка или авария, это просто не хороший дизайн, чтобы получить доступ к экземпляру, который находится в процессе уничтожения.

"О, я никогда не делайте этого!" Это, вероятно, справедливо, однако, что о пользователя вашего компонента? Понимают ли они внутренней работы вашего компонента и знать, что доступ к экземпляр пока он находится в муках уничтожения плохо? Что, если это «работал» в v1 вашего компонента и v2 изменили некоторые из внутренних? Они даже не знают, что экземпляр разрушается? К счастью, VCL предоставил решение этого по пути ComponentState. Перед вызывается деструктор, который начинается весь процесс уничтожения, виртуальный метод, BeforeDestruction называется устанавливающего флаг csDestroying. Это теперь можно использовать как сигнал для любого экземпляра данного компонента является ли оно разрушается.

В то время как мой пост обвинении FreeAndNil как не ваш друг, возможно, встретить, как одеяло заявления осуждают его бессмысленное использование, я был явно не артикулировать, а также я должен, что слепо помощью FreeAndNil не понимая последствий его влияния на систему в целом , скорее всего, чтобы укусить вас. Мой выше пример является лишь одним случаем, когда вы должны быть очень осторожны в обращении объект в процессе уничтожения. Моя точка зрения в том, что с помощью FreeAndNil может иногда появляются решить актуальную проблему, когда на самом деле, если уже просто обменял его на другой, более коварная, трудно найти проблему. Проблема, которая не кусается сразу."

P.S. как выясняется - Я НЕ ОДИН такой....

lulinalex: http://programmingmindstream.blogspot.ru/2013/12/blog-post_3160.html

XXX: Забей это у автора не то с генами

lulinalex: да?! :-) я СЧАСТЛИВ!! :-) СПАСИБО!!!

XXX: Его в комментах вежливо умыли что лучше огрести ав из за nil чем проезд по памяти из за записи в убитый объект

lulinalex: :-)

lulinalex: о чём gunsmoker и писал...

XXX: Он согласился хотя топик не снес

P.P.P.S. Не знаю уж кто такой "abauer" и чем он так "уважаем", но моё "уважение" к нему - ПОДОРВАНО... Раз (и думаю) - НАВСЕГДА...

Ссылка. Почему [не]нужно комментировать код


От себя добавлю. Я ПРЕДПОЧИТАЮ писать такие комментарии:

1. С описанием проблемы.
2. Со ссылкой на ошибку в Bug-Trekker'е.
3. Со ссылкой на тест.
4. Со ссылкой на нетривиальный алгоритм.
5. Документирующие ОСОБЕННОСТИ входа и выхода метода.
6. Документирующие пост- и пред-условия (хотя тут зачастую можно обойтись Assert'ами).

ВСЕ ОСТАЛЬНЫЕ коментарии я считаю - ИЗБЫТОЧНЫМИ и "вредными".

Понятное дело, что "абсолюта" - нет.

И кстати - если мне вдруг "хочется" написать комментарий, то я ПЕРВЫМ ДЕЛОМ думаю о том - "а нельзя ли тут написать Assert". Потом думаю что-то вроде - "а нельзя ли указатель заменить на ссылку". Потом думаю - "можно ли тут написать тест". А потом думаю об изменении наименований.

А потом только пишу комментарий, если другие варианты "не прокатили".

Вопрос только...


"Все - после этого человек официально трудоустроен, заключен договор и прочее.

И вот тут уже доходит очередь и до меня, где я прогоняю человека через несколько тестов (их сейчас 19 - если не ошибаюсь) на основании которых я понимаю в каких областях человек наиболее силен и где его применение будет наиболее выгодно для компании.
Грубо резюмы выглядят примерно так:
отличные знания VCL с углубленкой - рекомендую двинуть на него объем работ по разработке компонент. Или - практическое абсолютное понимание работу служб и сетевого транспорта, предлагаю двинуть его на наши сервера. Очень редко бывает и такое - отличное знание ассемблера, системных документированных и не очень структур, его я забираю себе - он будет помогать мне писать ядро защиты."

Вопрос только...

Человек получит "золотые горы"?... :-)

Или "всё как обычно"...

Как обычно это - http://programmingmindstream.blogspot.ru/2013/12/blog-post_23.html

"И наконец, в-пятых, сотрудник считает, что бенефициаром его усердного, качественного труда будет не он сам, а акционер. "


Вопрос в чём?

А вот в чём - так ли важны для "успешности" такие "мелочи" как "знание ассемблера и недокументированных структур"?

Или это ТУПИКОВЫЙ ПУТЬ? Приводящий к "сидению на месте" и "кручении гаек"...

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

Это - "вопрос вопросов"....

Люди признают, что готовы "пожертвовать качеством"


Люди признают, что готовы "пожертвовать качеством". В зависимости от того - "какие дентги платят":

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

Ну и в общем - ПРАВИЛЬНО. Если "не на окладе".

Ссылка. Книга. IT-проекты. Фронтовые очерки


Аннотация: "Эта книга, написанная живо и интересно, содержит практические рекомендации по управлению проектами, образованные в результате синтеза принципов управления и богатейшего практического опыта автора, и призвана способствовать совершенствованию управления проектами в любой софтверной (и не только) компании. Затронуты разнообразные аспекты создания ПО и управления этим процессом, высказаны оригинальные идеи о сущности программного обеспечения, о том, как мотивировать профессионалов, и о многом другом.

Эта книга будет полезна не только тем, кто занят в производстве ПО. Ее с интересом прочтет менеджер любого уровня."

Ссылка. Страсть к программированию. Глава 20. Телепат

Ссылка. "Ещё о FreeAndNil"

Значит так.

Я ДЛЯ СЕБЯ решил - Я ПИШУ FreeAndNil - ВСЕГДА.


Но не могу не привести контр-мнение - http://blogs.embarcadero.com/abauer/2010/02/16/38916

Ссылка. "Кстати про "хадкорную консоль" Вот эта примочка чуть улучшает стандартый cmd"

Ссылка. Visual Compare

Ссылка. Альтернативный терминал для Windows

ToDo. Blogger Importer

Архив блога

среда, 25 декабря 2013 г.

Ссылка. Language Integrated Query


Про эту "штуку" - до сегодняшнего дня - НЕ ЗНАЛ. Спасибо Namerec'у - ПРОСВЕТИЛ!

Ссылка. Castalia Delphi Parser

Ссылка. Delphi в мире Юникода, часть III: Юникодификация Вашего кода

Ссылка. Анализатор проекта


Ну и "от себя добавлю":

"Но парсер тут это даже не половина работы."

Вот тут себе позволю НЕ СОГЛАСИТЬСЯ.

В том виде в каком автор поста ставит задачу - она (ИМХО) сводится к "реализации парсера" и "построении дерева разбора". К которому затем применяется "поиск по образцу" в поддеревьях

Ну или вообще может быть задача сводится к "тупому распарсиванию USES (рекурсивно)" (я такое - делал. Там не бог весть как сложно) и дальнейшей проверке регулярных выражений.

Если "это так", то может быть вообще стоит посмотреть в сторону Colorer от FAR'а и его регулярных выражений. Там МНОГО чего поделано....

P.S. скажем так - "поставленную задачу" я за месяц-два - решу... НО! именно - "поставленную. БЕЗ "дальнейшего развития".

P.P.S. А если "по уму", то один коллега тут правильно мне написал - "там один сбор требований месяц займет. толком же непонятно что именно надо делать".

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

Ссылка. Ответ на задачку №2, часть первая


На самом деле я про проблему - "знал, но забыл" :-)

СПАСИБО автору, что напомнил и освежил в памяти.

Это кстати одна из мотиваций того почему я написал "собственную канву" и стараюсь пользоваться исключительно ею.

И ещё я писал вот что - http://18delphi.blogspot.ru/2013/04/vcl.html

Что до собственной канвы...

Она правда "сложна". Но оно того стоит.

Offtopic. Вопрос "о железе"...

Неожиданно спросили тут - "что выбрать Intel Core i7-4960X или Intel Core i7-4930K"?

Разница (говорят) в 15К рублей.

Ссылка. TDD for Responsive Design. Или как автоматизировать тестирование отображения сайта для разных устройств с помощью Galen Framework

Ссылка. Жизнь стала серой и однообразной. Пора увольняться?

Ссылка. Inversion of Control Containers and the Dependency Injection pattern

О книгах...

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

Нашёл книгу "Индивидуальная отладка программ" из серии "Библиотечка программиста" (с перфолентой на корешке). Где-то года 1982-го издания.

Что сказать?

Нормальная такая книга.

Про тестирование, "эталоны" и mock'и.

С учётом "небыстрого отклика" при разработке программ....

Я пытался читать её лет двадцать назад. ПЛЕВАЛСЯ - жутко. Думал - "что за хрень".

А сейчас перечитал - ХОРОШАЯ книга :-) ПОЛЕЗНАЯ.

В 1982-м году люди МНОГОЕ уже написали. О том к чему я "сейчас дошёл своим умом".

Люди меняются...

Вот кстати ссылка на книгу - http://www.e-reading.co.uk/book.php?book=132879

"Книга посвящена отладке программ средней сложности или небольших блоков программных систем. Излагаются методика и типовые средства выполнения основных работ, составляющих отладку программ, рассматриваются методы и приемы разработки программ, предупреждающие появление ошибок и облегчающие их обнаружение и устранение. Общая методика отладки, излагаемая в книге, как правило, не зависит от используемых алгоритмических языков и конкретных отладочных средств, но примеры даются для PL|1, фортрана, алгола и для ОС ЕС ЭВМ."

вторник, 24 декабря 2013 г.

Коллега написал. Пример Dependency Injection

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

Изначально это было сделано напрямую:

unit vcmBaseMenuManager;


procedure TvcmBaseMenuManager.RegisterKeywords;
 l_I, l_J : Integer;
 l_En : TvcmBaseEntitiesCollectionItem;
 if not f_KeywordsRegistered then
  f_KeywordsRegistered := True;
  for l_I := 0 to Pred(Entities.Count) do
   l_En := Entities.Items[l_I] as TvcmBaseEntitiesCollectionItem;
   for l_J := 0 to Pred(l_En.Operations.Count) do
    TkwEntityOperation.Register(l_En, l_En.Operations.Items[l_J] as TvcmBaseOperationsCollectionItem);
  end;//for l_I
 end;//not f_KeywordsRegistered

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

Даже наоборот - не нужно знать.

Чтобы обойти эту проблему можно использовать следующий подход: в библиотеке операций создаём утилитный класс-менеджер, который "выставляет" наружу интерфейс для передачи информации выше:

unit vcmOperationsManager;

 IvcmOperationsRegistrar = interface(IUnknown)
   procedure Register(anEn: TvcmBaseEntitiesCollectionItem;
     anOp: TvcmBaseOperationsCollectionItem);

 TvcmOperationsManager = class
   f_Registrar : IvcmOperationsRegistrar;
   procedure Register(anEn: TvcmBaseEntitiesCollectionItem;
     anOp: TvcmBaseOperationsCollectionItem);
   property Registrar: IvcmOperationsRegistrar
     read f_Registrar
     write f_Registrar;
   class function Instance: TvcmOperationsManager;

Также на нём реализован транзитный метод регистрации:

procedure TvcmOperationsManager.Register(anEn: TvcmBaseEntitiesCollectionItem;
  anOp: TvcmBaseOperationsCollectionItem);
 if f_Registrar <> nil then
 // или так: Assert(f_Registrar <> nil); - если мы уверены, что подписка происходит всегда
  f_Registrar.Register(anEn, anOp);

Этот класс создаём синглтоном (http://ru.wikipedia.org/wiki/%CE%E4%E8%ED%EE%F7%EA%E0_(%F8%E0%E1%EB%EE%ED_%EF%F0%EE%E5%EA%F2%E8%F0%EE%E2%E0%ED%E8%FF)#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D0.BD.D0.B0_Delphi)

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

unit kwOperationsRegistrar;


 TkwOperationsRegistrar = class(TObject, IvcmOperationsRegistrar)
   procedure Register(anEn: TvcmBaseEntitiesCollectionItem;
      anOp: TvcmBaseOperationsCollectionItem);
   class function Instance: TkwOperationsRegistrar;

procedure TkwOperationsRegistrar.Register(anEn: TvcmBaseEntitiesCollectionItem;
  anOp: TvcmBaseOperationsCollectionItem);
 TkwEntityOperation.Register(anEn, anOp);

Осталось организовать подписку.

Это можно сделать во многих местах, но мне было удобнее это сделать непосредственно в секции инициализации модуля kwOperationsRegistrar:

 TvcmOperationsManager.Instance.Registrar := TkwOperationsRegistrar.Instance;

Теперь оба синглтона созданы и путь для регистрации операций проложен.

Операции регистрируются через "третьи руки", целостность проекта не нарушена, зато понижена его связность:

В модуле vcmBaseMenuManager вместо строки

    TkwEntityOperation.Register(l_En, l_En.Operations.Items[l_J] as TvcmBaseOperationsCollectionItem);

надо вписать

    TvcmOperationsManager.Instance.Register(l_En, l_En.Operations.Items[l_J] as TvcmBaseOperationsCollectionItem);

Естественно, я не открыл Америку, и этот подход давно известен:


Вывод один - надо больше читать полезной литературы и тогда не придётся ломать голову, как избавиться от лишнего uses-а.
Другой коллега вот дал такую ссылку - http://martinfowler.com/articles/injection.html

понедельник, 23 декабря 2013 г.

Ещё раз про BDD, DelphiSpec & Co

Про BDD (http://en.wikipedia.org/wiki/Behavior-driven_development) "вообще" и "огурец" (http://en.wikipedia.org/wiki/Cucumber_(software)) в частности - я читал "много и вдумчиво".

И НИКАК НЕ МОГ понять "в чём соль".

И хотя я даже приводил ссылки на Романа Янковского (совсем недавно) - http://programmingmindstream.blogspot.ru/2013/12/delphispec.html

И приводил "свою реализацию" http://programmingmindstream.blogspot.ru/2013/12/delphispec_20.html -  (и  - http://programmingmindstream.blogspot.ru/2013/12/delphispec-2.html)

Я ВСЁ РАВНО "не мог понять" - ЗАЧЕМ ЭТО.

Я даже "поглумился" над словами Багеля "UML для начинающих, по сути?" (приведённые вот тут - http://delphimaster.ru/cgi-bin/forum.pl?id=1387384044&n=3&p=1).

Типа "какой UML" и "вообще О ЧЁМ ОН". :-)

И потом я ещё ОЧЕНЬ ДОЛГО думал над вот этой фразой - "вот я и не понял, тест вместо меня будет генерить основной код который мне потом надо будет отлаживать, или я буду писать свой обычный код и потом еще писать сценарии? 
я действительно не вижу причин делать этот over-скриптинг, и думал ты мне на пальцах и своими словами объяснишь, так как статьи на хабре мне никак не объяснили - куча иностранных крутых слов, а конкретики никакой, увидеть бы реальный проект куда оно внедрено, позапускать и сравнить. А то вокруг только теоретические выкладки про "эффективность"" (http://delphimaster.ru/cgi-bin/forum.pl?id=1387384044&n=3&p=3).

Пока не перечитал "раз 10-ть" вот это - http://programmingmindstream.blogspot.ru/2013/12/php-bdd-behat.html и прямая ссылка - http://habrahabr.ru/post/110422/.

"Лирику" про "Feature" и "Should" - опущу.

Заострю внимание вот на чём:

"Сохраняем, и вбиваем в консоль команду
$ behat features

На выходе получаем:
1 scenario (1 undefined)
5 steps (5 undefined)

You can implement step definitions for undefined steps with these snippets:

$steps->Given('/^I have an calculator$/', function($world) {
    throw new \Everzet\Behat\Exception\Pending();

$steps->When('/^I have entered (\d+) as first number$/', function($world, $arg1) {
    throw new \Everzet\Behat\Exception\Pending();

$steps->And('/^I have entered (\d+) as second number$/', function($world, $arg1) {
    throw new \Everzet\Behat\Exception\Pending();

$steps->And('/^I press \'([^\']*)\'$/', function($world, $arg1) {
    throw new \Everzet\Behat\Exception\Pending();

$steps->Then('/^The result should be (\d+)$/', function($world, $arg1) {
    throw new \Everzet\Behat\Exception\Pending();

Это говорит нам о том, что у нас не определены «шаги» сценария. Но мы-то знаем еще больше — у нас нет класса калькулятора. Напишем, не проблема.

class Calc {
    protected $first = 0;
    protected $second = 0;
    protected $result = 0;

    public function setFirst($num){ $this->first = $num; }
    public function setSecond($num){ $this->second = $num; }
    public function add(){ $this->result = $this->first + $this->second; }
    public function getResult(){ return $this->result; } 


Это реально Behaviour Driven Development.

Т.е. - НЕТУ - "over-скриптинг". Есть "описание фич", которое "порождает проектные классы".

Это для языков с Duck-Typing.

Когда Я ЭТО ПОНЯЛ - я сразу написал Роману - "в твоём подходе не хватает "генерилки" классов".

И "ОКАЗЫВАЕТСЯ" - прав был Багель со словами - "UML для начинающих, по сути?" ПРАВ!

ИМЕННО! "UML для начинающих, по сути"!!!

Для Strict-Typing языков правда такое - СЛОЖНЕЕ сделать. Но всё РАВНО МОЖНО.

Я уже примерно понимаю как.

Но "и это не важно"...

Главное - "суть подхода". ОТКУДА и ЧТО берётся. Что "телега", а что "лошадь" (http://programmingmindstream.blogspot.ru/2013/12/test-driven-development.html).

Скажем так. "Если говорить о BDD" - то Роман не с "того конца начал" (это НЕ КРИТИКА, а "заметки на полях"), а я "со своей эмуляцией" - И ПОДАВНО...

Роман С ДРУГОГО и НЕ МОГ начать - в Strict-Typing языке. НЕ МОГ. Иначе - он был бы ГЕНИЕМ.

Но! ГЛАВНОЕ, что "понимание достигнуто"...

За Романа говорить не буду. Но "для меня" это "тот самый текстовый UML" о котором я думаю "уже почти 10-ть лет".

Вот как-то так...

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

ToDo. Про TDD и Agile

A> я уже писал "без Agile" - никуда.. а нашем мире бардака...
A> да и потом - любое "делегирование" это уже - "Agile"
B> вот про делегирование - поподробнее. .
B> тема интересная, насчет делегирования.
A> ну как только заказчик что-то "отдаёт на откуп" - это уже "сразу Agile"
A> напишу наверное... 

Ссылка. DelphiSpec. Работа с "таблицами"


"Feature: Accounts
Scenario: Correct Login
Given users exist:
| id | name | password |
| 1 | Roman | pass1 |
| 2 | Other | pass2 |
When I login with "Roman" and "pass1"
Then I have access to private messages
Scenario: Incorrect Login
Given users exist:
| id | name | password |
| 1 | Roman | pass1 |
| 2 | Other | pass2 |
When I login with "Roman" and "pass2"
Then access denied"


Мои коллеги (знакомые с BDD) сказали, что "РЕАЛЬНО КРУТО" :-)

Я прям ОПЯТЬ "завидую" Роману.

Он "круто пошёл в гору". С "низкого старта".

Если я не ошибаюсь - у него есть все шансы - сделать "продаваемую" вещь.

Ссылка. FluidQuery

Ссылка. Сотрудники ленятся и халтурят, бессовестно глядя нам прямо в глаза. Что с ними делать?

Ссылка. COBOL on Wheelchair ;-)

Ссылка. Страсть к программированию. Глава 11. Научись рыбачить

Ссылка. Using Ruby to Automate Windows GUI Applications for Testing

ToDo. Написать про технику Dependency Injection на двух singleton'ах

ToDo. Написать про технику Dependency Injection на двух singleton'ах.

Которую Миша "изобрёл".

И про то как ЕЮ можно заменить Event'ы "со сложной вложенностью".

И про то, что "похоже на QT" конечно.

суббота, 21 декабря 2013 г.

Ссылка. PHP + BDD = Behat, или сказ о чудо-библиотеке

Ссылка. Readme-driven development


Из комментов понравилось вот что:

"Смысл не в том, что-бы тратить время на написание тестов. А в том, что бы написанием тестов экономить время на написании кода.

Если у вас не так, значит вы не умеете писать тесты."

И ещё:

"Так видимо не дружу с enter. Вообщем TDD это методология написания кода через тесты, тесты в ней используются для того чтобы задать критерий закончености куска кода. То что вы получаете покрытие тестами проекта — всего лишь приятный бонус. Вобщем — то написание в стиле TDD не отменяет написания Unit-Tests и Acceptance Tests. То о чем вы пишите — это автоматические Acceptance Tests. Я лично никогда не видел полностью автоматических Acceptance Test, в основном по причине того что они ацки сложные и хрупкие. Обычно Acceptance Test перекладывают на QA комманду."

Ссылка. Экстремальное программирование, знакомство с Behavior Driven Development и RSpec


Цитата из комментов:

"Честно говоря, статья так и не раскрыла разницу между понятиями «тест» и «должен», функциональное тестирование и unit-тестирование понятия иногда расходящиеся, иногда сходящиеся.

Почему бы «должен» не отнести к «метод А должен возвращать 1, если передали 0», реализация проверки есть самый настоящий «тест».

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

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

Более, того, на мой взгляд необосновано замолчено грандиозное требование TDD к использованию: код, который вы разрабатываете, должен предполагать автоматическое тестирование (!) Данный принцип позволяет проектировать архитектуру приложения исходя из возможности его тестирования автоматическими unit-тестами.

Аббревиатура BDD мне не очень известна, но известен инструмент FIT (и его аналоги), есть некоторые обзоры тут: lobasev.ru/search/label/FIT

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

Подчеркну, что TDD и BDD это не соперники, а скорее совершенно разные методики, которые совместно необходимо применять в проектах."

Ссылка. Товарищ ошибается, хотя и во многом - ПРАВ (хотя и "чудак" на букву М)

Ссылка. Товарищ ошибается, хотя и во многом - ПРАВ (хотя и "чудак" на букву М)


"В конце концов, все разработчики делятся на два типа: те кто не любит писать тесты, и те кто пи… врут." - вот за это "обобщение" - Я ДАЛ БЫ ПО МОРДЕ. Я - ЛЮБЛЮ ПИСАТЬ ТЕСТЫ! (для ИДИОТОВ - ещё раз ПОВТОРЮ - я не "начальник" - я РЕАЛЬНЫЙ РАЗРАБОТЧИК. Я - ЛЮБЛЮ ПИСАТЬ ТЕСТЫ!).

Товарищ извинится (интересно мне) или будет гнуть свою линию? Или ГОТОВ ВСТРЕТИТЬСЯ?

Хотя бы тут ошибается:

"И опять, опять писать эти чёртовы тесты на эти чёртовы изменившиеся требования."

Не "писали эти чёртовы тесты", а "обкатали АРХИТЕКТУРУ". И если заказчик "вернётся к первоначальному варианту" - МЫ ГОТОВЫ!

"Не стоит считать что TDD — панацея." - НЕ ПАНАЦЕЯ... Я о этом - СКАЗАЛ...

"Стоит четко понимать, когда TDD стоит применять (четкое, неизменное ТЗ)," - "чётких ТЗ" - НЕ БЫВАЕТ... Я про это - ТОЖЕ СКАЗАЛ...

"В частности в гибком и часто меняемом проекте TDD скорее лишний груз, который тянет команду назад." - БРЕД - ВСЕ проекты - "гибкие и часто меняемые".

"Который заставляет тратить время на то, что потом будет выброшено на помойку а результатом будет только излишнее раздражение команды." - БРЕД. Товарищ НЕ ПОНЯЛ про "настройку ИНФРАСТРУКТУРЫ".

"И опять, опять писать эти чёртовы тесты на эти чёртовы изменившиеся требования." - БРЕД. Отговорка для ЛЕНТЯЕВ.

Приходите ко мне в курилку. Я вам расскажу - "как правильно писать тесты".

P.S. "нет ТЗ" - НЕТ продукта. Есть только его ВИДИМОСТЬ.

P.P.S. "Разработка code first" - товарищ - НЕВНИМАТЕЛЬНО читал! Я "русским по белому писал" - "НЕТУ test first и НЕТУ code first".

P.P.P.S. "товарищ" НЕ НАПИСАЛ - НИ ОДНОГО СОБСТВЕННОГО поста... Занимается только "критикой".... - http://habrahabr.ru/users/LimeOrange/

Ну и стиль его комментов - "доставляет":

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

"Ну АНБ хоть хватает ума делать это скрытно, а эти — вообще ничего не боятся. Совсем страх потеряли."

"Лучше бы сделали облегченную версию сайта. С модой на js и client-side все вокруг словно с цепи сорвались в последнее время."

"у тормозить на входе так или иначе придется, чтобы не сгореть. Меня интересует почему он именно на главном двиге садится ровно на жопу, вместо использования нескольких двигателей поменьше в верхней части — с таким расположением и со стабилизацией сильно проще, и с маневрированием, да и мощностей для маневровых двигов надо сильно меньше, чем на старте — сажать-то надо уже почти пустую бочку, по сути."

Дальше можно "насладиться" тут - http://habrahabr.ru/users/limeorange/comments/

Ссылка. 3 предельно простые вещи, которые мы узнали про свою команду. Must read

Вот тут товарищ посетовал...

Вот тут товарищ посетовал, что "мол рушатся транзакции (Postgres) из-за нестабильной связи с Дальним Востоком".

Может быть кто-нибудь может посоветовать как это можно тестировать и "лечить" на локале?

Winsock.dll эмулировать и вносить туда "задержки и помехи" или есть более "продвинутые способы"?

Ссылка. Блог Rouse_. Задачка на понимание №2

пятница, 20 декабря 2013 г.

Ещё раз про DelphiSpec и "тестировании по-русски" №2. Для "ценителей"

Предыдущая серия была тут - http://programmingmindstream.blogspot.ru/2013/12/delphispec_20.html

Можно пойти дальше и избавится от глобальной переменной gTestedObject 

Таким образом:

Делаем переменную gTestedObject локальной:

WordWorker2 Scenario: FUNCTOR IN anObjectConstructor
  STRING VAR l_ScenarioName
  // - объявляем переменную для имени сценария
  l_ScenarioName := ( WordToWork1 DO )
  // - получаем имя сценария
  // - кладём имя сценария на стек
  @ (
   OBJECT VAR gTestedObject
   // - текущий тестируемый объект
   gTestedObject := ( 
    // - Обратно переключаемся в режим выполнения
    anObjectConstructor CompileValue
    // - компилируем значение anObjectConstructor как "литерал" в коде
    // - Обратно переключаемся в режим компиляции 
   // - создаём тестируемый объект
    [ WordToWork2 CompileValue ] DO
    // - выполняем код сценария
    gTestedObject TObject.Free
    // - уничтожаем тестируемый объект
  // - компилируем код сценария на стек
  // - регистрируем в тестовой машине тест с именем сценария и указанным кодом
; // Scenario:

Делаем вызываемые слова "зависимыми от контекста вызова" (метим их "директивой" CallerWorker) и используем в них контекст (через конструкцию Caller -> gTestedObject):
 Resut := ( @ TCalculator.Create )
 // - возвращаем указатель на конструктор объекта
PROCEDURE CallerWorker "I have entered {(INTEGER IN aValue)} in calculator"
 aValue Caller -> gTestedObject TCalculator.Push
PROCEDURE CallerWorker "I press Add"
 Caller -> gTestedObject TCalculator.Add
PROCEDURE CallerWorker "I press mul"
 Caller -> gTestedObject TCalculator.Mul
[] FUNCTION CallerWorker "the result should be {(INTEGER IN aValue)} on the screen"
 Result := 
   ( Caller -> gTestedObject TCalculator.GetValue = aValue ) 
   'Incorrect result on calculator screen'

Что мы тут имеем?

Внутри Scenario: мы скомпилировали код, который объявляет переменную gTestedObject.

И зарегистировали его в тестовой машине.

И мы пометили наши "слова обвязки" как "слова зависящие от контекста" ("директивой" CallerWorker).

Этот контекст передаётся в них как "параметр" Caller. "Скрытый". Примерно как Self в методах объектов в ООП.

От которого конструкцией Caller -> gTestedObject мы получаем переменную gTestedObject от КОНКРЕТНОГО контекста вызова.

По-моему - прикольно :-)

Ссылка. Test-Driven Development — телега или лошадь?


Что удивительно - у Леонова даже "карма" вверх попёрла...

Демотиваторы наверное "играют свою роль" :-)

Хотя некоторые вещи он написал так как "хотел услышать", а не так "как было сказано"... :-)

Например в некоторых местах он поменял слово "я" на "мы" и наоборот...

Ну и фразу - "имея ввиду тот процесс “разработки через тестирования», который близко соотносится с энциклопедическим Test Driven Development, но идёт гораздо дальше него." - я бы не стал воспринимать так буквально. Про "идёт гораздо дальше него" - я НЕ ГОВОРИЛ. Я говори про "синтез" и "переосмысление". Далеко НЕ ВСЕГДА "синтез" и "переосмысление" идут ДАЛЬШЕ оригинала.

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

Я работаю на РАБОТОДАТЕЛЯ и на себя. А с Леоновым - делюсь.

Многие другие ведь не готовы "слушать".. А Леонов - слушает...

И что УДИВИТЕЛЬНО - пока нет НИ ОДНОГО комментария... Я ОЖИДАЛ ТОННУ ругательных комментариев... Как в случае с UML - http://habrahabr.ru/post/188604/

Ссылка. Обсуждение DelphiSpec на "Мастера DELPHI"

Ссылка. DUnitLite



Ссылка. Анти-паттерны Test Driven Development. Must read! Must have!



Хотя некоторые "анти-паттерны" - я лично - ПРИМЕНЯЮ. Хотя и не должен бы.

Ссылка. О Test Driven Development (TDD) из личного опыта

Ещё раз про DelphiSpec и "тестировании по-русски"

Ещё раз про DelphiSpec (http://roman.yankovsky.me/?p=1258) и "тестировании по-русски" (http://18delphi.blogspot.ru/2013/11/gui.html).

Побудительным мотивом данного поста послужил комментарий Николая Зверева - "Это действительно круто, наконец-то от требований к тестам всего один шаг — формализовать требования в виде сценария… (ну и со стороны программы предоставить API)".

Тут я понял, что "я не всё правильно рассказал про "свои скрипты"" и что "Роман уделал меня на моём же поле" :-)

Я не претендую на первенство или оригинальность.

Тем более я не хочу умалять достоинства разработки Романа или критиковать её.

Я лишь хочу подкинуть "пищу для размышлений".

среда, 18 декабря 2013 г.


Ссылка. Анонс DelphiSpec


Цитата: "В блоге я уже несколько раз писал о предметно-ориентированных языках (DSL). Эта моя заметка будет куда более приближена к реальной жизни, так что не закрывайте пока страницу."

И ещё цитата: "В этом посте я хотел бы анонсировать библиотеку DelphiSpec. Не буду скрывать, что вдохновил меня проект Cucumber. То есть фактически библиотека является Delphi-реализацией языка Gherkin (переводится как «корнишон»). Реализация не полная (считайте альфа-версией). Некоторых возможностей пока нет, но проект будет развиваться. Мне он интересен."

Что сказать?

ХОРОШАЯ идея и ХОРОШАЯ реализация.

Особенно "приятность" доставляет использование АТРИБУТОВ.

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

Очень жаль, что у меня есть СВОЯ реализация в общем "подобных" вещей.

Иначе бы я воспользовался реализацией Романа, да и поучаствовал бы в ней.

Жаль, что реализация Романа (для меня лично) опоздала лет на 5-ть.

Но у нас уже есть "своё". Хорошо? Плохо? Не знаю.

Но - есть.

И под эту реализацию УЖЕ написано порядка 300 000 строк кода тестов.

И её используют как минимум 6-ть человек. (НЕМНОГО - ДА, но не ОДИН)

И их уже никуда не деть.

Но я буду ВНИМАТЕЛЬНО следить за разработкой Романа.

Она - БОЛЕЕ ЧЕМ перспективна.

И я вообще подумываю - не сделать ли с неё "кальку" для iOS. Где (в силу разных причин) у нас нету (пока) скриптовой машины.

Ссылка. Изучить Github за 15 минут


Что хочу сказать "за себя"? Хочу перейти на git.

P.S. Вот ссылка кстати - https://github.com/bergsteiger/rumtmarc

вторник, 17 декабря 2013 г.

Ссылка. Хамство как аргумент №2


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

Для "любителей" хешей и деревьев.

Степанов сказал примерно следующее - "для БОЛЬШИНСТВА задач должно быть достаточно ОДНОГО контейнера - std::vector. Если вы хотите использовать что-то другое - это БОЛЬШОЙ повод ЗАДУМАТЬСЯ".

И ещё цитата:


"Ну флагмановские продукты на C++ + QT, а новые по-разному, например Лоцман: ПГС на C#"
Вот ТУТ - "мне сделали смешно"... Я лично - "хорошо помню историю C#" и то, что он ПОРТИРОВАЛСЯ с Delphi - "без зазрения совести" :-) С точностью ДО КОММЕНТАРИЕВ в исходном коде.

А вообще... Я наверное - НИКОГДА не пойму - почему так заводят людей "религиозные войны".

Мне лично - ВСЁ РАВНО на чём писать. Главное - ПОДХОДЫ. А подходы (обычно) они - ВЫШЕ языков стоят.

Ссылка. Хамство как "аргумент в споре"

Ещё "о контейнерах"

Пост был тут - http://18delphi.blogspot.ru/2013/09/templates-in-object-pascal.html

И мой комментарий - "Поверьте - я ДАВНО смотрел на stl и ДУМАЛ - "как его написать для Delphi" и когда я прочитал статью Акжана Абдуллина - я "понял КАК"."

МОЙ товарищ мне написал следующее - Печально, что в Delphi приходится задумываться о таком, а не выбирать из готовых реализаций и задумываться уже о решении бизнес задач.

Я ему ответил - Дим, прости, но по-моему - ты меня - "троллишь"  а жаль... Я твоё мнение - уважаю...

Коллега тут написал про ВЫСОКОУРОВНЕВЫЕ (GUI) тесты

Хотел я этот текст обработать и "убрать местную специфику", но чувствую - пока сил на это нет.

Посему (с любезного разрешения коллеги) публикую текст "как есть" скажем так "в RAW-формате".

Мне есть что тут добавить и есть что "убавить", но мысли там изложенные - В ЦЕЛОМ совпадают с моим виденьем.

Посему публикую текст коллеги:

Продолжаю переписывать тесты (пока переписано больше 100 тестов с цепочкой TRY-FINALLY-END). В ходе работы, предложил проверить 2 «новых» сценария сотруднику группы качества с целью убедиться, что сценарий – понятен и воспроизводим.

Выяснилось следующее: 

1. Существует проблема с переводом пикселей в примерные размеры.
2. Сам сценарий, даже самый простой – вызывает дополнительные вопросы. Хотя, такой же сценарий из К (по тексту ошибки) – вопросов не вызывает. Связываю это с наличием картинок в К. Получил такой ответ:
«Если нужно точное воспроизведение – то лучше второй сценарий (старый). Если важно выполнение руками – тогда первый (новый вариант теста). Но большое количество тестов по старому сценарию вручную  – не воспроизвести».
К счастью, точное воспроизведение и не нужно. Его сделает тестовая машина. А человек руками сможет легко сделать примерный сценарий и увидеть в чем проблема.

Также, набросал несколько критериев подробности. Но их нужно еще дополнять.

Критерии подробности для написания тестов и заполнения словарей.

1) Заголовок теста всегда называется Тест K…; слова, которые ничего не оставляют после своего выполнения в стеке – PROCEDURE; слова, которые передают значения в стек для последующей работы – FUNCTION.
2) При написании теста использовать максимально простые и понятные фразы. Их толкование не должно вызывать дополнительных вопросов.
3) Словари делятся на высокоуровневые (прикладные) и низкоуровневые (технические) (они не должны ссылать на высокоуровневые).
4) Избегать дублирования кода.
5) Если мы пытаемся что-то “узнать” у контрола и при этом модифицируем его состояние – это плохо.
6) Если не хватает каких-то ручек для работы с контролами – нужно написать задачу на их создание.
7) Не переусложнять конструкций слов (использовать композицию и декомпозицию).
8) Не пропускать в описании мелочи, которые «известны всем», т.к. то, о чем думает и что известно «писателю», не всегда ясно и известно «читателю».
9) Обязательно! Обязательно при изменении умолчательных настроек, не зависимо от того, как пройдет тест, необходимо вернуть настройки!
10) Максимально приближать алгоритм теста к пользовательским действиям (например, требуется открыть любой список: нужно построить новый список, а не пытаться открыть ранее сохраненный, если это не указано явно).
11) Делать структуру теста плоской, т.е. избегать цепочек Если-то-иначе, TRY-FINALLY-END в тексте теста (нужно прятать их в словари). Тоже самое касается и выполнения определенных действий. Например, «Открыть оглавление и выполнить {(@ Действия)}» можно вызывать через WordWorker: «Открыть оглавление и выполнить» ( … ).
12) Стараться придерживаться единого стандарта при написании новых слов. Например, «Узнать что-то» - записать что-то в стек, «Сравнить с эталоном что-то» - записать что-то в эталон. Заголовки новых слов писать с заглавной буквы.
13) Избегать дублирующихся сценариев. Если они очень похожи – можно во втором тесте постараться добиться нужного результата с помощью с помощью других ручек. Например, отсортировать список, в первом случае, с помощью контекстного меню, во втором случае, с помощью команды главного меню.
14) Избегать использования в тесте английских слов и символов (исключения составляют название теста и названия клавиш).
15) Обязательно оставлять комментарии в местах, сложных для понимания и местах, где изменен исходный сценарий (почему изменен).
16) Не забывать расставлять ASSERTS в новых словах.
17) Не забывать расставлять отступы в коде, для наглядности иерархии.
18) ## - символы, которые несут справочную информацию для «читателя». Например, «## убедиться, что настройки в умолчательном состоянии».

По мотивам поста Леонова про "Delphi и интерфейсы"

Пост вот - http://blogs.embarcadero.com/vsevolodleonov/2013/12/13/bad_gui_in_delph/

Хочется сказать - "пост ни о чём".

Простите за "резкость".

Delphi - тут не причём.

Самый УЖАСНЫЕ интерфейсы знаете какие я видел?



Опять же - на MFC.

И на QT - "хрень" делают. И НЕ "хрень" - тоже.

Просто - Delphi'стов - было МАССОВО. "На коленке". 

И - ДА - не привлекали нормальных дизайнеров и специалистов по UI.

Хотя если вон взять скажем AQTime - ведь - БОЛЕЕ ЧЕМ ДОСТОЙНЫЙ интерфейс.

А есть ещё и ИГРЫ на Delphi. Более чем достойные.

В общем - поделился своим мнением. Если интересно.

И кстати - ГАРАНТ, который написан на Delphi и в котором "я тоже участвовал" - имеет ХОРОШИЙ интерфейс.

И что уж... Консультант-Плюс, который написан на MFC, если я не ошибаюсь - тоже имеет ХОРОШИЙ интерфейс.

И кстати САМА Delphi написанная на Delphi - имеет ХОРОШИЙ интерфейс. ОТВЕЧАЮЩИЙ решаемым ЗАДАЧАМ.

(Правда по мне - XE5 стала "хуже", чем Delphi 7, но это моё частное мнение)

Так что "средство разработки" и "качество интерфейса" - ВЕЩИ - очень СЛАБО взаимосвязанные.

А что до цитаты "В до-дельфийском Borland C++4.x заготовка шаблона диалогового окна подразумевала вертикальное расположение кнопок [Ok] [Cancel] справа. В Delphi можно было кнопки размещать как угодно. Можно ли это считать провокацией? Ровно настолько, насколько таковой считается «свобода» в общем представлении и «гибкость» в сфере инструментов для разработки ПО." - что я хочу сказать про эту цитату?

Я ПЕРВЫЙ, кто ЗА "битьё по рукам".


Поймите меня ПРАВИЛЬНО.

Но я - ЗА!

Кстати - "пример удачного битья по рукам" это - политика Apple. И стараниями этой политики там приложения - более менее - ЕДИНООБРАЗНЫЕ.

Продолжаем "вечер воспоминаний"


-- я вообще "до сегодняшнего момента" думал, что это "тоже PDP"...



Ну и:






"Применяемая в современных серверных и настольных процессорах Intel технология HyperThreading, позволяющая процессору решать несколько задач одновременно, навеяна исследованиями в области многопоточности, проведёнными командой Alpha в DEC в 1990-е годы. Из HP в Intel перешли более 300 инженеров работавших над Alpha, теперь большинство из них работает над процессором Itanium 2."

Может быть кто помнит? Ab Labtam...

Вот тут по мотивам статьи - http://blogs.embarcadero.com/vsevolodleonov/2013/12/13/altium/ - разговорился я с коллегой в курилке.

И вспомнил одну "прелестную штуку" (без всякой иронии) - была такая "машина" - Ab Labtam. Производства австралийской фирмы.

Если ничего не путаю - это была МНОГОПОЛЬЗОВАТЕЛЬСКАЯ система на базе PC XT/AT от австралийской фирмы Ab Labtam.

С операционкой то ли DOS-like, то ли CP/M-like, то ли вообще - Unix-Like.

Да! Да! Многопользовательская. Пятитерминальная.

Видел я "сиё чудо" лет 25 назад в ВКНЦ АМН СССР.

И там же я видел порт редактора WordStar (http://ru.wikipedia.org/wiki/%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D0%BD%D0%BD%D0%B8%D1%85_%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D1%85_%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BE%D1%80%D0%BE%D0%B2). Который "для меня лично" - остаётся "примером для подражания".

И там же было ещё много чудных штучек "портированных" (опять же - если я не ошибаюсь) командой "Прошкина" (это руководитель местного ВЦ в ту пору был).

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

И НИЧЕГО не нашёл.

Нашёл только - http://www.labtam.com.au/

Это - ТА САМАЯ контора. Логотип - ТОТ.

Но упоминаний о "чудо машине" - там - НОЛЬ :-(

А хотелось - почитать спецификацию и архитектуру.

Может быть у кого-то что-то сохранилось на тему машин от ab labtam?

ОЧЕНЬ хотелось бы почитать - "ЧТО это было НА САМОМ ДЕЛЕ"...

P.S. А ещё вот у этого товарища - http://www.findpatent.ru/byowners/7279/ (Коротков Андрей Марксович) - там же в ЭП МБП ВКНЦ я наблюдал Apple II. По тем временам это было "что-то"...

Ссылка. Delphi. Как указать папку "по умолчанию" для новых проектов


Не то чтобы "космос", но по-моему - может быть полезно.

Я правда "сам лично" - давно уже ничего не настраиваю.

А если и настраиваю, то потом сохраняю это дело в виде "батников" (cmd-файлов) и/или веток реестра (reg-файлы). И складываю всё это в CVS или SVN.

А потом если "переезжаю на другую машину" - достаю всё из репозитария и "накатываю" ВСЕ необходимые настройки разом.

"Примеры" кстати тут - https://sourceforge.net/p/rumtmarc/code-0/HEAD/tree/trunk/Blogger/RealWork/env

понедельник, 16 декабря 2013 г.

Перебор файлов по маске. При помощи "анонимных функций"

У нас был код для перебора файлов:

  TFileProcessingFunc = function (const aFileName: string;
                                  aData: Pointer): Boolean;

function ConcatDirName(aDirName : TFileName; aFileName : TFileName) : TFileName;
  if Length(aDirName) = 0 then
   Result := aFileName
   Result := aDirName;
   If (Length(aFileName) = 0) then Exit;
   If Result[Length(Result)] <> '\' then Result := Result + '\';
   If (aFileName[1] = '\') then Delete(aFileName,1,1);
   Result := Result + aFileName;

procedure ProcessFilesWithMask(const aDir, aFileNameMask: TFileName;
                               aFileProcessingFunc: TFileProcessingFunc;
                               aData: Pointer = nil);
 l_SearchRec: TSearchRec;
 l_FindResult: Integer;
 l_FindResult := FindFirst(ConcatDirName(aDir, aFileNameMask),
  while l_FindResult = 0 do
   if (l_SearchRec.Attr and (faDirectory or faVolumeID or faSymLink)) = 0 then
    if not aFileProcessingFunc(ConcatDirName(aDir, l_SearchRec.Name), aData) then


Он переписывается с помощью анонимных функций так:

  TFileProcessingFunc = reference to function (const aFileName: string): Boolean;

function ConcatDirName(aDirName : TFileName; aFileName : TFileName) : TFileName;
  if Length(aDirName) = 0 then
   Result := aFileName
   Result := aDirName;
   If (Length(aFileName) = 0) then Exit;
   If Result[Length(Result)] <> '\' then Result := Result + '\';
   If (aFileName[1] = '\') then Delete(aFileName,1,1);
   Result := Result + aFileName;

procedure ProcessFilesWithMask(const aDir, aFileNameMask: TFileName;
                               aFileProcessingFunc: TFileProcessingFunc);
 l_SearchRec: TSearchRec;
 l_FindResult: Integer;
 l_FindResult := FindFirst(ConcatDirName(aDir, aFileNameMask),
  while l_FindResult = 0 do
   if (l_SearchRec.Attr and (faDirectory or faVolumeID or faSymLink)) = 0 then
    if not aFileProcessingFunc(ConcatDirName(aDir, l_SearchRec.Name)) then


И используется так:

ProcessFilesWithMask('c:\temp', '*.tmp', 
  function (const aFileName: string): Boolean
   Result := true; 

Ну это из разряда "tips'n'tricks"....

P.S. Аналогично можно "переписать" и вот это:

procedure ProcessDirectory(const aDir: TFileName;
                           aFileProcessingFunc: TFileProcessingFunc;
                           aData: Pointer = nil);
 l_SearchRec: TSearchRec;
 l_FindResult: Integer;
 l_FindResult := FindFirst(ConcatDirName(aDir, '*.*'),
                           faDirectory ,
  while l_FindResult = 0 do
   if ((l_SearchRec.Attr and faDirectory) <> 0) and (l_SearchRec.Name <> '.') and (l_SearchRec.Name <> '..') then
    if not aFileProcessingFunc(l_SearchRec.Name, aData) then

   l_FindResult:= FindNext(l_SearchRec);

Ссылка. Objective-C in the Cloud

Ссылка. Паттерны ООП в примерах для iOS

четверг, 12 декабря 2013 г.

Ох что нашёл...

Коротко. Много написал про "примеси и шаблоны"

Вот тут например - http://18delphi.blogspot.ru/2013/07/2.html

Но оказывается надо ещё пояснить:

"давайте разделим...
шаблоны - это шаблоны.. это stl и Степанов...
Include в Delphi - это СПОСОБ реализации шаблонов...
разница чувствуется?"

"МОЯ реализация это "жалкая калька" со Степанова в условиях Delphi" (например СОВСЕМ БЕЗ итераторов)

Ну и "моя калька" - она естественно переписывается при помощи Generic'ов. В СОВРЕМЕННЫХ Delphi.

Ну и "из доисторического". Must Have. Это ОБЯЗАТЕЛЬНО стоит прочитать - http://18delphi.blogspot.ru/2013/09/templates-in-object-pascal.html

Поверьте - я ДАВНО смотрел на stl и ДУМАЛ - "как его написать для Delphi" и когда я прочитал статью Акжана Абдуллина - я "понял КАК".

среда, 11 декабря 2013 г.

Ссылка. Начала Евклида

По мотивам - http://programmingmindstream.blogspot.ru/2013/12/blog-post_1563.html

Сама ссылка - http://ru.wikipedia.org/wiki/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%B0_%D0%95%D0%B2%D0%BA%D0%BB%D0%B8%D0%B4%D0%B0


"Альберт Эйнштейн так оценивал «Начала»: «Это удивительнейшее произведение мысли дало человеческому разуму ту уверенность в себе, которая была необходима для его последующей деятельности. Тот не рождён для теоретических исследований, кто в молодости не восхищался этим творением»"

Первая книга начинается определениями, из которых первые семь (I def. 1-7) гласят:
  1. Точка есть то, что не имеет частей. (Σημεῖόν ἐστιν, οὗ μέρος οὐθέν — букв. «Точка есть то, часть чего ничто»)
  2. Линия — длина без ширины.
  3. Края же линии — точки.
  4. Прямая линия есть та, которая равно лежит на всех своих точках. (Εὐθεῖα γραμμή ἐστιν, ἥτις ἐξ ἴσου τοῖς ἐφ' ἑαυτῆς σημείοις κεῖται)
  5. Поверхность есть то, что имеет только длину и ширину.
  6. Края же поверхности — линии.
  7. Плоская поверхность есть та, которая равно лежит на всех своих линиях.
За определениями Евклид приводит постулаты (I post. 1-5):
  1. От всякой точки до всякой точки можно провести прямую.
  2. Ограниченную прямую можно непрерывно продолжать по прямой.
  3. Из всякого центра всяким раствором может быть описан круг.
  4. Все прямые углы равны между собой.
  5. Если прямая, пересекающая две прямые, образует внутренние односторонние углы, меньшие двух прямых, то, продолженные неограниченно, эти две прямые встретятся с той стороны, где углы меньше двух прямых.
За постулатами следуют аксиомы (I ax. 1-9), которые имеют характер общих утверждений, относящихся в равной мере как к числам, так и к непрерывным величинам:
  1. Равные одному и тому же равны и между собой.
  2. И если к равным прибавляются равные, то и целые будут равны.
  3. И если от равных отнимаются равные, то остатки будут равны.
  4. (И если к неравным прибавляются равные, то целые будут не равны.)
  5. (И удвоенные одного и того же равны между собой.)
  6. (И половины одного и того же равны между собой.)
  7. И совмещающиеся друг с другом равны между собой.
  8. И целое больше части.
  9. (И две прямые не содержат пространства.)
Если я не ошибаюсь - "метрики - тоже определены.

воскресенье, 8 декабря 2013 г.

Кстати товарищ ещё написал "о шаблонах"

"ну тот, кто сам построил пяток своих велосипедов, наверняка лучше поймёт как собрали профессиональный гоночный велосипед и будет уже знать, когда желание что-то в нем подковырнуть действительно приведёт к улучшению характеристик. И поймёт где лучше пешком"

Коллега прислал ещё ссылку. Must Have


Я САМ - НЕ ВСЁ видел. Но! Хочется поделиться...

Я пытался другую книжку читать, но - НЕ ОСИЛИЛ...

Кнута кстати я тоже - "до конца не осилил"...

Offtopic. Offtopic. Я пять лет назад говорил - "не хватает сантехников"

Я пять лет назад говорил - "не хватает сантехников".

Также токарей, слесарей и фрезеровщиков. etc

Теперь про это "НА ФЕДЕРАЛЬНОМ КАНАЛЕ" говорят...

Но "говорить" - МАЛО! НАДО, чтобы они ДОСТОЙНО зарабатывали...

Вот человек "поймал волну" и процитировал мне Степанова

Вот человек "поймал волну" и процитировал мне Степанова.

Как-то так:

"По поводу STL и дублирования кода вспомнилась лекция Степанова (который автор STL). Если есть время - рекомендую. Каких-то технических откровений там нет, но как источник вдохновения очень круто.


Наибольшая общая мера: последние 2500 лет (Originally prepared as the 1999 Arthur Schoffstall Lecture in Computer Science and Computer Engineering at the Rensselaer Polytechnic Institute).

Цель лекции — это убедить слушателя в том, что математика и алгоритмика едины, и что их единство — центральная тема нашей цивилизации. Идея обобщенных алгоритмов не была придумана нами, но имеет древнюю историю.

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

Сам Степанов тут - http://video.yandex.ru/users/ya-events/view/129/#

P.S. а я сам недавно писал вот о чём - http://programmingmindstream.blogspot.ru/2013/12/offtopic.html

Только что прислали ссылку - SapMM

Только что прислали ссылку - SapMM- http://www.thedelphigeek.com/2013/12/sapmm.html

Коротко. "По мотивам"

Коротко. "По мотивам" -  http://blogs.embarcadero.com/vsevolodleonov/2013/12/03/andrey_karpov_3_rec/

Пример с switch - он конечно "ужасен".

И "сначала" я подумал - что-то "не о том товарищ вообще говорит".

Но "к концу" - он "исправился" и стал говорить правильные вещи, типа "пишите ПРОСТОЙ код" и "ДУМАЙТЕ о КОЛЛЕГАХ"!!!

Что касается "использования шаблонов" и stl - хочется сказать - это не признак "крутости". Это скорее признак "зрелости" и "усталости". Да. Да! УСТАЛОСТИ. Когда хочешь "РЕШАТЬ ЗАДАЧИ", а не "писать фреймворки".

Тут уже сразу хочется "ПО-МАКСИМУМУ" использовать "чужое". Уже отлаженное.

И stl - это САМЫЙ ХОРОШИЙ пример.

И ещё - "скорость" vs ООП - это "не самый лучший спор".

Просто надо "думать в терминах предметной области" тогда и "программировать в них" - становится естественно. И тогда и вопроса с vs - не возникнет.

А вообще - хороший вебинар. Правда "америку не открыл". Но "вопросы поставил".

P.S. Когда Андрей сказал "некоторые путают 'эффективный' код с 'коротким'" - я зааплодировал.

P.P.S. И ещё - "шаблоны" надо использовать - не потому, что "круто" и не потому, чтобы "показать свой уровень", а когда - есть ощущение "необходимости". Когда "есть дублирование кода" и "хочется с ним что-то делать", а что делать - "непонятно".

А "дублирование кода" - оно появляется не только из-за "плохого программирования". Зачастую оно появляется "естественным путём". И коллегам в курилке - я НЕ РАЗ про это рассказывал. Оно ЗАЧАСТУЮ появляется тогда, когда появляется ТЗ в таком роде - "сделайте нами примерно такой же прецедент как существующий, но другой, а детали - "мы потом определим"". И тут - САМОЕ дело - "форкнуть разработку", попрограммировать в стиле Copy'n'paste. Получить ПОЛНУЮ КАРТИНУ. ДОРАБОТАТЬ ТЗ. Понять "на самом деле ОБЩИЕ МОМЕНТЫ". А потом ТОЛЬКО - проводить рефакторинг и избавляться от "дублирующегося кода".

Вот ТУТ на сцену приходят - ШАБЛОНЫ, ПРИМЕСИ и АСПЕКТЫ.

P.P.P.S. Ешё написали - "еще бывает, что сначала думаем, что общие моменты есть, а потом оказывается, что их как бы и нет". Собственно ИДЕЯ в этом и была.

P.P.P.P.S. И в СВЕТЕ ЭТОГО хочу сказать ещё одну "крамольную мысль". Борьба с дублированием кода это НЕ ДЛЯ ТОГО, чтобы "меньше кода написать". А для ТОГО, чтобы код потом ПОДДЕРЖИВАТЬ можно было ПРОЩЕ. А так в "дублировании кода" в самом "по-себе" - беды "особо нет".