Monday, December 3, 2018

{$IFDEF Version Problem

Inspired by Thomas Mueller (dummzeuch) here is a repost of my ifdef version maintained since 2015.

Since Day one of my FDK I had the same problem: How to maintain the distribution with different Delphi versions.

The reason for writing my FDK is/was a better and faster development of iOS and Android apps, but after a short, while it became more and more like a Swiss-knife for my daily work.

Since XE 2 all my new Programs are written with FMX and since 2015 I've used it every day for developing my Windows Programs, too.

So here is my version of the {$I Versions.inc}

unit Delphi.VersionConsts;

// =====>     FFFFFF  DDDDD   K    K    FireMonkey Development Kit
// ====>     F       D    D  K  KK        (c) F. Lauter   aka Mavarik
// ===>     FFFF    D    D  KKK               O. MĂĽnzberg aka Sir Rufo
// ==>     F       D    D  K  KK
// =>     F       DDDDD   K    K        Version 2015, 2016, 2017, 2018

{******************************************************************************
 * Changes:
 * 01.10.15 Everybody should use this Unit - I hate the $I Version.inc files
 *          I hope that someday EMBT will always provide this Unit with every
 *          new Version.
 ******************************************************************************}

interface

{$IF Declared(CompilerVersion)}
{$ELSE}
const
  CompilerVersion = 0.0;
{$ENDIF}

const
  CompilerVersion_RIO     = 33.0;
  CompilerVersion_TOKYO   = 32.0;
  CompilerVersion_BERLIN  = 31.0;
  CompilerVersion_SEATTLE = 30.0;
  CompilerVersion_XE8     = 29.0;
  CompilerVersion_XE7     = 28.0;
  CompilerVersion_XE6     = 27.0;
  CompilerVersion_XE5     = 26.0;
  CompilerVersion_XE4     = 25.0;
  CompilerVersion_XE3     = 24.0;
  CompilerVersion_XE2     = 23.0;
  CompilerVersion_XE      = 22.0;
  CompilerVersion_2010    = 21.0;
  CompilerVersion_2009    = 20.0;
  CompilerVersion_2007    = 18.5;
  CompilerVersion_2006    = 18.0;
  CompilerVersion_2005    = 17.0;
  CompilerVersion_8_NET   = 16.0;
  CompilerVersion_7       = 15.0;
  CompilerVersion_6_2     = 14.2;
  CompilerVersion_6_1     = 14.1;
  CompilerVersion_6       = 14.0;

const
  Compiler_RIO     = CompilerVersion = CompilerVersion_RIO;   // Carnival
  Compiler_TOKYO   = CompilerVersion = CompilerVersion_TOKYO; // Godzilla
  Compiler_BERLIN  = CompilerVersion = CompilerVersion_BERLIN;
  Compiler_SEATTLE = CompilerVersion = CompilerVersion_SEATTLE;
  Compiler_XE8     = CompilerVersion = CompilerVersion_XE8;
  Compiler_XE7     = CompilerVersion = CompilerVersion_XE7;
  Compiler_XE6     = CompilerVersion = CompilerVersion_XE6;
  Compiler_XE5     = CompilerVersion = CompilerVersion_XE5;
  Compiler_XE4     = CompilerVersion = CompilerVersion_XE4;
  Compiler_XE3     = CompilerVersion = CompilerVersion_XE3;
  Compiler_XE2     = CompilerVersion = CompilerVersion_XE2;
  Compiler_XE      = CompilerVersion = CompilerVersion_XE;
  Compiler_2010    = CompilerVersion = CompilerVersion_2010;
  Compiler_2009    = CompilerVersion = CompilerVersion_2009;
  Compiler_2007    = CompilerVersion = CompilerVersion_2007;
  Compiler_2006    = CompilerVersion = CompilerVersion_2006;
  Compiler_2005    = CompilerVersion = CompilerVersion_2005;
  Compiler_8_NET   = CompilerVersion = CompilerVersion_8_NET;
  Compiler_7       = CompilerVersion = CompilerVersion_7;
  Compiler_6_2     = CompilerVersion = CompilerVersion_6_2;
  Compiler_6_1     = CompilerVersion = CompilerVersion_6_1;
  Compiler_6       = CompilerVersion = CompilerVersion_6;

const
  {$IF Compiler_RIO}    PackageVersion = '260';StudioVersion = '20.0'; {$ENDIF} 
  {$IF Compiler_TOKYO}  PackageVersion = '250';StudioVersion = '19.0'; {$ENDIF} 
  {$IF Compiler_BERLIN} PackageVersion = '240';StudioVersion = '18.0'; {$ENDIF}
  {$IF Compiler_SEATTLE}PackageVersion = '230';StudioVersion = '17.0'; {$ENDIF}
  {$IF Compiler_XE8}    PackageVersion = '220';StudioVersion = '16.0'; {$ENDIF}
  {$IF Compiler_XE7}    PackageVersion = '210';StudioVersion = '15.0'; {$ENDIF}
  {$IF Compiler_XE6}    PackageVersion = '200';StudioVersion = '14.0'; {$ENDIF}
  {$IF Compiler_XE5}    PackageVersion = '190';StudioVersion = '13.0'; {$ENDIF}
  {$IF Compiler_XE4}    PackageVersion = '180';StudioVersion = '12.0'; {$ENDIF}
  {$IF Compiler_XE3}    PackageVersion = '170';StudioVersion = '11.0'; {$ENDIF}
  {$IF Compiler_XE2}    PackageVersion = '160';StudioVersion = '10.0'; {$ENDIF}
  {$IF Compiler_XE}     PackageVersion = '150';StudioVersion = '9.0'; {$ENDIF}
  {$IF Compiler_2010}   PackageVersion = '140';StudioVersion = '8.0'; {$ENDIF}
  {$IF Compiler_2009}   PackageVersion = '120';StudioVersion = '7.0'; {$ENDIF}
  {$IF Compiler_2007}   PackageVersion = '110';StudioVersion = '6.0'; {$ENDIF}
  {$IF Compiler_2006}   PackageVersion = '100';StudioVersion = '5.0'; {$ENDIF}
  {$IF Compiler_2005}   PackageVersion =  '90';StudioVersion = '4.0'; {$ENDIF}
  {$IF Compiler_8_NET}  PackageVersion =  '80';StudioVersion = '3.0'; {$ENDIF}
  {$IF Compiler_7}      PackageVersion =  '70';StudioVersion = '2.0'; {$ENDIF}
  {$IF Compiler_6_2}    PackageVersion =  '60';StudioVersion = '1.2'; {$ENDIF}
  {$IF Compiler_6_1}    PackageVersion =  '60';StudioVersion = '1.1'; {$ENDIF}
  {$IF Compiler_6}      PackageVersion =  '60';StudioVersion = '1.0'; {$ENDIF}

type
  TDelphiVersion = Record
                     Name          : String;
                     StudioVersion : String;
                   end;

const
  TDelphiVersions : array[0..6] of TDelphiVersion  = ((Name:'Delphi XE6';StudioVersion:'14.0'),
                                                      (Name:'Delphi XE7';StudioVersion:'15.0'),
                                                      (Name:'Delphi XE8';StudioVersion:'16.0'),
                                                      (Name:'Delphi 10 Seattle';StudioVersion:'17.0'),
                                                      (Name:'Delphi 10.1 Berlin';StudioVersion:'18.0'),
                                                      (Name:'Delphi 10.2 Tokyo';StudioVersion:'19.0'),
                                                      (Name:'Delphi 10.3 Rio';StudioVersion:'20.0'));

const
  Compiler_RIO_UP     = CompilerVersion >= CompilerVersion_RIO;
  Compiler_TOKYO_UP   = CompilerVersion >= CompilerVersion_TOKYO;
  Compiler_BERLIN_UP  = CompilerVersion >= CompilerVersion_BERLIN;
  Compiler_SEATTLE_UP = CompilerVersion >= CompilerVersion_SEATTLE;
  Compiler_XE8_UP     = CompilerVersion >= CompilerVersion_XE8;
  Compiler_XE7_UP     = CompilerVersion >= CompilerVersion_XE7;
  Compiler_XE6_UP     = CompilerVersion >= CompilerVersion_XE6;
  Compiler_XE5_UP     = CompilerVersion >= CompilerVersion_XE5;
  Compiler_XE4_UP     = CompilerVersion >= CompilerVersion_XE4;
  Compiler_XE3_UP     = CompilerVersion >= CompilerVersion_XE3;
  Compiler_XE2_UP     = CompilerVersion >= CompilerVersion_XE2;
  Compiler_XE_UP      = CompilerVersion >= CompilerVersion_XE;
  Compiler_2010_UP    = CompilerVersion >= CompilerVersion_2010;
  Compiler_2009_UP    = CompilerVersion >= CompilerVersion_2009;
  Compiler_2007_UP    = CompilerVersion >= CompilerVersion_2007;
  Compiler_2006_UP    = CompilerVersion >= CompilerVersion_2006;
  Compiler_2005_UP    = CompilerVersion >= CompilerVersion_2005;
  Compiler_8_NET_UP   = CompilerVersion >= CompilerVersion_8_NET;
  Compiler_7_UP       = CompilerVersion >= CompilerVersion_7;
  Compiler_6_2_UP     = CompilerVersion >= CompilerVersion_6_2;
  Compiler_6_1_UP     = CompilerVersion >= CompilerVersion_6_1;
  Compiler_6_UP       = CompilerVersion >= CompilerVersion_6;

  Compiler_RIO_DOWN     = CompilerVersion <= CompilerVersion_RIO;
  Compiler_TOKYO_DOWN   = CompilerVersion <= CompilerVersion_TOKYO;
  Compiler_BERLIN_DOWN  = CompilerVersion <= CompilerVersion_BERLIN;
  Compiler_SEATTLE_DOWN = CompilerVersion <= CompilerVersion_SEATTLE;
  Compiler_XE8_DOWN     = CompilerVersion <= CompilerVersion_XE8;
  Compiler_XE7_DOWN     = CompilerVersion <= CompilerVersion_XE7;
  Compiler_XE6_DOWN     = CompilerVersion <= CompilerVersion_XE6;
  Compiler_XE5_DOWN     = CompilerVersion <= CompilerVersion_XE5;
  Compiler_XE4_DOWN     = CompilerVersion <= CompilerVersion_XE4;
  Compiler_XE3_DOWN     = CompilerVersion <= CompilerVersion_XE3;
  Compiler_XE2_DOWN     = CompilerVersion <= CompilerVersion_XE2;
  Compiler_XE_DOWN      = CompilerVersion <= CompilerVersion_XE;
  Compiler_2010_DOWN    = CompilerVersion <= CompilerVersion_2010;
  Compiler_2009_DOWN    = CompilerVersion <= CompilerVersion_2009;
  Compiler_2007_DOWN    = CompilerVersion <= CompilerVersion_2007;
  Compiler_2006_DOWN    = CompilerVersion <= CompilerVersion_2006;
  Compiler_2005_DOWN    = CompilerVersion <= CompilerVersion_2005;
  Compiler_8_NET_DOWN   = CompilerVersion <= CompilerVersion_8_NET;
  Compiler_7_DOWN       = CompilerVersion <= CompilerVersion_7;
  Compiler_6_2_DOWN     = CompilerVersion <= CompilerVersion_6_2;
  Compiler_6_1_DOWN     = CompilerVersion <= CompilerVersion_6_1;
  Compiler_6_DOWN       = CompilerVersion <= CompilerVersion_6;

{$IF DEFINED( IOS ) or DEFINED(ANDROID)}

type
   Compiler = class sealed
     public
       Const
         HasArc      = true;
   end;

const
  CompilerIsMobil     = true;

  PlattFormOSX        = false;
  SupportsAnsiStrings = false; //Compiler_BERLIN_UP;
{$DEFINE CompilerIsMobil}

{$ELSE}
type
   Compiler = class sealed
     public
       Const
         HasArc      = false;
   end;

const
{$IFDEF MACOS}
  PlattFormOSX        = true;
{$ENDIF}

{$REGION 'Documentation'}
  /// <summary>
  ///   true if target ist iOS or Android
  /// </summary>
{$ENDREGION}
  CompilerIsMobil     = false;
  SupportsAnsiStrings = true;
{$ENDIF}

implementation

end.




Wednesday, October 17, 2018

This was the beginning...Buy Books!

Looking back on my developments, I was always proud of my software. 

Starting with a programmable calculator and Eumel on a ELAN System in 1981, I got my first computer a Sharp MZ-700 in 1982.



First of all - With learning Basic from the MZ-700 manual, I was able to sell my first software - a graphic editor - to a local dealer to get my first floppy drive.

My first book: Rodnay Zaks programming the Z80. 

My next Computer was the MZ-800! With the MZ-800 graphics, 80 Chars per line were possible and with this, CP/M could be used for development. The Editor - of course - Wordstar, assembler M80, linker L80. At the same time: Learning UCSD-Pascal on Apple II in school and with Turbo-Pascal for CP/M at home.

I decided to write my second program in pure assembler:

The FLDOS  (Frank Lauter's Disk Operation System) 


Thanks to a very kind employee of  Motorola - I got an original manual of the floppy-controller-chip. But this journey is another story. 

This "operating system" only take 1000 bytes of memory and was able to handle two parts. One for file-operation and the other was a Disk-Hex-Editor. Both parts could be reloaded from a floppy without violating the 1000 bytes limit.

The Z80-Book "paid" the start of my development equipment. A dual floppy drive! One with 40 Tracks, one with 80 Tracks. ~2400 DM at this time.

After that, I never tried to develop a whole program in pure assembler, because everything else was written in Turbo-Pascal. (Until today - I ignore my tries in C)

I have bought many books these days, but nearly all the books did not satisfy my needs. 700 or more Pages but only 60 pages of useful information - or less... So I had to buy 10 Books to get all the necessary information. (Perhaps that's why I stopped buying books)

And this leads to my next blog post ;-) or back to my Bookwriters post.





Wednesday, October 3, 2018

Pattern, naming and MVVM from a Delphi point of view.

Patterns are good tools and if you name it correctly, other developers should know what you are talking about.

Name it singleton and every developer knows how to deal with it... (I hope). If you are talking about dependency injection, perhaps you are not using it, but at least you can google it. So giving things the right name is always a good thing.

So let's take a look at the development of a new FMX application. Of course, you want modern design, maintainable code and testable business-logic. I think you are looking for the MVVM pattern. Model, View, ViewModel, but after File, New, Multi-device Application you have a project and a Mainform and with a closer look into your tool palette, you are unable to find a View, a Model or even a ViewModel. Nothing to put on your form.

BTW.: Clicking non-visual controls on your form is the worst thing you can do with the goal of MVVM.

And now? What to do? Google for a library?. Perhaps you find something and using a library is normally better than coding all by your self. Do you remember the famous words?

Using is faster than coding!

There are many useful libraries out there! Some are free, some are expensive and some are necessary. I'll never start a new project without my FDK. ;-) Especially when dealing with FMX. So every new project! My last VCL project/tool was with XE. 

Perhaps you are already using my FDK, but unfortunately my MVVM-Plugin is still not available today. Why? Because I'm still dealing with different MVVM-pattern-designs.
After "MVVM was the start" in 2015, "MVVM or what I think it is" in 2016, trying attributes in 2017, "MVVM 2.0 I did it my way" in April 2018 and some kind of different Bindings (no blog post - let's call it MVVM 2.5) -  I'm still working on the "best" way to do it right. I thought I was "short on final" with my View to CRUD-DB Binding pattern until last month "Sir Rufo" came up with a new binding approach. This with my last attempt will be the final one - I think - today... ;-)

At the moment I have 10 different Apps with my MVVM-Stuff from 2015,2016,2017 and 2018 and of course no MVVM-library form each year is compatible with the others. 4 different Libraries that are used in - at least - 2 Apps... Very bad to maintain. But back to Naming...

We are Delphi developers and I never had a View. I have forms, frames - perhaps I use panels or layouts to do visual tricks. Or on iOS & Android I use TabControls to display different - ok call it views. But why name it View? It's a Form... Because a Form is not a View and a Form could display many View's, but this View's are Layouts or Frames? Confusing... Starting in 2015 I had no clue why a Form is not a View - now I understand, but perhaps I will change the names... ;-)

Let's do some examples.

You have:

- TPerson with Name, Day of birth and more
- TAddress with Street, Zip, Town...
- TCommunication with Fon, Mail and more
- TBank with Bankname and Account
- TInvoice with Invoice Fields
- TArticle with Title, Price, weight

In 99,9% all Visual-Controls on my Forms representing a Field in the Database. The Database has - of course - more fields like Timestamp, CreationDate, LockOwner and more.

Perhaps my DB_Table (Person) is a TPerson,TAddress,TCommunication,TBank in one table. 80%

Perhaps I have TPerson, TAddress1, TAddress2, TFon1, TFon2, TBank1, TBank2, TBank3 100% until 2010 in one record written as binary to file with index. *lol*

Today I would have one DB-Table for TPerson, one for TAddress, one for TCommuniction  and one for TBank.

For this example I like to display this kind of data directly in Form-Fields (TEdit,TCombobox, TCheckBox etc.) and not in a Grid. Perhaps at the bottom a grid with the TInvoice and on dblclick display the Invoice on a second form with the containing TArticle(s).

So what do we have?

A FORM with Field separated in 5 subFRAMES, each subframe depends on a Databasetable. To Display more than one TAddress I had to create the controls at runtime on a scollbox. 
F for Form or Frame and D for Database.

Rule of thumb: Never use visual controls to keep/store your Data. 

That's why we need some class/Memory for our Fields. (That's why I would never use a Live-DB-Connection, where edits could only display the data if you have an open connection.) ARC on iOS & Android and no ARC on Windows - so we need an InterfacedObject as Memory - representation of our Form / Table. One last thing is something to Control the Dataflow from From (TEdit) to Memory -> to Database. Do we have a new Name?

FCMD - Form,Controller,Memory,Database.

FCMD - Sound like my new MVVM... ;-) or is it MVC?

Btw: What was the reason to do MVVM? Ahh yes... to have a good layer separation and testable units with - at the best - no dependencies.

Because we all doing unit-test... ;-)

What is your unit test coverage? 3%, 30%, 70% more?

OK - assume 100% coverage of your business units. Do you have unit tests for your ViewModel?
Maybe some time we got an IDE that could display the unit test coverage.

Back to the Form - we have a grid with a list of invoices - the grid has it's own model inside. Each row could be a ViewModel - InterfacedObject as Memory-Representation of the Database. So we need a Grid-Controller for displaying the TArray<IInvoice> perhaps with paging and background thread reloading new rows... Again a Controller to move n rows from Memory to the Grid-(View)Model.
And a Model "InterfacedObject Multiloader" to load all Invoices with
"Select * from InvoiceDB where Person = Person.GUID". 

On a DBLClick we could create a new Form and inject the IInvoice from GridHelper(ARow).GetRow<IInvoice> into the Controller of the new Form. Bingo... Working Demo.

So why FCMD and not MVVM or is FCMD another name for MVC?

To answer the question we have to look at the bindings.

In MVC the user uses the Controller to manipulate the Model that updates the View.
In MVVM then View has a bidirectional binding to the ViewModel and the ViewModel has a bidirectional binding to the Model. Is the Model the Database - no. Where is the data stored? In the ViewModel or in the Model? Ask 10 developers and you got 10 different answers. My ViewModels also have the Data and the Model has "all-Data" or the Interface for storing the Data via DB or REST or SOAP or Whatever.
In FCMD you have the Form and the RAD-approach. With the assignment of the ViewModel Memory-Representation to the View Form, you have to create your bindings to the Memory-Representation. This creates a Bind-Controller. If you type something into a TEdit the Bind-Controller transfers the data directly into your Model TInterfacedObject. This Object fires a propertychanged over the ViewModel  Bind-Controller direct to the view - Form. If you reload or load a different data, your View Form also displays the new content. The Memory Object has all Fields of the TableRow with some Attributes to Create and Handle the Database with CRUD I/O.
Perhaps we change from C for Controller to B for Binding.
So with FBMDR you could write your data to a local DB and in Background over REST to a Server. That's why my CRUD/ORM Memory-Representation could transfer all the fields to and from JSON.
Btw. Form-Bind-Memory-Database sounds like an in-memory database. So change the D to C like in CRUDTable

At this point no unit tests for the View Form-Logic, because there is no ViewModel. Perhaps parts of the ViewModel stuff is in the MemoryObject like "CanSave/CanDelete/Modified" and so on. The other things could be sent via the Bind-Controller or with TMessages into the View Form. Like DisableButton. 

With FBMC(R) 99,9% is testable like in MVVM but 70% less source code to type and 60% fewer Units.

I would love to see FBMC spread all over the Delphi-Community and beyond,

#FBMC - Form-Bind(ed)-Memory-CRUDTable


or perhaps I do some modifications and call it MVVM 2.5 - again...


The Binding-Controller not only handles the transfer but "he" is also able to do some data conversion, like string to integer or String to TDatetime or A->B, B->A.

So far so good. But with our new FMX-App, we need more. Nearly every FMX-Control has some animations build into the style. This animation is handled with timers - of course in the main thread. Like MouseDown, MouseOver, MouseUp and so on. If you are new to FMX you would write:

Procedure TButton1Click(Sender : TObject)
begin
  Button1.Enabled := false;
  DoSomeStuffFor20Sec;
  Button1.Enabled := true;
end;

If you click on Button1 the button is still enabled- you get no MouseDown animation your UI has no response and after 20Sec you can - perhaps - see MouseDown, MouseUp. But things are getting worse.

Procedure TButton1Click(Sender : TObject)
begin
  Button1.Enabled := false;
  NewForm := TNewForm.Create(Application);
end;

If you free the Form that contains the Button1 in the TNewForm Show or "Create Event". You'll get an exception because the MouseUp-Animation will be displayed after the TNewForm.Create is called on a no more assigned Button1.

Nearly everything you want to do like the good old RAD-Days you have to do asynchronously. At best, in the onIdle-Event for UI-Stuff or in Thread with other things.

Procedure TButton1Click(Sender : TObject)
begin
  Button1.Enabled := false;
  Button1.Text    := 'Processing...';

  TAsync.Await(Procedure
    begin // Thread Context
      DoSomeStuffFor20Sec;
    end).
  Execute(Procedure
    begin  
      Button1.Enabled := true;
      Button1.Text    := 'Save'; 
    end);
end;

OR

Procedure TButton1Click(Sender : TObject)
begin
  Button1.Enabled := false;
  Button1.Text    := 'Processing...';

  TIdleWorker.Execute(Procedure
    begin // UI Thread 
      DoSomeStuffWithUI;
      Button1.Enabled := true;
      Button1.Text    := 'Save'; 
    end);
end;

With the Bind-Controller from #FBMC you could bind a command/Method at the Button that can handle this kind of action without the need of writing additional lines of code.

With all these and the additional JSON Import/Export, REST Client/Server Unit you are able to Build your Multi-Device-App with "Cloud-Dataexchange" in minutes. At the moment it works perfectly with my Windows-Server. 

The next step is to test the Serverside in a Linux-Docker-Container...

But every day is too short... So stay tuned...

Friday, September 28, 2018

Neural Network - Part 2 is coming

First of all: I'm Sorry about by short blogpost from march 2018 about Neural Networks.

It is the second most-read post I've ever done and it has nearly no information in it...

It is part of my FDK - and normally I do not share this code - but perhaps I will do it this time.

If I have some samples to show I will come back to the topic.

Is wrong always bad?

In software development, there are often (too) many ways you can solve a goal.


But how do I find the right way?

Perhaps you saw this approach in other sourcecode or at a conference. You downloaded the code from Bitbucket or GitHub... Perhaps you found it in a book…

I often heard:

- It's the Microsoft way - they know how to do things - don't question this.
- This is a pattern - you have to do it by the book - more intelligent people have hammered this in stone

or the other side

- don't use this - it's part of the language, but do not use this (With, FreeAndNIL, Goto)

Who is able to decide what is right or wrong and if it is "marked" as wrong is it so bad to use or do it this way?
Is it really so, that out there are only a very few who set the rules? Yes I think so. I call them Book writers or "Head of the Team". Do not get me wrong - these guys are very talented, and they know how to do things. And for our Delphi?
The count for  "Head of the Team" is much smaller than on C, C++ or C#. (btw. from my point of view, all other languages do not count, especially if they do not result in CPU binary code)
But what if you do it in another way, what if you like to do it "called wrong" and what if your way is a better way for you
My Answer is: Then do it this way.
If your code is still: Readable, maintainable, stable and testable. Compile it, ship it and earn you money. 
Why should I do things only by the rule book? - But wait… Perhaps another developer doesn't understand your way and could not use your source or library. Yes, you can write it in your documentation and answer RTFM.
For a good library or component, there is no need to look into the documentation. Is it so? If yes we are all using stuff the is build decades ago… And yes we do, and we're dealing with this every day.
You like a small example? OK, find the bug:
var
  i : integer;
  d : TDateTime;
begin
   D := now;
   i :=0;
   while i < 30 do
     begin
       incDay(d);
       inc(i);
     end;
end;
From my point of view - it is a bug - but the answer is "We don't want to cause problems to existing code" - bug-report closed. So we still have to look at the documentation. I would have been so happy if they have used this answer at implementing Unicode as default into the compiler.
If you are working with a team or writing code that is used by many other developers you have to do things as your audience would expect it. OK... I agree.
But I often like to do things my way because it is - from my point of view - the better way. That's why I have my own MVVP 2.5 Pattern, my FluidCreator or Fluent-Creator, my own Binding and not the visual live binding, do things in code and not in the object inspector, create a database with a creation pattern, have a wrapper for FireDac, a wrapper for AppTheathering, a wrapper for Bluetooth, a wrapper for Streams, a wrapper for exception handling, many wrapper to do threading, IDictionary and normally everything thread-safe…
Perhaps one time in the future - I like to do this since 20 years - I will write a book about this and become part of the "Book writers"...
We will see…
But first I had to travel to a planet with a slower rotation speed!

Monday, September 10, 2018

Where to do the Synchronisation?

While designing a new class/function there are some thoughts to do.

  1. Could it be useful to others?
  2. Could I use it in other Apps?
  3. Could it be useful to have it as TWhatever<T>?
So if one of 1-3 is true - I have a new class/function in one FDK-Unit or perhaps a new Unit at all.

The next thing is: Where would I like to execute this stuff - Main-thread or Background? If the answer is Background the next question is how! With existing threads or a new one? Should the User just place it into a TTask.Run?

Threading is a big part of the FDK and there are 14 Units at the moment dealing with threading. Some of them using a basic thread implementation from another unit, some implementing their own Threads because of special needs.

So for this blog post lets assume background operation, but every background execution has some point of the interface into the Main-Thread. And here comes the question:

Where to do the synchronization? 


Let's have a little example:

Procedure Button1Click(Sender : TObject)
var
  LMemoText : String;
begin
  Button1.Enabled := false;

  TAsync
  {} .Await( Procedure
               begin
                 LMemoText := THTTPRead.URL(SomeURL); 
               end )
  {} .Execute( Procedure
                 begin
                   Memo1.Lines.Text := LMemoText;
                   Button1.Enabled := true;
                 end );   
end;

So the Await procedure is running in a thread, that's why I set a string and not directly the memo. The Execute procedure is called in MainThread to handle UI-Stuff. So the synchronization is handled internally. It could be different... But this is the common usage of this TAsync. I Could write it so: 

Procedure Button1Click(Sender : TObject)
begin
  Button1.Enabled := false;

  TAsync
  {} .Await( Procedure
             var 
               LMemoText : String;
             begin
               LMemoText := THTTPRead.URL(SomeURL);

               TThread.Queue(NIL,Procedure 
                 begin
                   Memo1.Lines.Text := LMemoText;
                 end);
              end )
  {} .Execute( Procedure
                 begin
                   Button1.Enabled := true;
                 end );   
end;

But in this example the synchronization is done twice...

Back to the question: Is the internal synchronization of the Execute part a good idea? In the example I think yes. 

Sometimes internal synchronization could be a bad idea especially if TThread.Synchronize is used and not Queue but in the next example even Queue did not help, and here is the reason:

Normally I would do any HTTP related things with a callback, but for this example I like to show a Modal-Call of an Async function, just for Demonstration.

Procedure THTTPRead.URL(Const AURL : String) : String;
var
  LEvent : TEvent;
  LResult : String;
begin
  LEvent := TEvent.Create(NIL,true,false,'');
  
  try 
    THTTPTAsync.URL(AURL, Procedure (Const AResult : String)
      begin
        LResult := AResult; 
        LEvent.SetEvent;  
      end);

    LEvent.Wait;
  finally
    LEvent.Free;
  end; 

  Result := LResult;
end;

Don't do this ;-) but if, then hope that the Result procedure is not called in a TThread.Queue, because this would be a dead-lock. If you have a Threaded or Async Class/Function use it always as it was designed for. 

On the other hand, I hate to put in a TThread.Queue in every Call-Back that's why I often design an optional parameter.

THTTPTAsync.URL(AURL, Procedure (Const AResult : String)
  begin
    _Result := AResult; 
    LEvent.SetEvent;  
  end,false); // false = no sync

For better code reading perhaps rename the call like

THTTPTAsync.URL_NoSync(AURL, Procedure (Const AResult : String)
  begin
    // Whatever
  end);

or

THTTPTAsync.URL(AURL, Procedure (Const AResult : String)
  begin
    // Whatever
  end,TSync.No); // TSync = (Yes,No);

Honestly, I mostly just use a boolean, but I'll put it on my list for refactoring.

So with this approach, I have the best of both...

Monday, September 3, 2018

App-Development, Cloud-Server and distribution to multi clients!

Cloud-Database.. (And many more...)


OK - It's just a computer at another location - so what is this blog post about?

It's about the next step form my last blogpost: Database and Server synchronization.
In many conversations with other developers, most of them want to build a mobile app that is kind of an Access Point to the data used by one or more  PC-Application(s).
At first - no Form from the Desktop App should be taken into the mobile App!
Designing a mobile App with a "smaller" UI, to achieve some of the basic functionalities that are necessary to handle the data, is not a big deal. If you are new to FMX, it just takes a while.
So how could you overcome the problem of not reinventing the wheel and perhaps reuse the work for the next App, too?
BTW: Thank you for reading my blog… This blogpost is again just for advertising my Firemonkey Development Kit. ;-)  (sorry, linked post -  is not translated, yet)
Best practice for the development of libraries like my FDK is as always: "Eat Your Own Dog Food".
And I can promise  -  I eat it every day! It saves me a lot of time and things are always easier.
The next version of the FDK would have some new plugins.
  1. Simple ORM
    Just create a class with some Field-Attributes and you'll get a Database with a Table to store the Fields. (nested Tables are also supported, for multi entries like 1-n Bank accounts or 1-n communication - subtables )
  2. CRUD IO
    You like the easy CREATE / READ / UPDATE / DELETE access of your data. Set some Class-Attributes and use the simple ORM model to build your application.
    An Easy SQL-Producer is included.
  3. MVVM 2.5
    How to Access the Data? Just bind (in Code) the View to your ViewModel/Model (CRUD->ORM) class and you can easily display the Class from (1) on your View.
  4. All your Events - PropertyChanged - are auto-connected with one line of code. You can multi-connect data to 1-n UI-Fields. Data->View, View-Data and Bidirectional, with optional converter functions. There is no need for a special UI-Component and there is nothing to drop onto your form. As described in this post.
  5. Async Await
    Perhaps you know Async Await from C# - I have a "lite" Version for UI/Async/Threading tasks included.
  6. Async Threading Command Queue
    The Threaded-Command Queue is for SQLite/Embedded Databases that can only handle one Thread/Connection at the time. Define your Data-Access-needs and just call them by Name. The Queue will handle all your calls one after another - or if you have some important stuff to do, you can call it prioritized.
  7. JSONStore-Server
    A "just use it" Unit to store every data you like in JSON Format on your server database.
  8. REST-JSONStore-Client
    To handle the JSONStore Server-Side you get the Units to handle all transfers/updates/locking/rebuild features to do your data-exchange with the Server or/and multi Clients. Of course, this module has the Async Threading Commands for the module (6) included doing everything in the background.

So what is the deal? My goal for mobile App creation was:
Create your UI - create your Classes - just set some Bindings and Field-Attributes. Nothing to drop on your form and nothing to set in the object-inspector!

Just write some uses and have fun...








Saturday, August 18, 2018

Database and Serversyncronisation

As a developer I would like to program fancy stuff, but in 90% of my time I only transfer Data from here to there...

Edit -> Memory -> JSON -> REST -> JSON -> Query -> Database.
or
Database -> Memory -> Form -> Memory -> Database.

Collect data here, combined with data from there, ask the user and write it back.

Sometimes

Client 1 : Form -> Database -> JSON/REST -> Server -> Database;
Client 2 : Server -> JSON/REST ->  Client -> Database.

Comparing problems on a single non Server App against a Multi-Client-, Multi-Server-Environment you can find pitfalls on many procedures.

With all the mobile devices you normally have more the one location of your data and if you provide a mobile solution to your desktop application, the user expects a synchronization over the "cloud".

I've always developed it again and again for every new App, but why?

My cloud store is using the same database structure as the desktop and the device database was often nearly the same. So to store the data into the Server database I had to develop it each time.

For my application there is no need for a web interface, so the server must not have access to the actual data.

So finally I've developed a Class/ORM/CRUD/Cloud store interface that can be used by all of my (FDK) Applications. Both interfaces for Client and Server are in the next FDK-Plugin. so stay tuned.

So next time more fancy stuff and less hassle with the data.



Wednesday, July 18, 2018

Delphi & C++ Builder Community Editions are online...

For many years a Community Edition was missing…
 
Now it is out:
 
 
 Registration and download:
For the moment you could not install both in one VM.


Info from embarcadero.com:
Embarcadero® Delphi 10.2 Tokyo Community Edition is a great way to get started building high-performance Delphi apps for Windows, mac OS, iOS, and Android. Delphi Community Edition includes a streamlined IDE, code editor, integrated debugger, two-way visual designers to speed development, hundreds of visual components, and a limited commercial use license.
To learn more about Delphi Community Edition Click here

Friday, July 6, 2018

IIS an Plugin-loading

The Loadlibrary Problem!


Since many many years I do all my Web stuff with ISAPI.DLL's on one of my Windows Server. Starting with the support of ASP.NET in Delphi I use only ASPX and background code for the Webdesign. (Only one project I've done with VCL for the Web.)

The benefit with ASP.NET was, that you do not have to restart the IIS to change the code behind.

There was an ISAPI Loader from egg-Soft that was able to update the working DLL on the fly if you upload your dll as name.upd - works great for many years.

After updating the server to 2008 R2 this loader did not work anymore… So every time I had a new version of my DLL's I had to stop and restart the IIS. Normally a 1-second interruption, if your IIS is only handling local stuff or just producing websites.

But for 5 years I have a web service for my customer running, that depends on an external service. The service sometimes takes some time and I have many requests. So stopping and restarting the IIS take 5-25 seconds and that is bad for my customer. Every development took place only at night.

Inspired by the EMBT Rad-Server project I want to build my own Service (perhaps as part of my FDK)

Project/New/ISAP.DLL but this time with loadable and unloadable plugins. My idea was - I provide you with the hard stuff and you only have to write your business code.

The FRS - Firemonkey REST - Server was born.

Or Fast-Remote-Service? Because in some parts the Firemonkey part in FDK is wrong, because you could use it in VCL, too - I do not have finally considered the Name. 

A working demo was done in one day (2016) - LOCAL - but my first try on a real server - nothing. No plugin could be loaded, only the root admin things are running. No idea where to look. But as always: While starting a new project - there was no time for digging into this problem.
Sometimes before I build a new ISAPI.DLL I'll try some Ideas (2017), but after a few tries I build a new ISAPI.DLL with copy/paste from the last one.
But not this time. (2018) After some chatting with MVP Andrea Magni (MARS-Curiosity) and after some logging - I found the problem. Loadlibrary did not come back and crashes the AppPool. No Idea. Andrea provided me a Link. DLLMain - What? I have no DLLMain so I did not see the hint at the first read.
The hint was: do not call Loadlibrary in the Main-Thread. From my point of view every ISAPI.DLL is loaded by the IIS and with every request the IIS creates one thread of it.. So never in the Main-Thread.
After a few tries with LoadLibraryEx - I tried to compile my DLL's in 64Bit so this WOW thing is not necessary. LoadlibraryEx worked but no handle or a handle but nur GetProcAddress.
After some googling for a new version of the Egg-Loader I came back to the Best-Practices Link and finally found "Call LoadLibrary or LoadLibraryEx (either directly or indirectly). This can cause a deadlock or a crash." OK - This is the problem - and perhaps the same for the old egg-loader - and now?
Don't do this and don't do that - but how to load a DLL?

You remember : NOT IN THE MAIN THREAD!

After a simple TTask.Run() around my Plugin-Loader everything works fine. Perhaps I will create a normal thread for this task. But for the moment it's working (that are the good news) - the bad news are: Now I'm able to build all that stuff that is on my wish-list and I have no excuse not to do it) ;-)
But as always - not enough time.

Monday, June 25, 2018

German CodeRage 2018

Nur eine kurze Erinnerung: CodeRage 2018 am 26.06.18.

Meine Session ist 18:00 Uhr - 18:45 Uhr

Fluiddesign und andere Techniken um sich den Programmieralltag zu erleichtern.

Ab 18:45 Uhr bin ich fĂĽr FAQ's online!


Hier der Youtube-Link.

Sunday, May 20, 2018

Formatting Sourcecode

Formatting Delphi/Pascal Sourcecode is an interesting topic.

Take 10 developers and let them all hand-formatter some sample source-codes and you will get 10 different results.

You disagree?

Most developers have developed their own style in formatting source code because they are working alone and nobody else would see the code. Perhaps you are new to Delphi and used another programming language for many years. I can not remember what Delphi version was this first with an included formatter CTRL+D. Perhaps before that, you are using an IDE plugin or external program.
If you are working alone - do whatever you like with your source-code, but if you have to work together with other developers in a team - it's time to think about "your" formatting.
Some developers like many empty lines and indent nearly everything or want to have a description with a Date, Name, and Copyright over every method. Other developers hate empty lines and only ident one space.
Perhaps you have the "begin" at the end of the line and the "end" at the first position like:
if A > B then begin
  foo(42);
end;
But since the IDE has Castalia or perhaps you are using a third-party-tool you got the funny colored helper-lines to show the corresponding begin-end's, it is better that begin-end has the same ident.
Is there a right way to format your source-code? You may have the standpoint - only the default formatter-settings are the right way.
Keep in mind - if you are writing a program, you will read more source code then you write or in other words writing source code is not the trick, writing source code that could be read easily and by other developers too, is the goal.
Of course, the formatting is just the start, the next topics are caps, spaces and naming. There are so many rules out in the field.
Class fields have an "F" at the beginning, parameters an "A", local var's an "L". Perhaps you like to mix your local language with English (better not). Are you rename all your visual controls?
Label1 -> lbName
Edit1 -> edName
Edit1 -> NameEdit
Do you like long var-names "Name_of_the_person" ( hope not with "_" )
So where to start?
In the next day's I will try to introduce some of these rules to a team of four very different developers. Let's see if I can create a set of rules that everyone can live with.
But that will eventually be a topic for another blog post.

Thursday, April 26, 2018

MVVM 2.0 - I did it my way.

If you like, you can compare this with one of my older posts from 2016: MVVM - Or what I think MVVM is.  (Translated)

Why MVVM?

  • Because it’s cool and I’m a geek
  • to show – I’m better than other developers
  • so nobody else could maintain the code

no – perhaps – NO!!! Just joking!

Because we like to
  • separate forms from code
  • to get better maintainable code
  • have less-hardcoded dependencies
  • to be able to test the business logic
  • to test the workflow

Sure? Are you writing tests? If not – stop reading…
But perhaps you like to develop code you can use again in other applications…
Ask 10 developers to explain MVVM – at first; you will get a picture from dotnetpattern.com, msdn.microsoft.com or wikipedia.org, then everybody tells you: “This is the pattern and “so” it has to be implemented”
OT: Like many other patterns… You have to follow the rules of these 4 guys and the book from 1994! More than 500.000 copies of the book have been sold – not so bad at all…
Back to MVVM - If you ask for the details, you will get 10 ideas on how to implement it.
But… We are Delphi developer – why should we try to implement things as Microsoft did in .net? Because this is the right way?

Let us dive into:
The core elements are View, ViewModel, and Model. In the beginning, you could trade a TForm as the View, but this is not the same. A TFrom could be the container for many views at the same time. For the moment, we say TForm = View – the key things of MVVM are the bindings or better, the communication from ViewModel to View and back. (And perhaps to the Model)
If we follow the rules – the view should have no logic, the ViewModel is responsible for handling the view-logic and converting the data to the View and the Model contains the data. (hope this is right) I never took this approach.
Our view is not a stupid XML-only-description of visual controls. Our controls always have their own logic, we have styles and animations, able to do onMouseover/down/up things. Trigger doing fancy stuff.
The Model is dealing with the data and the Database, too? I don’t think so. What is a database?
Neither my ViewModel nor my Model knows what a database is. The Models get an interface to store or load data – without knowing where it ends.
How does communication work?
The Model changes some data and now the ViewModel wants to inform the View or perhaps all Views, about this change.
At first, we need a Multicast event to inform more than one View about the new data. So every view has to sign in for the event. Now the ViewModel could send a PropertyChanged Event like:
PropertyChanged(PersonNameProperty);

Every view – that is able to show the change, gets the Event and could ask the ViewModels Property PersonName.

What?

PersonNameProperty is defined as:
Const PersonNameProperty : String = 'PersonName';

Use Consts and no magic String so we always have the right typo. OK…That is good, but:

In the View, we end up in a

procedure PropertyChanged ( Const APropertyChanged : String);

Comparing with many If then else constructions (first bad thing) and because we have a const in the ViewModel, the reference is not the same so the string-compare must compare all chars. (second bad thing).
If we have a huge view (yes we could perhaps split it) we and up with a too-long comparing procedure.

Since Windows 3.1 - in the early days – Messages are sent with the content or at least with a pointer to the content.
So why are we just sending change “hints”? This is like sending an SMS – I have news call me back, instead of “I will be late, arriving at 8pm”.

Sending Strings is good for testing. Eg: A property change of PersonName := 'NewName'; should fire 'PersonName' – I tried Const ID’s  like Const idPersonName : Integer = 42; Not so good for testing but you can use a case at the View.

I don’t like to repeat on every Property:
begin
  if FPersonName <> AValue then
    begin
      FPersonName := AValue;
      PropertyChanged(PersonNameProperty);
    end;
end;
Same in every setter.

Then to the View:
if APropertyChanged = TPersonViewModel.PersonNameProperty then
  PersonName.Text := FViewModel.PersonName;

I first implement the MVVM Pattern the MS-way, but if you think – “Too much writing” or “I did not test my code” – you are right and of course, debugging is not so easy, too…


In fact, development time takes a bit longer. This extra time cut’s down my Test-writing-Time… (Bad thing three), because I love TDD.

It is faster if you could use the same Model or perhaps the ViewModel in another project, but that is another story.

These problems lead me to “my way” MVVM 2.0…


We have attributes and the RTTI!

I think: The best way to use a pattern is if the pattern is not so far from your normal workflow.


I like to design my Forms and so my Views as Forms, too – Frames are bad and often lead to problems with the IDE. So SubViews are Forms with a TLayout-Container that parent is mapped to the target-parent at runtime.

My new workflow is:
  1. Create a Form/View
  2. Change Class(TFrom) to Class (TMVVMForm) / or Frame for SubViews
  3. Put attributes at FormControls like [ViewModelLink] PersonName : TEdit;
  4. Create Procedures with attributes like
    [PropertyChange]
    Procedure PersonNameChanged(Const AValue : String);
  5. Register the Form at the ViewLocator with the necessary ViewModel
  6. That’s it.

In your NavigationService you could get the View from the ViewLocator for a given ViewModel and an optional Name. On Creation the View connects all bindings and propertyChanges.
You like to change Names? All attributes take optional name parameters. For:
[ViewModelLink(TPersonViewModel.PersonNameProperty]
Edit1: TEdit; // Better rename this!
Now to the ViewModel:
  1. Create a class TPersonViewModel = Class(TRootViewModel)
    I don’t like ViewModelBase as Name – it sounds like a database for ViewModels…
    All my DBClasses ends with Base – PersonBase not DBPerson!
  2. Define your private Fields as
    FPersonName : autochange<string> // FPersonName : String
  3. Property PersonName : String : read GetPersonName write SetPersonName;
  4. Procedure SetPersonName(Const AValue : String);
    begin // Auto-PropertyChanged if different.
      FPersonName.Value := AValue;
    end;
  5. That’s it.
Most of the stupid code writing is not necessary anymore and done in the background over the RTTI.
Of course, this is only a small part of this pattern, but now I can point my focus on the more advanced parts.
You like this approach? – Please leave a comment – if not…;-)
  

Wednesday, March 14, 2018

Neural Network

Neural Network or Neuronal Network... Whatever...


For many years I want to test this kind of programming... But never had time for this.

You can find many videos on YouTube, but "all" are full of math or full of the wrong programming language. ( or both )

You can find some source files, but what is the minimum of LOC's you need?

For now: Less the 300 LOC in Delphi for a working network.

At the moment I have many ideas about what I can do with this... But perhaps first dig into the next step:

Genetic algorithm.

I will include this in the FDK, if ready...

Best video I found: 

https://youtu.be/-zT1Zi_ukSk (C#)
https://youtu.be/KkwX7FkLfug
This, I take to just live to code this - with many modifications - in Delphi - a little bit of debugging and it works. ( not much longer than it takes to look the video)

Tuesday, February 20, 2018

FDK XE8 - 10.2

Hello!

I've already found the time to compile my FDK for XE8 up to 10.2.2!

I finally found the F2018 error so XE8 and Seattle are working again.

So starting at this point I'll prepare the next update.