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

Offtopic. Briefly. About similarities

I go in for aikido. Simply “because it is graceful”...
Also, because the “heady air” after training creates an illusion of being in the mountains...
In numbers – for 10 years already.

But closely (honestly) – for five years.

To train honestly and closely means to “break and fall”… stand up… “break and fall”… AGAIN stand up… “break and fall”….Feeling no breath… The heart beats off-scale… When the training session is out, you understand – “I did it honestly”… I did not just “come and wave my hands and my arms”...

As in the mountains – I climb on a peak... Feeling no joy and no grief... But mere exhaustion... Understanding – “I’ve made it”… I sit there for a while and have a smoke… and go down…

Suddenly, at a regular training it “stroke” me... (I train in the mornings with my good friend.)

I seem to “know how to do”, but I don’t understand the idea.

I move my arm “here”, my leg “there”, I “stretch” here but “fell short” there… I have to “feel” these things...

In a way, it is similar to programming – when they ask me, “How do you do this?”, “How did you know the error was there?” or “How would you find the error?”...

The answer is ANYHOW...

I just do it “a million times”… Straight and tiresomely…

It is impossible to EXPLAIN…You have to fall – a MILLION times, straight and tiresomely…

And you have to swing your blade a MILLION times… RIGHT.

I swung my blade a MILLION times… WRONG.

NOW I will learn to do it RIGHT.

It is similar to programming.

Wait!... I have not been in the mountains yet… BUT this is a separate story…

P.S. My most “fundamental” developing were made in the mountains… when I was hanging another rope… in isolation from computers…


P.P.S. You always have to imagine that your opponent holds a knife in his hand.

They ask me…

Original  in Russian: http://18delphi.blogspot.ru/2013/04/blog-post_13.html

How can it be possible that I have been working for 17years at one place?

Do I have nowhere to go? Or am I so stupid?

Nowhere is a wrong word (though, I have not been invited)… I am not stupid, too…

Did you bring up YOUR children? I only begin to… My daughter is almost 6 and my son is 4 years old…

Same with my work…

I “brought up” much. I’d hate to leave. It is not honest, too – to leave.

But, more likely, it’s a pity since so much effort was put.

There’s no other choice but to search for the harmony in what I have. And, in fact, it is there…

I’d really like to tell about what I’ve reached with my “ball-breaker”...

I do tell “inside” myself… And get no response… This is not because “no one understands”… This is more likely because “everybody knows”… I tell about TRIVIAL things...

My colleagues are not sensitive to these things… They UNDERSTAND it without me...

They ALREADY reached “zen”… and they draw the energy from the “space”…

P.S. Just in case, this has nothing to do with sarcasm.

The work is GOOD… It is very technological... It is difficult to judge from outside… Sometimes I look at our inside technologies and think – “why the pillars like MS or IBM did not think these up?” Or did they think these up and hide it ELABORATELY? Or may be it was not necessary?

As for “17 years”… I’d like to think I am a “black sheep”… I LIKE to do what I do, I have no reasons to change something…

Two quotes…

Original in Russian: http://programmingmindstream.blogspot.ru/2015/04/blog-post_15.html

"In terms of mathematics, there’s no better way to check than to calculate. So, Shlemiel the painter’s algorithm.

Shlemiel the painter contracted to paint the dotted road center lines. On the first day, he was given a paint can, put it on the road and, by the end of the day, painted 300 m of center line. “Well done!”, the foreman said, "you work hand over hand!”, and paid him a penny.

The following day, Shlemiel painted 150 m. “Hrmph, this is not that great as yesterday but good enough”, the foreman said and paid him a penny.

The following day, Shlemiel painted 30 m. “30 meters, just that!", the foreman roared. “This is no good at all! You did 10 times more on the first day! What’s the matter?"

"Can’t hale it," Shlemiel said. "Every day I go away from the can farther and farther!"

Suppose, the number of meters painted within one approach to the can is constant and equals Dp, so on the first day the painter covered the distance:

Dp + Dp + 2Dp + 2Dp + 3Dp + 3Dp +... + M*Dp + M*Dp = [где M*Dp = 300] = 2Dp (1+2+3+... +M) .

It is more clear with Dp taken as 1 m, in order to get rid of lengthy formulas. In this case, calculations are as follows:
2(1+2+3+...+300) – the first day,

the second day:
(301 + 301 + 302 + 302 + ... + (N-1) + (N-1) + N + N = 2 (301 + 302 + (N-1) + N) = [ since natural series sum 1+2 + 3+ N = N(N+1)/2 – is the so-called triangular number ] = 2* (N(N+1)/2 - 150*301) = N^2 + N - 90300 , А это O(N^2).

This is so if we assume the line painting quickness and the speed of movement to be constant. At the same time, if we start from the distance painted, the time is also O(N^2). By the way, the figures given by Joel Spolsky about it are rather exaggerated not to painter’s credit. To see it, one needs only to solve an equation. That is so somehow..."

"I’ll say... I am jealous of the people who know what “natural series sum” is and who can find algorithm complexity... Seems to me, I am too old to learn it."

I personally belong to the second group of people...

Briefly. Again about dependency inversion

Original in Russian: http://programmingmindstream.blogspot.com/2015/03/blog-post_73.html

Again about dependency inversion.

The source code was here – Briefly. Shooting the breeze. Dependency Inversion.

Two diagrams were there:

Diagram 1:

Diagram 2:

I “conjured” over patterns generation a bit, and the diagrams became like this:

Diagram 1:

- virtually, we define DispatcherHelper service.

Diagram 2:


- we define one of the implementations of DispatcherHelper service named TvcmDispatcherHelper.

The code remains the SAME.
Patterns implementation:

: ServicePrim::Class
= SimpleClass::Class
 
// Functions of stereotype
 
%f _st_space_key
 SHD
 
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BA9C0354*
//#UC END# *5502C6A200F5for5502BA9C0354*
 
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BA9C0354*
//#UC END# *5502CBD4031Efor5502BA9C0354*
 
// Inherited implementation 
 
// overriding of base stereotype Delphi interfaces and implementation::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
? Service
= ServicePrim::Class
 
// Parameters of stereotype
a f
/ - abstraction type
 
// Functions of stereotype
 
%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*
 
// Inherited implementation
 
// overriding of base stereotype Delphi interfaces and implementation::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BABC0193*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BABC0193*
 
// overriding of base stereotype ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BABC0193*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BABC0193*
 
// overriding of base stereotype 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(Interface of service %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(External service implementation %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*
 
// Nested stereotypes
 
: Service::Class::responsibility::Operation
? Responsibility
= ClassBase::Class::Operation
 
// Parameters of stereotype 
v +
/ - visibility types

a f
/ - abstraction type
T 
/ - can have no “purpose” (type/result)
m f
/ - can be not implemented/have overridden implementation 
// Generators
// Model generation in MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BBDB02C9*
//#UC END# *46E6D4BB0339for5502BBDB02C9*
 
// generator of interface factories implementation in java (.java)
+ fctr.java
//#UC START# *470321C1038Afor5502BBDB02C9*
//#UC END# *470321C1038Afor5502BBDB02C9*
 
// The second interface stereotype section, for example, class properties implementation.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BBDB02C9*
//#UC END# *477398E501C0for5502BBDB02C9*
 
// The third interface section, for example, properties field.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BBDB02C9*
//#UC END# *4774D2A20372for5502BBDB02C9*
 
// Forms files generator (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BBDB02C9*
//#UC END# *49F5795900ECfor5502BBDB02C9*
 
// // TestComplete Scripts(.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BBDB02C9*
//#UC END# *4DE79AFC0030for5502BBDB02C9*
 
// Hack for [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BBDB02C9*
//#UC END# *4E65F581015Afor5502BBDB02C9*
 
// Native Delphi interfaces (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BBDB02C9*
//#UC END# *470F1571031Cfor5502BBDB02C9*
 
// Implementation in Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BBDB02C9*
//#UC END# *470F15B800CBfor5502BBDB02C9*
 
// Functions of stereotype
%f _st_space_key
 SHD
 
// Inherited implementation
 
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of wiki methods
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BBDB02C9*
//#UC END# *470484D50138for5502BBDB02C9*

: ServiceImplementation::Class
? Service implementation
= ServicePrim::Class
 
// Parameters of stereotype 
a f
/ - abstraction type
 
// Functions of stereotype
 
%f _st_space_key
 SHD
 
// Inherited implementation 
 
// overriding of base stereotype Delphi interfaces and implementation::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BADD01CB*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BADD01CB*
 
// overriding of base stereotype ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*
 
// overriding of base stereotype 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(registration %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*
 
// Nested stereotypes
 
: ServiceImplementation::Class::implements::ClassDependency
? Specifying of implementation
= Delphi interfaces and implementation::MDAGenerator
 
// Generators
// Model generation in MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BC8E029A*
//#UC END# *46E6D4BB0339for5502BC8E029A*
 
// Native Delphi interfaces (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BC8E029A*
//#UC END# *470F1571031Cfor5502BC8E029A*
 
// Implementation in Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BC8E029A*
//#UC END# *470F15B800CBfor5502BC8E029A*
 
// The second interface stereotype section, for example, class properties implementation.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BC8E029A*
//#UC END# *477398E501C0for5502BC8E029A*
 
// The third interface section, for example, properties field.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BC8E029A*
//#UC END# *4774D2A20372for5502BC8E029A*
 
// Forms files generator (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BC8E029A*
//#UC END# *49F5795900ECfor5502BC8E029A*
 
// TestComplete Scripts(.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BC8E029A*
//#UC END# *4DE79AFC0030for5502BC8E029A*
 
// Hack for [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BC8E029A*
//#UC END# *4E65F581015Afor5502BC8E029A*
 
// Functions of stereotype
%f _st_space_key
 SHD
 
// Inherited implementation
 
// implementation of abstract stereotype Documentation::MDAGenerator
// check of elements constraints
%t _constraint
//#UC START# *4704C0E30186for5502BC8E029A*
c          {}
r {""=""}: {}
//#UC END# *4704C0E30186for5502BC8E029A*
 
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of element (operation, attribute) in wiki
%f _wiki_child_kind
//#UC START# *4705CBD6003Efor5502BC8E029A*
//#UC END# *4705CBD6003Efor5502BC8E029A*
 
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of auto-generated methods in wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BC8E029A*
//#UC END# *470484D50138for5502BC8E029A*

“Gobbledygook” patterns look bone chilling. However, they are written “for good” and can possibly be used many times.

A small legend:

%S - is Self.
\ - is ;
%P – parent element.
%G – base classes.
%R – implemented interfaces.
%T - expression type.
%C – child elements.
%CN – child element name. Usually - Child.Name.
%CS - child element stereotype name.
%S%{Facet} – field value (member) from Self. Usually - Self.Facet.
%f _Name – Declaration of current stereotype function called Name (class method).
f _Name – free function declaration.
%t _constraint –declaration of current stereotype transformer named “constraint”. Analogue of the Case.
: ServiceImplementation::Class – declares ServiceImplementation stereotype.
= ServicePrim::Class – inherits it from ServicePrim.
? Service implementation - specifies documentation for the current element.
The cycle:
<{}{%CS=Dependency}%CN>
// - looks through the child elements that represent dependences and prints their names (%CN)
 
<{}{%t_simple_class(%P)=true}%PN>
// - looks through the parent elements that are “simple classes” and prints their names (%PN)

Operator 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
// i.e. if Self.Mixin has not been set, we look through the childs for PureMixIn

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

At least 10-20 of already written classes will be changed under this paradigm. I am terribly bored with parasite cross-dependences between the libraries.

Why do “parasite” cross-dependences actually appear?

This is not because one doesn’t know about dependency inversion principle.

The reason is he is often not enthusiastic about “all this staff”

It is more simple to write “one more uses”.

Sometimes one simply doesn’t know that changes  he makes can influence the concurrent projects.

This is normal.

Instead, when parasite dependences are revealed, they are dealt with “in two clicks”.

Briefly. Shooting the breeze. Dependency inversion

Original in Russian: http://programmingmindstream.blogspot.ru/2015/03/blog-post_12.html

Lately I’ve been shaking up our libraries for correcting of dependences.

The libraries contain several millions of code lines and several thousands of modules.

They are used in several tens of programming projects developed by fairly large number of programmers teams.

That is not an “idle talk”.

For long time we have written:

1. Our own word processing application on a level of Word 97.
2. Our own implementation of IStorage, which is more effective than from MS.
3. Our own full-text indexer.
4. DUnit add-ins (in Russian).
5. Our own script engine (FORTH-like) on the level of Python.
6. Our own implementation of GUI-cases testing in “natural language”.
7. Our own rendering of RTF-like documents for iOS.
8. Our own implementation of SAX and DOM paradigms.
9. Our own code generation from UML.
10. Our own implementation of MVC-like framework.

The dependences are shown only by drawing of this staff on UML and, subsequently, validation of relations and cycles as well as code generation.

I’ve already used the simple “dependency inversion” more than once.

I really like it.

I developed such a liking for it that I even made a separate code generation pattern for this staff.

I’ll give an example – WITHOUT code generation pattern, in BASE primitives.

It looks something like this:

Previously:

A call B.method

A was connected to B,

Now:

A call C.method
B implements C.method

A is connected to C.
B is connected to C.

A has “no idea” of B.
B has “no idea” of A, too.

A knows about C.
B knows about C.

С is a “service” enabling behavior substitution.

The diagram:



The code:

Injection point:
unit l3DispatcherHelper;
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "L3$AFW"
// The unit: "w:/common/components/rtl/Garant/L3/l3DispatcherHelper.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Low Level::L3$AFW::VCMHelpers::Tl3DispatcherHelper
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// ! Completely generated from the model. It is not allowed to edit manually. !
 
{$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;
     {* Signature of ClearFields method }
 public
 // public methods
   procedure SetAlienHelper(const anAlien: Il3DispatcherHelper);
   class function Exists: Boolean;
     {* We check if singleton instance has been created }
 public
 // singleton factory method
   class function Instance: Tl3DispatcherHelper;
    {- returns the singleton instance. }
 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.

The injection:
TvcmDispatcherHelper = class(Tl3ProtoObject, Il3DispatcherHelper)
 public
 // realized methods
   procedure ClearHistory;
 public
 // public methods
   class function Exists: Boolean;
     {* We check if singleton instant has been created }
 public
 // singleton factory method
   class function Instance: TvcmDispatcherHelper;
    {- returns the singleton instance. }
 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);
...

Actually, this approach is used by Embarcadero in FMX.

They call it Services.

Sure, with a true Service-Locator.

It is more SIMPLE in NON-BASE primitives. But I’ll write about it edit next time, if you are interested.

For those who like to “nit-pick through spaces and commas” – I’ll STRESS it is only an IDEA, not a guide to action.

Naturally, I’ve already given a link to Spring For Delphi.

My colleague also wrote about it – The colleague wrote. Example of Dependency Injection  (in Russian).

Some more (in Russian):

Link. Taking stock of dependency inversion principle
Link. Dependency inversion principle 

A similar problem was discussed here – About tests and specially-fitted “check points”


Today it seemed to me I found an error in Delphi XE memory manager

Original in Russian: http://18delphi.blogspot.ru/2013/04/delphi-xe.html

All symptoms indicated it.

I even specified a test:
procedure TReallocMemTest.DoIt;
var
 l_Index : Integer;
 l_P : PAnsiChar;
 l_I : Integer;
 l_Size : Integer;
 l_OldSize : Integer;
begin
 for l_Index := 0 to 5000 do
 begin
  l_Size := 10;
  GetMem(l_P, l_Size);
  try
   while (l_Size <= 6144 * 2) do
   begin
    FillChar(l_P^, l_Size, Random($ff));
    l_OldSize := l_Size;
    l_I := PInteger(l_P + l_OldSize - SizeOf(Integer))^;
    Inc(l_Size, Random(20));
    ReallocMem(l_P, l_Size);
    Check(PInteger(l_P + l_OldSize - SizeOf(Integer))^ = l_I);
   end;//l_Size <= 6144
  finally
   FreeMem(l_P);
  end;//try..finally
 end;//for l_Index
end;//TReallocMemTest.DoIt
 
procedure TReallocMemTest.DoIt1;
const
 cMagicSize0 = 10;
 cMagicSize = 3120;
 cNewMagicSize = 6144;
var
 l_P : PAnsiChar;
 l_I : Integer;
begin
 GetMem(l_P, cMagicSize0);
 try
  FillChar(l_P^, cMagicSize0, 10);
  l_I := PInteger(l_P + cMagicSize0 - SizeOf(Integer))^;
  ReallocMem(l_P, cNewMagicSize);
  Check(PInteger(l_P + cMagicSize0 - SizeOf(Integer))^ = l_I);
 
  FillChar(l_P^, cMagicSize, 10);
  l_I := PInteger(l_P + cMagicSize - SizeOf(Integer))^;
  ReallocMem(l_P, cNewMagicSize);
  Check(PInteger(l_P + cMagicSize - SizeOf(Integer))^ = l_I);
 finally
  FreeMem(l_P);
 end;//try..finall
end;//TReallocMemTest.DoIt

I even told my colleagues about my “discovery”. I even wrote to Embarcadero.

But! This test does not fall if you do not call MY CODE first.

The ball is on my side.

I looked so stupid.

But only he that never climbed never fell. Instead, I added one more test to the base.

I’ll repeat that the written and DEBUGGED test should not be thrown but added to the test base. It took our “nerves and blood”.

It reminds me of a Russian fairy-tale: “Don’t dead me, Ivanushka the Fool, you can make use of me”.

I hope, that I’ve become a bit wiser today.

P.S. The actual problems were in this “staff” - http://18delphi.blogspot.com/2015/02/how-to-find-out-true-size-of-memory.html

Why I pay so much attention to mixins and tests

Original in Russian: http://18delphi.blogspot.ru/2013/04/blog-post_4.html

I do so because mixins and AOP provide the fundamental basis for MY development. I think in these terms.

In their turn, tests make it possible to keep developing stable without letting up.

I’m planning to describe mixins and tests and move to more complex issues, like UML, code generation and metaprogramming.

BUT first you have to understand the idea of mixins – as I see it.

Lyrical digression

Original in Russian: http://18delphi.blogspot.ru/2013/04/blog-post_3754.html

Time and time again I’ve been thinking about what I could be if programming was out of question.

I found no answer.

I studied physics and mathematics, but that’s not my scene. Soul theorem and quantum physics alone are enough. I don’t understand a thing! Though, I had good teachers. Pavel Alexeevich Eminov - http://pm.miem.edu.ru/Pm/PEOPLE/eminov.htm lectured physics. But I am a poor student.

I went in for sports, various sports. I got top senior grade. I got candidate master degree in “mountaineering” (in fact, but not formally). To get it, I have to “go through the formalities” and I am not enthusiastic about it. Besides, is there a need?  I wouldn’t even mention aikido… I train with one of the best trainers in Russia. I visited a seminar in Rostov and I was said that “I could probably grow in two months with Vadim Ivanovich (http://www.aikidocenter.ru/)”. May be I am stupid… I really take sports irregularly but make honest efforts. I personally see no growth…

I tried to be a radio ham – “to solder so that it DOES NOT WORK”.

I tried to make something “with my hands”. I failed in everything except for “battering in a nail” and “drilling a hole”.

I tried to sew… Oh, what field equipment I made… Again – I failed. I had trouble with parallel stitches…

I cooked. What pemmican I made! :-)

Nowhere. NOWHERE I found either success or slightest achievements.

I was lucky to live in the age that gave birth the profession of programmer.

I made at least something in programming.

Probably, I would be able to dig ditches, though poorly, and I would be displeased.

Am I alone in my problem? I don’t think so…

What do you see yourself in the 19th century? Or in the Middle Ages?...

What is more – I thought several times that railway evolution in the 19th century is similar to computers and cosmonautics in the 20th and the Internet in the 21th century...

I would probably be a railway engineer… Sure, if I did not have to work “with my hands”.

And now – “at the end of my life” – time and time again I think about teaching. I want to share my IDEAS. They say to me – “you won’t do it, you’ll kill all the students”. People are right… :-)

Perhaps, I should write a book… About “Mixins, TDD and AOP and some Generic's" or “Programming of word processors and formats generator” (Actually, here the copyright is not mine).  To tell the truth, this blog is a “test of the pen”… If is is not interesting, and it is all clear here…

I am TERRIBLY satisfied with my work, but I am TERRIFIED to fancy what I would do if I didn’t have it. I am terrified to think about what if there were no such profession as a “programmer”.

About "refactoring"

Original in Russian: http://programmingmindstream.blogspot.ru/2014/09/blog-post_25.html

Based on – Depression, or Falsity of hResult and other ErrorCode

I have found two more “bottlenecks” - AllocNewFATAlement and AllocNewCluster.

They, in turn, lead to LockFile.

That’s because we lock the header that stores the information about warehouse structure.

Another reason is the fact that the header has to be time-accessed.
Otherwise, we’d get a “mess” instead of a “warehouse”.

Users would “bump into these locks”.

I observed such a picture today on “synthetic” load tests.

Under the debugger.

All other machines "sweated guts out”, and I “debugged” one of them.

AND I SAW IT. I really saw it. In the code and on break-point's.

I saw that “one waits for another”.

I already know how to deal with it.

In a lookahead manner, I should allocate not just FATElement and Cluster, but several (five, ten, twenty, thirty) at once.

In one piece.

It is effective in respect that a file usually has more than one, more than two and even ten clusters.

I should also hold the free list at a client site. When a client ends a session, they are returned to the free list – i.e. the list of “not used”, so that other clients could use it too.

It is probable that we lose elements, if the client aborts the process.

But then we get to the “bottleneck” less often, since we can write:
if AllocatedFatElements.Empty then
begin
 // - here we have an interPROCESS “bottleneck”
 Lock;
 try
  Result := AllocNewFatElement;
  for l_Index := 0 to 10 do
   AllocatedFatElements.Add(AllocNewFatElement);
 finally
  Unlock;
 end//try..finally
end
else
 // - here we have ONLY interSTREAM “bottleneck” (because AllocatedFatElements is, naturally, protected from inter-stream)
 Result := AllocatedFatElements.GetLastAndDeleteIt;

Instead of:
Lock;
// - here we ALWAYS have a multiPROCESS “bottleneck”
try
 Result := AllocNewFatElement;
finally
 Unlock;
end;//try..finally

Same for clusters.

Even if elements “hang”, it won’t get worse much, the warehouse won’t be destroyed, it will just have “holes”.

Considering that we have a “night Update” in the night - if possible - the warehouse will anyway be repacked, so the “holes” will disappear “towards morning”.

We’ll get the repacked permanent part without holes and the “empty” variable part.

Clients write their documents versions to the second one during the day.

The next night, the process repeats again.

That is only if there are no signed on users.

How to test the "totally untestable"

Original in Russian: http://programmingmindstream.blogspot.ru/2014/02/blog-post_4473.html

Right here - http://programmingmindstream.blogspot.ru/2014/02/blog-post_15.html . I’ve tried to give a detailed description of the “untestable” architecture testing “algorithm” and making it “testable” somehow.

Let’s view it from a different angle.

Suppose, we have a “principally untestable application”.

Let’s consider the “MOST TERRIBLE” case.

We do everything in the OnClick “handler” on the FORM, at the same time, the DATA from the database are being PROCESSED.

Namely:

It is MONOLITHIC and works with DataSet's on the form.

Something like this:
type
 TMainForm = class(TForm)
  DataSet: TDataSet;
  Grid: TGrid;
  Button: TButton;
  Label: TLabel;
 end;//TMainForm
 
procedure TMainForm.ButtonClick(aSender: TObject);
begin
 Label.Caption := Grid.SomeRow.SomeCalculations;
end;
...
begin
 Application.CreateForm(TMainForm, MainForm);
 Application.Run;
end.

Let’s test it:

We change the code of the project in a way:
...
begin
 Application.CreateForm(TMainForm, MainForm);
 GUITestRunner.TGuiTestRunnerForm.Create(Application); 
 // - we add the window with a “tests launcher”
 Application.Run;
end.

We add a test:
unit MyTest;
 
interface
 
uses
 TestFramework;
 
type
 TMyTest = class(TTestCase)
  published
   procedure DoIt;
 end;//TMyTest
 
implementation
 
uses
 MainForm // - HERE we KNOW about the MAIN form of the app
 ;
 
procedure TMyTest.DoIt;
var
 l_Form : TForm;
begin
 for l_Form in Screen.ActiveForms do
  if (l_Form Is TMainForm) then
  begin
   TMainForm(l_Form).Button.Click;
   l_Text := TMainForm(l_Form).Label.Caption;
   CompareWithEtalon(l_Text);
   break;
  end;//l_Form Is TMainForm
end;
 
initialization
 TestFramework.RegisterTest(TMyTest);

Do you understand the idea?

Of writing the CompareWithEtalon?

Of finding “that” TMainForm?

Of ensuring “repeatability” of a test?

Of ensuring the “database state”?

These ARE the QUESTIONS – JUST SO.

They can be DISCUSSED!

But!

Did the application STOP to be “untestable”?

Didn’t it?

There ARE QUESTIONS.

Many questions.

But!

We can discuss them.

“As it goes”.

But they “can be discussed” not in ABSTRACT – “what should we do if all went wrong”, but quite SPECIFICALLY in terms of “what should we do if we have THIS SPECIFIC problem”.

I hope, I have outlined another “one of the ways” how to test the “untestable application” and how to “turn away” from “cows in vacuum”.

P.S. It is obvious that “it is “the most real “white box”. But we have to START WITH SOMETHING! I mean, considering we do not have a “maid”...

P.P.S. It is also obvious that HERE the issue is neither “GUI tests”, nor “integration” tests, MUCH LESS it is “atomic” tests. The issue is ONLY writing of a “whatever test”, kind of “giving a start”, “raising” of the INFRASTRUCTURE.

When you have written a dozen of such “one-eyed, ill and obscure” tests, eventually, “it would be easier for you to do”. I am ALMOST POSITIVE about it :-)

You’d begin to refactor both tests and the code, getting rid of the “illness” and “Cut'n'Paste”.

And it would “work by itself”.

By and by, you’d get “correct” tests:
1. “Atomic” test.
2. “Integration” tests.
3. Regression tests.
4. GUI tests.

And the “one-eyed and ill” will BE GONE.

THE FIRST IS THE WORST!

Start with “something”.

P.P.P.S. It is obvious that raising of MODAL DIALOG is the GREATEST PROBLEM. It is also a QUESTION, that CAN and HAS TO be discussed.

But it is already a QUESTION, more than a “cow in vacuum”.

P.P.P.P.S. Right here - http://programmingmindstream.blogspot.ru/2014/02/anemicdomainmodel.html?showComment=1392717297690#c4055365633171954826 . – I’ve been “thrown to a challenge” :-)  I ACCEPT it :-)

Vsevolod sent a project to me to test.

More about testing

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

Briefly. Weak reference to interface

Original in Russian: http://programmingmindstream.blogspot.ru/2015/04/blog-post_3.html

In some cases we have to keep WEAK references to interfaces (without reference counting).

The analogue of attribute [Weak].

For example, for publisher/subscriber.

"It defines the one-to-many relationships between the objects so that on changing the state of one object all the objects related to it are reported about it."

Here's the solution:

type
 TmsWeakInterfaceRef<t> = record
 // Weak reference to interfece
  rShape : Pointer;
  constructor Create(const aShape: T);
  function AsShape: ImsShape;
  class operator Equal(const A: TmsWeakInterfaceRef<t>; const B: TmsWeakInterfaceRef<t>): Boolean;
  class operator Equal(const A: TmsWeakInterfaceRef<t>; const B: T): Boolean;
  class operator Implicit(const aShape: T): TmsWeakInterfaceRef<t>;
 end;//TmsWeakInterfaceRef
 
 TmsWeakShapeRef = TmsWeakInterfaceRef<imsshape>;
...
// TmsWeakInterfaceRef<t>
 
constructor TmsWeakInterfaceRef<t>.Create(const aShape: T);
begin
 Assert(SizeOf(T) = SizeOf(IUnknown));
 Move(aShape, Self.rShape, SizeOf(T));
end;
 
function TmsWeakInterfaceRef<t>.AsShape: ImsShape;
begin
 Result := ImsShape(Self.rShape);
end;
 
class operator TmsWeakInterfaceRef<t>.Equal(const A: TmsWeakInterfaceRef<t>; const B: TmsWeakInterfaceRef<t>): Boolean;
begin
 Result := (A.rShape = B.rShape);
end;
 
class operator TmsWeakInterfaceRef<t>.Equal(const A: TmsWeakInterfaceRef<t>; 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<t>.Implicit(const aShape: T): TmsWeakInterfaceRef<t>;
begin
 Result := TmsWeakInterfaceRef<t>.Create(aShape);
end;

Link to the commit - https://bitbucket.org/lulinalex/mindstream/commits/825ca7487905ce786aa9f44b6a0d95e570b06b71

Another commit - https://bitbucket.org/lulinalex/mindstream/commits/861e56e0bff2613b652d633f0183c93fde75601e

The final version:
type
 TmsWeakInterfaceRef<T: IUnknown> = record
 // Weak reference to interface
  rRef : Pointer;
  constructor Create(const aShape: T);
  function AsRef: T; inline;
  class operator Equal(const A: TmsWeakInterfaceRef<t>; const B: TmsWeakInterfaceRef<t>): Boolean;
  class operator Equal(const A: TmsWeakInterfaceRef<t>; const B: T): Boolean;
  class operator Implicit(const aShape: T): TmsWeakInterfaceRef<t>;
  class operator Implicit(const aValue: TmsWeakInterfaceRef<t>): T; inline;
 end;//TmsWeakInterfaceRef
 
 TmsWeakShapeRef = TmsWeakInterfaceRef<imsshape>
...
// TmsWeakInterfaceRef<t>
 
constructor TmsWeakInterfaceRef<t>.Create(const aShape: T);
begin
 Assert(SizeOf(T) = SizeOf(IUnknown));
 Move(aShape, Self.rRef, SizeOf(T));
end;
 
function TmsWeakInterfaceRef<t>.AsRef: T;
begin
 Result := nil;
 Assert(SizeOf(T) = SizeOf(Result));
 Move(Self.rRef, Result, SizeOf(T));
 Result._AddRef;
end;
 
class operator TmsWeakInterfaceRef<t>.Implicit(const aValue: TmsWeakInterfaceRef<t>): T;
begin
 Result := aValue.AsRef;
end;
 
class operator TmsWeakInterfaceRef<t>.Equal(const A: TmsWeakInterfaceRef<t>; const B: TmsWeakInterfaceRef<t>): Boolean;
begin
 Result := (A.rRef = B.rRef);
end;
 
class operator TmsWeakInterfaceRef<t>.Equal(const A: TmsWeakInterfaceRef<t>; 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<t>.Implicit(const aShape: T): TmsWeakInterfaceRef<t>;
begin
 Result := TmsWeakInterfaceRef<t>.Create(aShape);
end;


Хорошая подборка кстати:
https://www.google.com/search?q=Weak+reference+to+interface&oq=Weak+reference+to+interface&aqs=chrome..69i57j69i60l2.13918j0j7&sourceid=chrome&es_sm=122&ie=UTF-8

(+) Weak interface references