Sunday, May 22, 2022

How to format your Delphi-Sourcecode!

At first:

Formatting your source code the Embarcadero way is not a mistake or to make it clear, probably the best way to format your code. Especially if you want to share your code with other developers.

But...This is not my way...

So I'm doing it wrong? No... I have good reasons to format my source code in a different way!



I have implemented some of my formatting rules many many years ago and some of them in the last 5 years. Some rules I developed at a time when nobody talked about that a procedure should have only 75 lines or "must" always fit completely on the screen. Therefore it was necessary to guess from the formatting what is "hidden" in the invisible part.

There are four kinds of rules:

  1. Formatting and Indenting
  2. Formatting on Syntax
  3. Naming
  4. Empty lines or other "small things"

All rules are "just" to make the code more readable or in some cases better maintainable.

One drawback of my rules: No formatter is able to format Delphi source code 100% according to my rules.

Therefore I started the development of my own code formatter some time ago. My formatter is using a different approach to format code. First, a tokenizer creates the syntax tree, and then a procedure is called for each part.

E.g. to format the uses list, a procedure "format_Uses" with all the necessary sources is called. By default, the code just formats it the Embarcadero way or you could implement your own method for this. So beyond some settings, you can do everything!

I'm very busy with my main "job" for some time and that's the reason this project is in the WIP folder.

So enough talk, here are my rules.

Let's start with a simple one... And don't expect a complete list here it would be out of scope for a little blog post. If you like my style of formatting or my rules, please write a comment. If enough developers would like to see more, perhaps I consider writing a complete rule book.

case Whatever of
  whNone : ;
end; // of case

All case ends gets this comment because this end is the only end without a begin.

TFoo = class   
  private
   
fWhatever : String;
   
fCount    : Integer; 

    function 
GetWhatever : String;
    procedure
SetWhatever( Const aValue : String );
    function  GetCount : Integer;
    procedure SetCount( aValue : Integer );
  public
    Constructor Create;
    Destructor  Destroy;override;

    Property Whatever : String  read GetWhatever write SetWhatever;
    Property Count    : Integer read GetCount    write SetCount;
end;

OK, this end has also not a begin, but the is not inside the source code where you have multiple levels of begin ends. For many years I've written FWhatever, but a lower f is more readable in many cases, like FField or fField. The lower "f" is easier to ignore while reading. Also, every function gets an extra space so that the method names are in the same column. the sane for the destructor. There is an empty line after the vars... And the properties got formatted by length for better readability.

Please compare this with:

TFoo = class   
private
  
FWhatever:string;
  
FCount:Integer; 
  function
 GetWhatever:String;
  procedure 
SetWhatever(const AValue:string);
  function GetCount:Integer;
  procedure SetCount(AValue:Integer);
public
  Constructor Create;
  Destructor Destroy;override;
  Property Whatever:String read GetWhatever write setWhatever;
  Property Count:integer read GetCount write SetCount;
end;

Well-formatted source code becomes more and more important for me the older I get.

Naming

Again field values get a lower "f", params get a lower "a", local vars in methods get a lower "l", and const values get a lower "c". I know the small l is not so easy to distinguish from the upper "I", for Interfaces.

But you would never write IFoo := NIL... 

User   
 
System.SysUtils
, System.Classes
, FMX.Graphics
, Web.HTTPApp
, FireDAC.Phys
, FireDAC.Phys.MySQL
// , FireDAC.Phys.SQLite
, Delphiprofi.FDK.FireDAC
, Delphiprofi.FDK.QRCode
, Delphiprofi.FDK.Server.ISAPIHandler
{$IFDEF DEBUG}
, Delphiprofi.FDK.Logging
{$ENDIF}
, Settings
, HTMLHandler
;

By formatting the uses with a leading "," and only one unit for each line, you can easily comment out some units and excluded unis by IFDEF is much better readable. After that, I like to sort my units..

  1. System
  2. Plattform
  3. Other RTL
  4. Frameworks like my FDK
  5. Units from the project. 

Please compare this with:

User   
  
Settings, Web.HTTPApp, System.SysUtils, Delphiprofi.FDK.FireDAC,
FMX.Graphics, {FireDAC.Phys.SQLite}, Delphiprofi.FDK.Server.ISAPIHandler, FireDAC.Phys, FireDAC.Phys.MySQL, System.Classes, Delphiprofi.FDK.FireDAC, Delphiprofi.FDK.QRCode, Delphiprofi.FDK.Server.ISAPIHandler{$IFDEF DEBUG}, Delphiprofi.FDK.Logging{$ENDIF}, HTMLHandler;

Formatter on Syntax

Do you remember these days, when your source looked like this:?



These days I created a simple rule...

Do you know, if the "if FileExists ..." has an else part? No, not from this point in the source code. Then you have to scroll down and if the procedure is very long, you have to scroll way too far down for this information.
If the "if" has an else part, the "then" is in the next line, if not the then is in the same line as the "if".

So simple, this if has an else:

if FileExists(fLogFilename) 
  then begin
         FS := TFileStream.Create(fLogFileName, fmOpenReadWrite);
...

This if has no else:

if FileExists(lLogFilename) then
  begin

    FS := TFileStream.Create(lLogFileName, fmOpenReadWrite);
...

Of course, never format it this way, because the lines from begin to end do not work:

if FileExists(LogFilename) then begin
  FS := TFileStream.Create(LogFileName, fmOpenReadWrite);
...

So it look like this if you have only one line:

if 
FileExists(aLogFilename)
  then FS := TFileStream.Create(aLogFileName, fmOpenReadWrite)
  else FS := TFileStream.Create(aLogFileName, fmCreate);

In any other cases, it looks like this:

if FileExists(cLogFilename)
  then begin
         FS := TFileStream.Create(cLogFileName, fmOpenReadWrite);
         Whatever := 'XX';
       end
  else begin
         FS := TFileStream.Create(cLogFileName, fmCreate);
         Whatever := 'YY';
       end;


and by the way... cLogFilename a const not a var anymore. And if you look up you can recognize one var is a (l) local, one is part of an object (f), and of is a param to this method (a) containing this code... If you just write LogFilename like in the bad example - you have no clue where the var is defined.

Empty lines and CR's


Where to put an empty line an where not, is the most overseen method to make your code more readable. Let's take a look at this bad example (stupid code):

Procedure TMainModel.LogVars(LogFilename:string);
var i:Integer;FS:TFilestream;
begin
 
LogFilename:=TPath.Combine(Path,Logfilename);startconvert:=true;
  if FileExists(LogFilename) then begin
    FS := TFileStream.Create(LogFileName, fmOpenReadWrite);
  end else FS := TFileStream.Create(cLogFileName, fmCreate);
  for i:=0 to varlist.count.1 do begin
    for var k:=0 to varlist.count-1 do varlist[k] := prepare(varlist[k]);
    
fStartConvert := true;
    if varlist[i].MustConvert then convert(varlist[i]);
    Case varlist[i].Kind of
      tkStrLog(FS,varlist[i].ForLog);
      tkInt : 
Log(FS,varlist[i].AsString);
    end;
    if varlist[i].MustConvert then reconvert(varlist[i]);
  end;
  startconvert:=false;
end;


{ -------------------------------------------------------------------------
  (c) by Peter Parker
  1998 Version 1.0 of Whatever...
  Procedure to display a message 
  ------------------------------------------------------------------------- }

Procedure TMainModel.Whatever(Display:string);
begin
  if Display.trim<>'' then MyMessage(Display) else
    raise Exception.Create('no Text to Display')
  if Display='-' then Memo1.Lines.Clear;
end;

Ok, now use my rules... before every "for" there is an empty line, also after the "for". The same rule applies to "if" and case, but not if before is a "begin" or "try" or after is an end ( of course ). Only one empty line between methods. Never write code behind an "elseless" then. (if you read the Display trim stuff... at the first millisecond it looks like this "if" raises the exception.  Here is my code (and simple i is kept, and no stupid comments) :


Procedure TMainModel.LogVars( Const aLogFilename : String );
Var 
  i            : Integer;
  lFS          : TFilestream;
  lLogFilename : String;
begin
  
lLogFilename  := TPath.Combine(cPath, aLogfilename);

  if FileExists(lLogFilename) 
    then lFS := TFileStream.Create(cLogFileName, fmOpenReadWrite)
    else lFS := TFileStream.Create(cLogFileName, fmCreate);

  try
    for var k := 0 to varlist.count - 1 do
      
varlist[k] := prepare(varlist[k]);
    
    for
 i := 0 to varlist.count - 1 do
      begin
        fStartConvert := true;

        if varlist[i].MustConvert then 
          convert(varlist[i]);

        Case varlist[i].Kind of
          tkStr : Log(FS,varlist[i].ForLog);
          tkInt : 
Log(FS,varlist[i].AsString);
          
{$IFDEF DEBUG}
          else raise DeveloperException.Create('you forgot a case entry for .Kind');
          {$ENDIF}
        end; // of case
  
        if varlist[i].MustConvert then 
          reconvert(varlist[i]);
      end;
  finally
    lFS.Free;
  end;

  if fStartConvert then
    fStartConvert := false;
end;

Procedure TMainModel.Whatever(Display:String);
begin
  if Display.trim = '' then
    raise Exception.Create('no Text to Display'); 

  MyMessage(Display);
end;

Every case that has a limited set will raise an exception so you "never" forget to update your cases. If possible Early exit a procedure - this rule for (exit and exceptions). Strings as params get a "Const"... Sometimes you need a local var because of "const", but better if you copy it to a local instance at the very end than passing strings around without a "const". (Consider the string has passed around more than one method.

Now I hope you have an idea why I do it my way. If you consider that my rules are something you would like to use in your code... Be my guest and please leave a comment.

Monday, March 21, 2022

What is the easiest way to create a dynamic web page?

Before I will talk about the topic: Yes, my #DMVVM project is still on hold. I was just too busy to find the time to do the last steps.



I do not talk about the HTML part... From my point of view, it has to be Bootstrap or something similar, so that every target device could be used.

Of course, I'm not talking about static HTML pages, and if you know me just a little bit, you know that I hate PHP and wouldn't use it.

I haven't tested the cross-compiler for Pascal to javascript yet, so even though I've seen it before, I can't really make a judgment on it
.
Of course, I have been using the Webbroker functionality for my WEB projects for years. This technology is ideal for dynamic websites. 
In the past, I had also set up projects with ASP.NET - actually the absolute best way to execute server-side code. Unfortunately, the last compiler (except Prism) was Delphi 2007 and nowadays I would like to use features of the current Delphi versions and compile my ISAPI.DLL to 64 bit.

One really good feature of the Webbroker is, that you can also create it for Linux, but in my case, I always use a Windows-Server. So while the ISAPI.DLL is loaded only once into the memory space of the IIS. The execution performance is the best you can get. Native code running directly on the CPU to deliver the content. 

So why not use it and be happy?

You can upload an HTML file to the Server, you can change tokens to any value you like, you can use a table-producer to show a complete database table inside your content...

But there is one drawback: For every change, you have to recompile your DLL and upload it to the server.
This is of course the same or even more painful if you're not the web designer.

While searching the internet for ideas I found a Razor implementation from Marco Cantù. A nice little piece of code to integrate some functionalities to HTML. But after one day of rewriting, I stop the development and forgot about this idea.

One year later I was working on a new idea to upgrade my TWebbrowser interface to a new level. In our main application, we are using the TWebbrowser component to autofill forms of many different websites. 

(Sad story, which would lead too far here, why the various websites are not able to provide a simple REST web interface)

Some of these websites are disabling the IE so I must upgrade to EDGE. 

With this interface I have reached the same point as with the web design: For every change, I have to recompile the main program.

End of the story? 

Of course not. I had worked briefly on a project where I wrote a UI test framework for our software. For this, I had to use the Pascal script from RemObjects. A small IDE was quickly put together with these components. Unfortunately, the component is somewhat "unwieldy" and I hate to install packages into my IDE. On top, I do not like to click invisible components on a form.

Therefore I wrote - as always - an interface wrapper for these components...

An IDE interface with compiler and runtime and of course separate compiler and runtime.

To do it right from the start, I created the wrapper directly in Fluentdesign and included it in my FDK right away.

Using this Wrapper for webform autofill was done in minutes and now I'm able to load the right methods to do the autofill from our website, without installing a software update of our main application.

Maybe you already have an idea what this is all about.

Of course, now I use this interface for my web design.

Using Pascalscript for web pages is not new, but I have different requirements.
  1. A web designer must be able to modify the code.
  2. I want the bootstrap layout of the whole website to be visible in the editor so that you don't lose the WYSIWYG view.
  3. I want to have a template system, so i don't have to copy header, footer, navigation, etc. in every HTML file.
  4. I want to be able to write inline Delphi (PascalScript).
  5. I don't want to have to parse the Delphi part over and over again.
And already the solution was obvious:

I parse the HTML page, find includes, find the Delphi parts and find tokens that have to be replaced.

So when a new or changed web page is uploaded to the server, I compare the creation date of the file with the compiled version. If the date differs, the page is compiled and written to disk as a new file, with a replacement table and the appropriate compiled Delphi parts.

If the date ~ is the same, the file is loaded and a new response stream is created from the static parts, the replacements, and by executing the Delphi parts. Vola.

Even though in my tests the analysis and compilation of a "normal" index.html take less than one millisecond, the execution is of course only a stream copy and the runtime of the Delphi scripts.

Usually also faster than one millisecond. (Of course not, if you read 10 million data sets from a database) Here the execution duration is naturally still affected by the Delphi parts.

At the moment I have no time for a demonstration, but a Webinar is on my to-do list.

So stay tuned...

Friday, December 3, 2021

The trap of wanting to make it perfect, or #D.MVVM what takes so long?

Hello, my friends!

It's quite some time since my last blog post - I know - it was/is a busy year. 



I regularly get emails asking when my MVVM framework will be ready for shipping. This is a very good question... (It was ready nearly two years ago - my designated release date was 2019-12-06)

What? 

Yes, I'm sorry this is the sad truth because just one week before my estimated release date of the beta version I decides to cancel it.

Why?

As it is/was a source code distribution, after a close look at the code, it was messy and really unreadable. 

So I started a little bit of refactoring.

To demonstrate the power of the framework I also started writing some sample applications for VCL and FMX and also some mockups for unit tests.

Getting more and more into real-world design details, everything was working so far, I found some places that could be better, or in other words: The comfort of the framework was not easy enough to create some special bindings. 

Of course, from the early beginning, the main binding unit was able to bind everything (by "Hand", I mean in Code).

At this point, I could just follow the bad rule: "It compiles, It works, just ship it". 

But I expected more, so I deleted all binding rules and the main binding unit. There has to be a better way. (At this point I also decided, not to stick as close as before to the MS-C# MVVM examples)

Just imagine: You have a ComboBox for "Mr., Mrs, Sir, Dear" this might be a close list (Style: csDropDownList) or just (csDropDown) where you are able to put in a free text.

If you didn't watch any of my MVVM-Youtube Videos. My Framework could bind to "normal" properties at the ViewModel, but I also created my own TProperty<T> fields which are much better than just properties. E.g. all the PropertyChanged or INotifyPropertyChanged events are builtin.

So if you want to set the Item list from the ViewModel (like reading the Items from a database), you probably want to bind to the Itemindex and to the Text-Property and perhaps (on FMX) to the Textpromp property. The UI often has to enable the controls or even set the visibility and last but not least perhaps you want to set the hint text. (In most cases you want to handle the OnChange event or the OnClick)

In the MVVM-Pattern you normally do not set a Visual Control Visibility in the ViewModel, or even the color. This is part of the View on some conditions. Like: ViewModel.CanSave or ViewModel.CriticalState (to show a warning label in red)!

After talking to many Delphi Developer I decides to enable the visual settings also to the TProperty<T>. So if you have

Name : TEdit;

on the View (Form) and a property field like:

fName : TProperty<String>;

you can write

fName.Enabled := false;
fName.Text    := 'Frank';
fName.Hint    := 'could not be changed';

in the ViewModel.

If you think that is not like MVVM should be... Sorry, I don't care!

So it is even possible to Name it EdName:TEdit on the View and set your own naming converter to bind all TEdits with Ed[Name]:TEdit as a prefix to f[Name]:TProperty<String>.

So back to our TComboBox problem:

With

Salutation : TCombobox;

the ViewModel could look like this (Property Version):

{ I skipped the getter/setter here to make the code more simple }

TPersonViewModel = Class(TViewModel)
  private
   // ...
  public
    Property Salutation : String;
    Property SalutationItems : TStrings;
    Property SalutationIndex : Integer;
    Property CanShowSaluation : boolean;
    Property CanEditSalutation : boolean;
end;

Or mixed with command Methods like:

TPersonViewModel = Class(TViewModel)
  public
    procedure SalutationClicked;

    function  CanEditSalutation : boolean;
    function  CanShowSalutation : boolean;
 
    Property Salutation : String;
    Property SalutationItems : TStrings;
    Property SalutationIndex : Integer;
end;

Or with my TProperty<T> fields:

TPersonViewModel = Class(TViewModel)
  private
    fSalutation      : TVisualProperty<String>;
    [ OnValueChanged('SelectionChanged') ] 
    fSalutationIndex : TProperty<Integer>;
    fSalutationItems : TListProperty<String>; 
  protected
    procedure SelectionChanged;
  public
    procedure SalutationClicked;
end;

My goal was/is: To support all these different methods and also bind everything without even one single line of code. Don't get me wrong - also nothing set in the Object Inspector. No double click on an event! Just a barebone Form clicked together nothing more.

That's why I had to reinvent the binding rules syntax!

So one ComboBox must auto bind by name (perhaps with a rename rule) to three different fields! Only one should have the visual parts (that should raise an error if more than one is bound). On value change should automatically call the SelectionChanged procedure, the Index property field should be an Integer nothing else, and the OnChange, OnChangeTracking (FMX), and the OnClick event should be connected to the corresponding fields, properties, or procedures. You should be able to mix my Property-Field with normal Properties. 

On top:

There is one visual component with one OnChange event... Where to bind?

of course to fSalutation:TVisualProperty<String>

and not to the two others. So the syntax for the binding should be able to define where to bind the events...

For the Combobox, the style like 
csDropDownList limits the possibility to bind the control to the string property and in this case the OnChange event should bind to the 

fSalutationIndex:TProperty<Integer>
 

field. (Or just to a SalutationChanged method...)

Not an easy task you can imagine!

I have done some work over the last two years, but the main part of the binding stuff I didn't touch. Or even worse, I no longer understood my own source code. 

I tried my best, but without renaming methods and variables it was impossible to read. I often looked for a distraction so that I would not have to deal with the actual problem. It certainly took me 10 attempts to finally start developing the binding routines again. 

So...

There is good news and bad news!

I think I see light at the end of the tunnel, but I need a few more months to get an alpha version on the road. (Ahh and btw. I developed an IDE-Wizard to create a new #DMVVM application for VCL and FMX also not 100% finished and not tested with D11, yet).

I'm still in my own trap to develop the best MVVM-Framework money can buy...

How to bind Stringgrids or event TreeViews are totally beyond the scope of this blog post...

So please stay tuned...


 

Wednesday, September 22, 2021

US Version of my German CodeRage 2021 session is online!

My contribution to the German CodeRage 2021 on September 9, 2021.

The 40 tricks/techniques that every developer should know.

This is not about knowing the different software patterns, but the little tricks that often make development easier. In this session very simple things are shown, but also quite sophisticated techniques are demonstrated. So there should be something for the Delphi beginner as well as for the advanced Delphi developer.

It's now online with the US-Translation on my YouTube Channel!


Sunday, September 5, 2021

CodeRage Germany Sep 9th, 2021

Of course, I'm doing a session on the german CodeRage 2021. My session is not about FMX and not about MVVM... Hard to believe, isn't it?



This time my session topic is:

The 40 tricks/techniques that every developer should know.

This is not about knowing the different software patterns, but the little tricks that often make development easier. In the session very simple things are shown, but also quite sophisticated techniques are demonstrated. So there should be something for the Delphi beginner as well as for the advanced Delphi developer.

As this is the German CodeRage my session is in the german language. But if I find the time I will provide an English Version on my Youtube Page - Delphiprofi.




Thursday, July 22, 2021

What happens when the flood comes?

Maybe you have seen it in the news or are affected yourself...

There was a flood catastrophe in Germany, due to heavily rained and overfilled dams.

But that's not what this blog post is about. 

The question is: How well is your network/server infrastructure set up to function again as quickly as possible in such a crisis?

I'm not talking about backups here, everyone should have those anyway! I'm talking about the structure and the software you use.

A small example: 

Is the MySQL server IP hardcoded or is it stored in an INI-file? Is a URL used or a domain controller? 

Is internet access needed for smooth functionality, because the server may have to synchronize data with an external server?

What if you change IP addresses due to an emergency solution?

I just imagine how your thoughts circle over your own network structure and creates an OMG...

What I've learned in the last few days:

  • It's just terrible how dependent we are on the Internet these days.
  • It must be possible to replace ground Internet access with a mobile solution at any time.
  • Document folders and paper storage are good. (Still necessary in Germany, unfortunately). But you can't digitize too much! Especially when you're looking for an insurance contract and can only wave behind the corresponding folders as it just disappears into the floods.
  • A pile of paper according to the motto: I'll scan that when I have time for it... Will never exist anymore.
  • Software that needs a fixed IP must at least be able to load this information from an INI-file.
  • Software that can only handle IP4 must also be able to handle IP6.
  • Software that gives permissions based on the Mac address needs to be redesigned.
  • Software that requires a domain controller or a fixed network name must be redesigned.
  • If a local server is needed on the network, it must be possible to replace it with a cloud solution.
  • Password storage software that encrypts all collected access passwords must have a simple memorable password to open the information!
  • IP telephony is crap.
  • If there is no electricity and no internet, all-important numbers must be stored in the cell phone. (Preferably also cell phone numbers because your opposite surely also has IP phones that do not work without internet and without electricity.

Well - this is all doable. And I'm sure I will find the time to do this ASAP.

We were lucky this time. No employee is injured and everything else is replaceable. Unfortunately, there are far too many who have been hit much harder. My thoughts are with all those who lost much more or everything.

Saturday, June 19, 2021

Is HTTPS enough to secure your connection to a Webservice?

For many years, hardly anyone has bothered to secure their own server with a certificate or HTTPS. Why?

Because certificates are expensive and there was no reason to secure a private handwritten HTML page with the family pictures.

Bussines Websites with money transactions were the first to go HTTPS.

In the old days, many or nearly every MySQL Server had an open port to the internet. Today you can't do that anymore.

Is it so? Everybody will probably answer this question with:

"You have to connect to the database over a REST-Service, for safety!".

But what is the difference between login to a REST-Service and login to a Database-Server? Log in to a Database-Server is done with User and Password. And to a WebService? Normally with basic authentication, what under the hood is User and Password.

So why is it better to use a Webservice instead of a direct connection? The WebService could do more checks. Well, besides the security, if you send a request directly to your database server everything has to be transferred to the client. Inside a Webservice, you can prefilter manage and do different things before you send the data to the client. This could reduce the amount of data that must be transferred, but on the other hand, if you use JSON the data gets expanded by all the fancy { and } and some data gets really big, like pictures or other data blobs, because every byte has to be encoded with Base64 or Hexstrings.

As the internet gets faster and faster it looks like nobody cares anymore about the amound of data. The days for handwritten, optimized HTML are long gone. Everybody is using some kind of framework that transfers big javascript files with every response.

So, let's say that more bytes are transferred, so the database connection is certainly slower, but nobody cares about it, because of the increased security.

If you are using HTTP everybody in the middle could read all your data, that's why you have to use HTTPS. Thanks to Let's Encrypt it is not a factor of money anymore. But how secure is your connection?

If you open a website with your browser, you get this little lock in front of your URL. Nice we are safe! Are you sure? Let's leave that aside for now. What about when we query a REST(Full) web service from within an application?

We use a component or native HTTP-Get to the URL of our web service. The URL has HTTPS at the beginning.

Are you sure you are connected to your server?

Let's check if the certificate is correct! That's a really good idea. So we write a little proof of concept application. Intercept the certificate-check-call and compare if the information matches our certificate. 

And?

Fail! This is not our certificate! Is there a Man-In-The-Middle? Yes, it's your virus-scanner application! A very bad habit of a virus scanner is to check all HTTP and HTTPS traffic to find bad HTML that could harm your PC or your data.

Of course, it could also be another tool, such as Fiddler. But that should be clear to me because in this case, I started the tool by myself. However, on the way from my internet connection to my server, a corresponding tool could also be used.

I have no clue if the virus scanner has a backdoor and I'm not an aluminum hat carrier. But let's assume for the moment that this is the case, then the login data to your web service has been sent directly to the NSA in plain text. LOL...NSA in this case stands for all strangers who should not receive your data or logins.

If you have to protect your data stream, in this case, you have two options. 1.) Ignore it and may the NSA be happy with my login information, or 2.) Stop the data transfer.

So we are doomed?

There is one possibility you can do. (Not so easy on a website, but from your application).

Crypt your traffic!

Use the public RSA-Key of your Service to crypt your request. Send the public key of your application to the server so that the server could encode the data for you. Perhaps change the key for every new request.

Doesn't that sound familiar? 

Yes, it's like the SSH/HTTPS handshake. Thanks, virus scanner developer. 

Oh, by the way, if you are doing the crypting by yourself anyway, there is no need for an SSL certificate in the first place.

One nice side effect: Any tool that is trying to read your data stream can not fool you with its own certificate to read the data.

If you have read this far, I have one last question: Should I do a webinar / Youtube video on this topic?


Please leave a comment.






Wednesday, May 26, 2021

Stackoverflow: This time with Delphi in the list.

There is an annual developer survey going on on Stack Overflow. Delphi is in the language list, now we need Delphi developers answering the survey and ticking Delphi to show it is relevant. Stack Overflow account is not required.

So please fill out the survey and on the environment question, please enter "RAD Studio" in the empty field.

Here is the link.

Monday, May 3, 2021

TCoffeeAndCode - Threading and Concurrency

Hello!

Are you interested in learning more about threading and concurrency?

On Wed, May 5, 2021, 7:00 PM - 9:00 PM CEST 

or for better understanding 17:00-19:00 UTC,

you can listen to how we approach these things and what our opinions are on these topics.

Here is the replay!

Saturday, February 27, 2021

Delphi 10.4.2 - What is your current Hardware for Development?

Well, this is of course not related to this newest version of Delphi, it's the right question for every Developer, but with every new version of Delphi, this topic is back on the table. If you're looking for my opinion on 10.4.2 - please just scroll down!

Declaimer: This is not related to Embarcaderos specifications of minimum requirements, this is "just" my point of view.


Let's start with a little example:

If you were a carpenter, would you buy a jigsaw from the hardware store for 49.95 or would you have a high-end circular saw table that can do everything you need?

If you have to cut down an entire forest, you wouldn't use a handsaw, but a chainsaw, would you?

Is it possible that your 3D printer cost more than the laptop on which you "work"? 

I just read a question about the new IDE: "If I press a key and the LSP has to update, I can hear my Laptop-Fan is ramping up... 

Laptop? Really? Are you kidding me... 

There are some Laptops out there, you can probably use...But for this price, you better buy a third Monitor.

Ok, If my system is mining in the background and I'm watching a Video while loaded up 3 VM with different IDE's sometimes I hear the fans of my watercooler spin a little bit faster. Just joking, minding on the GPU is stupid.

Your Workstation is your main tool for work, yes I call it Workstation, Powerhouse, whatever... If you call it "My PC" and you are not able to run the latest AAA games on it. Buy a new one!

After 35 years of Development here is my list of NO-GOS (in unsorted order):

  1. Use a non-SSD Harddrive or an SSD attached via USB.
  2. Not installed the latest OS
  3. less RAM than 16MB
  4. Screen resolution less than 1920x1080
  5. Only one Monitor.
  6. Not using a VM
  7. Using a non-standard keyboard. (perhaps you can work on a Laptop keyboard I could not)
  8. Not using a Source-Code-Management System (svn, git, mercurial)
  9. Firemonkey App development without my FDK... ;-)
So what are my recommendations you ask?
  1. I would never want to develop without a VM again. So: Use a VM. I like VMware, there are some issues with it but overall it runs perfectly. Using a VM set the bar for a good system a little bit higher! But having auto-snapshots every hour and be able to revert the installation back to a working copy if you have installed something stupid or your installation just broke down is worth it.
  2. Your CPU should have a core-count that is double as high as you would like to have in your windows system. I prefer 4 cores so with hyperthreading you have 8 logical cores in my windows. That's why my CPU has 8 cores with 16 logical cores. 4 for the VM and 4 for the Host. I'm an Intel-Fan-Boy, never tried AMD. My colleague has bought a board with the latest AMD CPU and he has so many problems...
  3. Use 3 Screens. 
    1. Center screen for the IDE. 
    2. Left screen for the undocked the Objectinstpector and structure view. 
    3. Right Screen for the program group and the component palette. 
    4. My Line for breaking up the source line is not at 80 anymore, it's on 160!
    5. While debugging, place your program on the right screen (program group not shown). 
    6. Most of the time when doing boring stuff I put my OI docked at the left side of the IDE on the center screen because I switch my left screen to my Host for watching YouTube videos or other stuff...

  4. If you want the "same speed" inside a VM that you would expect from your main system, Harddisk and RAM performance is the key.
    1. I've installed 64GB of RAM so I can start 3 VM's with 16GB and still have 16GB left for the host system. Or any other combination. 
    2. Perhaps you think: RAM-Speed is not so important. I did not test this and perhaps high-speed RAM has a not-so-big impact on your system. I prefer RAM modules that are recommended by the Mainboard Manufacture and often higher speeds come with a huge impact on the price.  But this looks not so bad compared to the rest of the world.


    3. On the Drive-Side there is no room for low-cost at all! Maximum performance is the key to a smooth-running VM because the VM is often very disk intence.
      1. You get the best performance with an M.2 Drive. If you combine 2 or 4 of these high-speed M.2 to a RAID 0 stripe-set you are pretty close to the maximum speed your bus could handle.
      2. Never ever use your VM on a Harddrive or a single SSD connected to a SATA connector. I had SSD failures in a RAID 10 and this saved my installation.
      3. For Backup I have a RAID 10 of 4 SSD's and a RAID 5 with 3 M.2! Here is the trick: I use the hourly auto-backup of VMWare. That's fine. From time to time I shutdown my VM and copy it (1,6 TB) from a RAID 0 (4 x M.2) to to the RAID 5. This is the best performance I could get. After a few minutes, I can restart my VM and then copy the files for this RAID over USB C 3.1 Gen II to an M2. in a fan-cooled external housing. With this, I get the maximum performance USB could handle. I really would like to have a Thunderbolt connection (should double the speed), but the card I bought was not working and I have no spare slot on my Mainboard. 

  5. I know some people prefer Air-Cooled systems. But I'm using a custom loop for so many years now and the only problem I had once was because my soft tubes are getting old and one fitting was leaking. My System runs quiet, always below 50° C (often below 45° C) and with adding a little bit of water from time to time I had no maintenance to do. (Yes, I just use water, not any colorful additive or even distilled water) That's why I have no little particles clocking up my block. With my last CPU/Mainboard update I installed a new reservoir (the old Plexiglass had got some cracks) and switched to a new pump (just in case). This was the only maintenance in 10 years. 
  6. Install a really good graphics card. Perhaps not so important for VCL developers, but as FMX uses the GPU to render, you'll get the speed you've never seen before with VCL.
  7. For the App development, I'm using a Mac-Mini. Ok, I switched out the hard drive and installed an SSD. (I really should test a macOS-VM sometime). 
  8. And similar to point 9 of my no-gos - use my FDK for your FMX, VCL, and App-Development on the mobile platforms.

Anything else?

hmm... I'm still on D2007 with my main application. (Not finding the time to fix all the Unicode warnings). But the old compiler is also able to compile more than 2. Mio. LOC in under 16 seconds for a full build.
 
Perhaps you call my recommendations overkill, I call it: Best bang for the bug... I spend so many hours at my workstation and I have no time to wait for something to finish. That's why I want the best performance you can buy. (For a reasonable amount of money).

I love the statement about electric cars from the best rally driver of the world Walter Röhl: 
I'm too old and I don't have enough time left to wait at the loading dock. (Translated)

In my case: I'm too old to wait for the compiler. If I currently working in a unit to implement something and I have to take a look into a different unit (normally I have too many open units, often more than 20), it is faster to hit compile and let the compiler find the position I am working on, then to search for the unit or ever do a text-search inside the same unit... ;-)

So - don't complain that something is too slow, beef up your system!

If EMBT tries to speed up the IDE and the compiler at the same time, we will get a faster and faster development environment or at least a constant speed as the possibility grows.

Back to 10.4.2


In my tests 10.4.2 is faster than 10.4.1 and 10.3.3. There is of course an impact now many components you have installed and how long your search path is. Also, there are differences when compiling inside the IDE or using the external compile or MSBuild.

Besides the numbers, the IDE feels snappier and there is a lot less flicker (or nearly/no flicker anymore). There is a little loading screen, popping up when the IDE is loading units. You can disable this, but for the first time you get a notification of what the IDE is doing - I love it.

There is also this new feature of the LSP. You know the old red wriggling lines below errors that were wrong in most cases! With the new settings, you could switch to different lines or dotted lines that also could have different colors. Blue, Yellow, and Red for "not used", "hint" and "error"... My first reaction to this was...

Why on earth did they do this?

But while using this feature for some days - I love it - you can faster correct your mistakes or change a var name because you misspelled it.  This allows you to develop faster, believe me.

Overall it feels better - yes there are still some little bugs in the IDE - we all know, but I can live with the new version!

And as always:
We hope for the next version (10.5) and that the little bug gets fixed!

So long, have fun with the new version.


Friday, February 5, 2021

My road to a useable MVVM Pattern implementation for Delphi!

If you read my blog regularly, the MVVM topic will be nothing new to you.

But please take your time and fill out my new survey, thanks for that, of course, even if you visit my blog for the first time. I would love it if you can also be part of this survey

If you are a first-time-reader... Welcome to my blog. Please read the other posts about my #D.MVVM implementation. As you can see, this subject is not new to me and my knowledge has, of course, improved over the years. (I hope, I'm right with this statement)



Here are the links to my other MVVM-related blog-posts in reverse order:

There was a blogpost from Oct. 2019 with the question: How long does it take to develop a "complete MVVM framework for Delphi. (Link above) the answer is: Not long if you take shortcuts or too long if you are a single developer with no help. But I won't cry, because my goal was not to do it the easy way.

If you do not make it down to the end:
Here is the link to my new survey!
But perhaps you want to know why I've created a new one? ;-) 


Let's collect - one more time - my goals:

  1. The framework must be as fast as possible. (My goal is - it is supposed to be the fastest MVVM framework available for Delphi.)
  2. The development time should not be significantly longer than using the RAD-Approach. At best, the development time should be shorter, comparing to a non MVVM, but not "everything in the Form unit" - development.
  3. Everything that could be done in a background thread should be done in a background thread.
  4. Support for FMX and VCL. Including the "special needs" for the FMX UI.
  5. It must definitely run on ALL platforms.
  6. 100% Unit-Test-able of your Application. (Switch for disabling the background thread to do a better Unit-Testing).
  7. Mockup's for View-Components to test the Binding of your App.
  8. A nice Wizard should be installed into the IDE to create a new VCL or FMX-MVVM Application. This Wizard should be changeable over an Ini-File to make a User-Configuration without recompiling the Wizard-DLL.
  9. One central binding point (Composition.Root) 
  10. If you are an FDK-User (My Firemonkey-Development-Kit) the framework should work streamless as a plugin, with all the benefits of my ORM-Lite, threading, or Client-Server units.
  11. No need for special components. (Components must work without an extension)
  12. Open to User-Implementation for non-standard components.
  13. The View (Form) should not have a single line of code. Or should not need any code-behind...
  14. Visual Livebindings must not be used.
  15. A developer who has NEVER dealt with MVVM has to get along with my framework IMMEDIATELY.
  16. A good developer who has already used MVVM should find his way around immediately. (Except for some things that I have implemented differently than MS).
  17. We are Delphi-Developer - If we are doing MVVM differently than our C# friends - that's fine!
  18. Views must be able to be composed of any number of sub-Views (frames) without writing a single line of code for them. (Sub-Views must be interchangeable for special requirements)
  19. It must also be possible for a sub-View to be a ViewPort3D (FMX-Only). Full support of 3D objects from the ViewModel will be another thing for further investigation. This could be very interesting for Game-Development, but that is completely another topic.
  20. User-Level and flagged Menu-System with auto Action-Binding.
  21. Multiple View for a ViewModel, also with sub-View/ViewModel Binding.
  22. Conventions over definitions.
    1. This is especially true for automatic binding by naming convention. Example: Name: TEdit should auto bind to the fName: TProperty<String> or to a normal property Name: String. The Binding is connected to the Text-Property of the TEdit Component and the OnChange and OnChangeTracking (FMX Only) event should update the ViewModel.
    2. User-defined naming convention... Bind Name:TEdit to fEdNameField : TProperty<String>
    3. Global naming rules and also naming rules by TypeInfo.
    4. Overwrite any predefined rule with an attribute.
  23. Multi-Binding to different properties.
    1. Example: Save: TButton.OnClick -> Procedure DoSave
    2. Save :TButton.Enabled -> fCanSave : TProperty<boolean> or Property CanSave : boolean
    3. Fone : TCombobox.Items -> fFoneItems : TListProperty<String>.
    4. Also user-defined naming: "Can"+Save;"Do"+Save could be changed to: e.G.: -> "CheckFor"+Save;"Execute"+Save.
  24. Optimal performance on ".Strings";".Items";".Lines" - never ever send the complete list on a single change. A virtual created adapter must take care of the updates. (e.G. for a single changed line in a Memo of 10.000 lines it is a nogo to update the Text-Property of the Memo.)
  25. Data-Verification on Property-Level to check the fields inside the ViewModel.
  26. Listview and Listbox special treatment for FMX.
  27. A data model for VCL Grids - The FMX Grid already has a data model.
  28. A not so easy implementation of an MVVM-Treeview. (Perhaps not in the Beta)
  29. Complete logging of all internal functions should be possible. (Only for the Plugin Version)
  30. Error messages that are normally written in English must be able to be translated by an external language file.

The MVVM-Pattern has the Model included in the Pattern-Naming, but actually, the Model is not really a part of the Pattern. But in my case:

  1. Only if the Framework supports the transfer of all the collected data from the ViewModel to the Model, my goal of: "As fast as RAD Development" is possible. 
  2. The Framework must have a Datacontext that can make the transfer from the ViewModel to the Model, and back.
  3. The Datacontext should be able to convert, combine and separate fields as they are transferred back and forth.
  4. The Model should directly work as an ORM or REST-full Web interface. 
  5. As an FDK-Plugin it should also work with my Client-Server-REST-Units.

So far so good...

There is light at the end of the development tunnel! I'm really happy with the actual implementation. I think I have done all the necessary improvements for the first version. and - as always - I would have programmed the framework even if I wasn't planning to offer it commercially. Of course, programming is a bit different when the source code is handed over to other developers. Certainly, I could have made a lot of things more static or simpler.

And now?

There will be a Beta-Version and an Early-Bird-Order! But maybe this time I should do an Alpha -Version too - if I can find developers interested in helping me finish the release version.

But how and why?

After years of development - only in my spare time, of course - perhaps I've done something wrong, perhaps I should rename a method or change params of a function. Whatever... I don't want to make breaking changes from Beta to Release.

I know - some of you - are waiting for the release of my Framework, but besides the old survey, I don't know how many Developers would still like to be part of the Alpha or Beta-Team. (or even would like to buy my #D.MVVM-Framework). (Old survey filled by 177 Users).
I've talked to some of these developers and they can't wait to get started with my framework. (I'm super happy to hear that, of course).

A comment in advance from René Höger:
"Is a lot of information! Those who have dealt with this, I think will be hot on it! I don't know what your feedback is so far, but I think this could be a milestone. When I think of all my old applications! But maybe I am biased because I have already received an introduction into your framework!" 

💖 Thanx René!

Perhaps I need to write some kind of NDA contract (never done before). One thing I want to avoid, after all these hours, is to find my Source-Code as a zip on a hacker site.

Before I could start the Alpha-Phase, I have to:
  1. Open up a ticket system or some kind of bulletin board?
  2. Perhaps a discord server?
  3. Perhaps a slack group?
  4. Think about how to collect User-contributions...
  5. Think about contribution benefits?
  6. Late or discount payment for Alpha & Beta users? 
How do I distinguish between a developer who "just" wants to see cool source code and a developer who wants to actively contribute to the framework? Maybe I should just assume the best and trust that Delphi developers are all super nice people who are interested in using this technology. I think I'll stick with that idea or a very little "fee" just to check if the developer really wants it? Perhaps some kind of reward system?

If you've made it down here - Thanx for reading and please be so kind and fill out my survey!