SOLID Principles in Delphi [2] – The Open/Closed principle

The second principle of SOLID is the Open/Closed principle: ‘Classes and other entities should be open for extension but closed for modification’. This article is about how in Delphi you keep a class closed for modification, but open for extension.

Let me emphasise one part; achieving this goal via inheritance or overriding classes is a bad idea in my opinion. If you want to read more about this, check out what Bertrand Mayer and Robert C. Martin have to say on this subject.

Okay, let’s take the following example:

type
  TShip = class
    // This is the actual ship
  end;

  TPartList = class
    // This class holds all the needed parts for building a ship
  end;

  TShipLayout = class
    // This class provides the blueprint of the ship to build
    function GetBlueprint: TList<TPoint>; // just as an example
  end;

  // This is the factory class to build a ship
  TShipBuilder = class
  private
    FParts: TPartList;
    FShipLayout: TShipLayout;
  public
    procedure LoadParts(APartList: TPartList);
    procedure LoadShipLayout(ALayout: TShipLayout);

    function BuildShip: TShip;
  end;

As you can see, these are simple classes, without interfaces and without the possibility to extend them easily. The ShipBuilder class is however already (partly) closed for modification; the internal operation is separated from the outside world because the local variables are made private. In Delphi however, you can still access these variables when you access this class from the same file. Therefore, a simple improvement is to make the private a strict private.

However, the inner workings of this class itself is still open for modification. One can easily call on the BuildShip function before even providing the necessary parts and ship layout.

But how do we ensure that these classes are open for extension, but remain closed for modification?

The answer? Interfaces!

Why interfaces? This has to do with another principle: program against interfaces and not against implementations. The example above is the implementation of the class TShipBuilder. As soon as you start working with this implementation, you are automatically ‘stuck’ with the TPartList and TShipLayout implementations as well. Let’s see how we can improve this. The first step is to create several interfaces and modify the TShipBuilder class to implement those new interfaces. The second step is to use dependency injection to open this class for extension, but close it for modification. If you do that, you will end up with something like this:

type
  TShip = class
    // This is the actual ship class
  end;

  IPartList = interface
    // Necessary info to provide the parts
  end;

  TPartList = class(TInterfacedObject, IPartList)
    // This class holds all the needed parts for building a ship
  end;

  IShipLayout = interface
    // Necessary info to provide the blueprint
    function GetBlueprint: TList<TPoint>;
  end;

  TShipLayout = class(TInterfacedObject, IShipLayout)
    // This class implements the blueprint function of the ship to build
    function GetBlueprint: TList<TPoint>;
  end;

  TShipBuilder = class
  strict private
    FParts: IPartList;
    FShipLayout: IShipLayout;
    procedure LoadParts;
    procedure LoadShipLayout;
  public
    constructor Create(APartList: IPartList; ALayout: IShipLayout);
    function BuildShip: TShip;
  end;

So, what exactly did we do? As you can see, we now have a TShipBuilder class which requires the two interfaces via a constructor. Both the LoadParts and LoadShipLayout procedures are made strict private, which ensures that the class is closed for modification, so we use these procedures only within the BuildShip function for example.

Additionally, our class is open for extension. It is possible to extend this ShipLayout functionality for example by just creating another implementation of the IShipLayout interface, as long as we implement the GetBlueprint function. We just have to make sure that we will provide a class with the IShipLayout interface implemented when calling the constructor of the TShipBuilder class.

As with most examples I’ve showed earlier, be aware that you shouldn’t put both the interfaces and classes all in the same file. It’s just for the sake of readability that these are in one place right now.

So, to summarise: to use the Open/Closed principle in Delphi you need interfaces to make a class open for extensions and make use of the (strict) private keyword to keep the class from modifications. Use as little inheritance as possible, because with inheritance, you risk opening the class for modifications. And remember: always program against interfaces instead of implementations.

Become a GDK Delphi hero! Subcribe here to our Delphi mailing list!

SOLID Principles in Delphi [1] – The Single Responsibility Principle

Single Responsibility Principle

Today, we’ll dive into the S of the Solid principles: The Single Responsibility Principle. But before we start, just a quick refresher on Solid.

SOLID is an acronym for a set of five software development principles, which if followed, are intended to help developers create flexible and clean code. The five principles are:

The Single Responsibility Principle — Classes should have a single responsibility and thus only a single reason to change.

The Open/Closed Principle — Classes and other entities should be open for extension but closed for modification.

The Liskov Substitution Principle — Objects should be replaceable by their subtypes.

The Interface Segregation Principle — Clients should not be forced to depend upon interfaces that they do not use.

The Dependency Inversion Principle — Depend on abstractions rather than concretions.


So, the single responsibility principle. As the name suggests, each class in a program must have a single responsibility for only one part of the program’s functionality. But that seems easier than it is. What exactly is a one part of a program, and how to know when to separate functionality? It’s too simple to say that a class should only do one thing.

Robert C. Martin expresses the principle as ‘Gather together the things that change for the same reasons. Separate those things that change for different reasons’, and more recently ‘This principle is about people’. That should point us into the right direction.

When you write a software module, you want to make sure that when changes are requested, those changes can only originate from a single person, or a single tightly coupled group of people representing a single narrowly defined business function. This means that a software module or class should have one responsibility for that particular group of people.

It is easier to explain this by means of an example. Let’s take a look at this following class:

type
  TShip = class
  private
    FPosition: TPoint;
    FHeading: Integer;
    FSpeed: Integer;
    FCargoLoad: string;
  public
    procedure SetHeading(NewHeading: Integer);
    procedure SetSpeed(NewSpeed: Integer);
    function GetCoordinate: TPoint;
    procedure PlotCourse;
    procedure LoadCargo(NewCargo: string);
    procedure PrintCargo;
    procedure ReportPosition;
    procedure CalculateProfit;
  end;

This is a class that is doing a couple of things, all about managing a ship’s position and course, its load and some reporting things. As this is a brief example to show how to think about the Single Responsibility Principle, don’t pay too much attention to the details of the code itself; it is all about the large overview of the structure of this particular class.

I think we all know these kind of ‘God’ classes. Usually packed with lots of functionality and code, and managing one particular part or module of your program. The question is, if we need to make some changes to this class, how can we refactor this class to make sure we gather together the things that change for the same reason, and separate those things that change for different reasons.

Let’s stop for a moment and think about responsibilities of this code regarding to the (group of) people. We can define a couple of specific people that will have some responsibility regarding the ship’s management, direction and heading, and reporting tools. So let’s say in this case we define a skipper, a navigator, a cargo load master and a financial manager. If you think of these different roles, it’s suddenly very easy to separate this class into different modules, with just one responsibility to that particular role. We should have a class for setting the heading and power (skipper), one for managing position and plotting the course of the ship (navigator), one for managing the load of this ship (cargo load master), and one for all our (financial) reporting (financial manager).

Our new classes might now look like this:

type
  TShipLocation = class
  private
    FPosition: TPoint;
  public
    function GetCoordinate: TPoint;
    procedure PlotCourse;
    procedure ReportPosition;
  end;

  TShipMovement = class
  private
    FHeading: Integer;
    FSpeed: Integer;
  public
    procedure SetHeading(NewHeading: Integer);
    procedure SetSpeed(NewSpeed: Integer);
  end;

  TCargo = class
  private
    FCargoLoad: string;
  public
    procedure LoadCargo(NewCargo: string);
    procedure PrintCargo;
  end;

  TShipReport = class
  public
    procedure CalculateProfit;
  end;

  TShip = class
  private
  public
    // reference to subclasses
  end;

Would you have done the same if you didn’t think of the people behind the class’s responsibilities? Maybe, but I can imagine the ShipLocation and ShipMovement class could have ended up in the same class.

So, what happens now if we got a feature request from the skipper to add a bow thruster to make it easier to steer the ship in small canals? Just make this change in the ShipMovement class, without affecting any of the other classes. And if we want to implement a new cargo load system? Just alter the Cargo class, again without touching any of the other classes.

I hope by now you see why the single responsibility principle is really about people, or actors, and the responsibility of the functionality of modules or classes of your program in relation to these people. And of course, you can apply this on different levels of your program, from modules to classes to specific functions.

If you always have this principle in mind when refactoring or designing a module or class, I’m sure your code will be better maintainable and is easy to change.

Dependency Injection in Delphi

Always wanted to know how to use Dependency Injection with Delphi? I’ve set up an example for you in which we go from strongly coupled code to beautiful, uncoupled code in a few steps via Dependency Injection and with the help of interfaces.

We’ll start with the following example:

unit DI1;

interface

type
  TLanguageTools = class
  private
    procedure CheckGrammar;
    procedure Translate;
  end;

  TWordApp = class
  private
    FTranslator: TLanguageTools;
  public
    constructor Create;
  end;


implementation

constructor TWordApp.Create;
begin
  FTranslator := TLanguageTools.Create;

  FTranslator.Translate;
end;

{ TLanguageTools }

procedure TLanguageTools.CheckGrammar;
begin
  //
end;

procedure TLanguageTools.Translate;
begin
  //
end;

end.

As you can see, there is nothing wrong with the code in principle. It is valid Delphi code and it works. However, there are a few remarks to be made. First of all, the code is strongly coupled; the TWordApp class not only depends on the TLanguageTools class, but you cannot even extend the TLanguageTools class with extra functionality. Even if you would override the TLanguageTools class with, for example, TEnglishLanguageTools, TWordApp simply uses the base class TLanguageTools.

We can do better than that! A first major improvement is to remove the dependency from the constructor Create, and inject it. Injecting a dependency can be done in several ways, via properties, procedures or constructors. In this example, I use the constructor. The code below already has a slightly looser dependency between the two classes:

unit DI2;

interface

type
  TLanguageTools = class
  private
    procedure CheckGrammar;
    procedure Translate;
  end;

  TWordApp = class
  private
    FTranslator: TLanguageTools;
  public
    constructor Create(ATranslator: TLanguageTools);
  end;


implementation

constructor TWordApp.Create(ATranslator: TLanguageTools);
begin
  FTranslator := ATranslator;

  FTranslator.Translate;
end;


{ TLanguageTools }

procedure TLanguageTools.CheckGrammar;
begin
  //
end;

procedure TLanguageTools.Translate;
begin
  //
end;

end.

As you can see in the example, we are still using the TLanguageTools class. However, it is now possible to override this TLanguageTools class, and give this new class to the TWordApp class. And actually, this is the basis of Dependency Injection. Your code is much more loosely coupled and reusable.

By using interfaces, we can go one step further. It is possible to describe the functionality of the TLanguageTools class in different interfaces, and pass this on to the TWordApp class. In this way, we program against abstractions, and not against implementations.

unit DI3;

interface

type
  IGrammarChecker = interface
    ['{FED7BA76-0EDE-40E7-BABB-16BCFE76F6DF}']
    procedure CheckGrammar;
  end;

  ITranslator = interface
    ['{C1F1092F-3589-49E5-8F22-33E8D7587A8B}']
    procedure Translate;
  end;


  TLanguageTools = class(TInterfacedObject, IGrammarChecker, ITranslator)
  private
    procedure CheckGrammar;
    procedure Translate;
  end;

  TWordApp = class
  private
    FTranslator: ITranslator;
  public
    constructor Create(ATranslator: ITranslator);
  end;

implementation

constructor TWordApp.Create(ATranslator: ITranslator);
begin
  FTranslator := ATranslator;

  FTranslator.Translate;
end;

procedure TLanguageTools.CheckGrammar;
begin
  //
end;

procedure TLanguageTools.Translate;
begin
  //
end;

end.

As you can see, the TWordApp class is no longer at all dependent on the TLanguageTools class. As long as we pass on to the constructor an instance with an implementation of the ITranslator interface, the code will just work. We don’t even need the TLanguageTools class anymore.

So, with the help of Dependency Injection and with interfaces, we get nice, decoupled, and well-maintained sourcecode.

All the Delphi books you need to improve your programming skills

As a developer, you can always improve yourself, acquire skills, learn to program better. This can be done simply by programming more (and thus learning from the mistakes you make), but if you really want to get a push, you can best make use of the knowledge of others. That’s why at GDK Software we have a policy that you can always buy books at the expense of the company. You’ll earn this investment back in no time.

At GDK Software we work with both Delphi and Mendix. For the Delphi developers among us, I have listed some good books to expand your (Delphi) knowledge.

I’m sure you can pick something up from the next list of books. Most are aimed specifically at Delphi programmers, but I added two books that are generally very useful to read.

We start with the ‘base’, if you don’t know much about Delphi or Pascal this one is highly recommended.

Object Pascal Handbook by Marco Cantu

Marco Cantu is the best-selling Delphi books author and Delphi Senior Product Manager. He has already written many books about Delphi, but with this updated version you have a complete manual of all the ins-and-outs of the programming language Object Pascal. Highly recommended if you want to start programming in Delphi. The book covers the basics, from elementary console applications to complex code structures.

And as a bonus, Marco added “The Evolution of Object Pascal” in the appendix as well.

Coding in Delphi and More Coding in Delphi by Nick Hodges

To describe these books it is best to give the floor to the author himself:

“The one thing that I notice is that there are a lot more of you Delphi guys than the average Delphi guy thinks. There are Delphi folks everywhere. Also, I have noticed that a lot of Delphi developers are “behind”. That is, they are either using an older version of Delphi, or they aren’t using or aren’t even aware of all the features in the newer versions of Delphi that they are using. If the above is familiar, this book is for you: The Delphi developer that hasn’t quite yet made the leap over into the cool and amazing things that you can do with the latest versions of the Delphi language.”

Need I say more?

https://leanpub.com/codingindelphi and
https://leanpub.com/morecodingindelphi

Delphi Cookbook by Daniele Teti

This book aims to help professional Delphi developers in their day-to-day jobs and consists of about 50 Delphi programming recipes. The book covers topics such as manipulation JSON, anonymous methods, multithreading and Firemonkey stuff. Including the code recipes found at https://github.com/PacktPublishing/Delphi-Cookbook-Third-Edition it’s useful to have a look at the examples.

https://www.packtpub.com/application-development/delphi-cookbook-third-edition

Dependency Injection by Nick Hodges

This book covers Dependency Injection from A to Z. In it, you’ll learn about Constructor Injection, Property Injection, and Method Injection. You’ll learn about the right and wrong way to use the Dependency Injection Container.

And why do you need Dependency Injection? Just read the book and you know why!

https://leanpub.com/dependencyinjectionindelphi

Expert Delphi by Paweł Głowacki

This book by Paweł (who sadly passed away in 2017) focusses on mobile development with Delphi. Although the book is several years old, it is still valuable to read if you want to get started with mobile applications. Via Packtpub you can read the book for free as well:

https://www.packtpub.com/free-ebooks/application-development/expert-delphi/9781786460165

Delphi in Depth: FireDAC by Cary Jensen

If you work a lot with databases (and who doesn’t) then this book is for you. The book describes how to get optimal performance from your database and the connection to databases, how to work with cached updates, FireDAC scalar functions and so on.

https://sites.fastspring.com/jensendatasystems/product/delphiindepthfiredac

And finally, two books I really appreciate. Both are not specific to Delphi but are very useful and fun to read.

Clean code by Robert C. Martin

The subtitle of this book is “A Handbook of Agile Software Craftsmanship”. A book every software developer should have read.
“Even bad code can work. But if code isn’t clean, it can bring a development team to its knees. Every year, countless hours and considerable resources are lost because of poorly written code. But it doesn’t have to be.” Recommended reading!

https://www.oreilly.com/library/view/clean-code/9780136083238/ and https://cleancoders.com/

Code: The Hidden Language of Computer Hardware and Software by Charles Petzold

Not a hands-on book as such, but a great book to clarify exactly how your code is executed ‘underwater’. Starting with the working of a telegraph pole, a complete working computer is thought out on paper. Very interesting to read, with appealing examples.

https://www.barnesandnoble.com/w/code-charles-petzold/1100324884

Delphi projects: Some stats about the top 1000 projects on GitHub


Photo by Carlos Muza on Unsplash

Last week, I analysed the top 1000 Delphi projects on GitHub, mainly out of curiosity, and also to play with another programming language (Python). I took Delphi projects because we at GDK Software have many customers with this programming language.

To be able to do the analysis, I did the following steps:

  1. Using the GitHub API, I created a list of Delphi projects (sorted by the number of stars).
  2. I cloned every Delphi repository to my environment.
  3. Then I analysed the source code. I mainly looked at some interesting statistics that I could get out of the code in this way.

Below is the entire list of repositories added, sorted by the number of stars on GitHub. I’ve removed some projects from the list because they weren’t Delphi projects, or (in the case of “awesome-pascal”) because it is just an overview of frequently used Delphi projects.

Top 10 Delphi projects on GitHub
Top 10 Delphi projects on GitHub, sorted on Github stars

If we make a selection of the repositories with the most lines of code, it looks very different (repositories with at least 10 stars):

Lines of code

To show some interesting conclusions; of the 1000 Delphi projects, there are no less than 240 where empty “except…finally” constructions occur. Also, 291 projects use Generics and 217 use the Firemonkey framework.

There are quite a few of these public projects that are not afraid of long functions or procedures. The largest procedure I could find consists of more than 2939 lines (project MCH_Delphi_Software).

As for the largest Pascal files, see below. If you want to view the Delphi files yourself, just search Github for the corresponding filename. Or, see below how you can clone the Delphi repositories.

In the next weeks, I’ll share some more stats. If there’s anything you’d like to see, feel free to reply and ask! 🙂


Download here the CSV file with the complete list of repositories.

If you want to download the repositories yourself, go for it! Make sure you first install the Python libraries pygit2 and Github

pip install PyGithub
pip install pygit2

https://gist.github.com/cmgeuze/d624c86bc7d9930cd4c26ba58ec62445

Delphi package managers

Photo by Leone Venter on Unsplash

The absence of a good package manager in Delphi is, after 25 years, still a big problem. There are a lot of excellent third party components and libraries available for Delphi. It is what makes the development in Delphi so easy.

Unfortunately it also causes a problem with new installations, or when taking over a project from someone else. If you don’t have the right libraries and components installed you have a problem. Wouldn’t it be great to have a package manager -as available for many other languages and platforms- to resolve this automatically? If you are familiar with tools such as npm (Node package manager) you undoubtedly know how useful a good working package manager can be.


There have been quite some initiatives in recent years to create a package manager for Delphi. We have the GetIt package manager shipped with Delphi itself, and a number of projects such as delphipm, delphinus, boss and MultiInstaller. Unfortunately, this comic also applies here:

Comic about standards
https://xkcd.com/927/

Although all these initiatives are great in principle, it does immediately expose the underlying problem; there is no clear vision from Embarcadero on incorporating the open source community into the Delphi eco-system. These community initiatives arose because there is a need to easily manage packages in Delphi. So instead of developing the GetIt package manager internally, it would have been much better to make GetIt an open source project and to invest heavily in its development. The idea behind the GetIt package manager and all other initiatives are great. But without a clear vision and one central hub of packages and libraries, the development of package managers remains fragmented and inconvenient to use.

Therefore, Embarcadero; Make use of the Delphi community, please don’t be too afraid to use open source projects and clearly communicate the long-term vision of the GetIt package manager. In the end, every Delphi developer is served by this, and it will spread the use of Delphi.

Upgrading Delphi software, the smart way

#Delphi25th

This year (2020) Delphi celebrates its 25th anniversary. In those 25 years an enormous amount of code has been written. Many of these applications are still in full use by companies and individuals. This shows the power of Delphi; code written decades ago still works, even in the latest Delphi versions.

Still, there are some remarks to be made about this praise. Unfortunately we see that there are also many applications that are still being developed in old Delphi versions. That is a pity, because the new versions of Delphi really have a lot of advantages. Not only is the IDE much more pleasant to use, the new language enhancements are a real improvement.

There are a number of recurring problems when converting older Delphi applications to the latest Delphi version. For example, as of Delphi 2009 you have to take Unicode into account. In addition, there may be components that are no longer being developed, or that have been significantly modified. This means that there are still companies working with Delphi 5, Delphi 7 or some other old versions. Now, converting your source code is not always easy. At GDK Software we have had many projects and customers who came to us with older Delphi software. Because we often come across the same issues, we have developed a tool that makes conversion much easier; the GDK Compiler Helper. In this post I will briefly explain how the GDK Compiler Helper assists us with the conversion projects, and how GDK Software can also help you with the upgrade of your Delphi project.


GDK Compiler Helper

The GDK Compiler Helper uses the Delphi compiler to automatically compile programs, search for errors and modify code to fix these errors. Because all changes are carried out via actions, you can just grab the latest codebase and restart the conversion every time. During the development of the GDK Compiler Helper we have always had in mind to automate the conversion as much as possible.

I will start with a brief introduction to the mechanics of the GDK Compiler Helper. After that I will give some examples of the different actions the tool can perform.

Pre-compilation

We perform a number of steps automatically before starting the compilation process. First we do a pre-compile action on all source code. This consists of the following actions:

  1. Convert all form files (.dfm files) to text files
  2. Perform all pre-process actions that are defined

To start with the first point; with Delphi it is possible to save form files as binary files. Since it is possible to replace components with the compiler helper, the form files must be saved as readable text files.

Then we perform all pre-process actions. Suppose we know that in every pascal file certain modifications have to be made, we can specify these in the action list. The compiler helper will first perform these actions on all source code, before starting the actual compilation.

Compilation

Then we use the Delphi compiler to compile the project and fix errors.

Demo compiler helper

For the purpose of fixing errors, warnings and hints, we have created a database of actions, which the compiler helper uses to automatically perform code changes and recompiles the source code. An action can consist of:

  • Add a unit to the uses
  • Remove or rename units
  • Modify the code by using a simple replace
  • Modify the code using Regular Expressions
  • Add a prefix to an identifier or variable
  • Change the type of a variable
  • Replace a (design time) component
  • Replace all code by running a replace or Regular Expressions over the pascal file.

Examples of actions

Because we have performed many conversions at GDK software, we have compiled quite an extensive list of these actions. Through the GDK Compiler Helper we can easily add and edit these actions:

Edit form actions

Some examples of compiler errors and the corresponding actions are:

error E2003: Undeclared identifier: 'CurrencyString'

The solution is the action AddPrefixToIdentifier and the prefix or solution is FormatSetting.. Here the GDK Compiler Helper automatically updates the code to FormatSettings.CurrencyString. Likewise for the following errors:

error E2003: Undeclared identifier: 'CurrencyFormat'
error E2003: Undeclared identifier: 'CurrencyDecimals'
error E2003: Undeclared identifier: 'DateSeparator'
error E2003: Undeclared identifier: 'TimeSeparator'
[...and so on]

Another example:

error E2003: Undeclared identifier: 'VarArrayOf'

In this case a unit must be added to the uses class. This is done by using the action AddUnitToInterface where the unit System.Variantsis added.

An example of a more complex action is the solution to the following problem:

error E1050: WideChar reduced to byte char in set expressions.  Consider using 'CharInSet' function in 'SysUtils' unit.

In this example, we have identified the Delphi warnings to show as errors. The solution to this problem is the ReplaceByRegEx action. For a replace action (both the regular action and the Regular Expressions action) we need to specify two parameters; the search string, and the result. In this particular case, the search string was a rather complex Regular Expressions function

([\w\^]+[[]?[\w\+\.\-\s]+[]]?)\s+[Ii][Nn]\s+([a-zA-Z0-9[\s]*[Cc][Hh][Rr][(][\d]+[)]*[a-zA-Z0-9'?,\s(\]]*[Cc][Hh][Rr][(][\d]+[)]*[]\)]?)

and the result

CharInSet(\1, \2)

The Compiler Helper will apply this solution to the specific line of code, after which the compilation process will continue with the rest of the source code.

Adding actions

While working on a conversion, you obviously want to add new actions as easily as possible. Although the GDK Compiler Helper can solve quite a lot of things automatically, there are always specific problems that need to be solved for a project. That’s why you can easily add your own solutions and actions.

As an illustration I will show an example of a part of the conversion of the (open source) MPEG Audio Collection Library. One of the Delphi projects gives the following error message:

error E2003: Undeclared identifier: 'ReadLn'

The corresponding code line is

Str := TCP.ReadLn;

By analyzing the source code I know that the ReadLn function of the Indy Libraries is now in unit TCP.IOHandler instead of in the unit TCP. So we need the action ReplaceIdentifier and replace TCP. with TCP.IOHandler. Adding this action is now very easy:

Adding actions

The main advantage of modifying your source code in this way is that it is transferrable. If this specific code occurs again somewhere else, the GDK Compiler Helper will automatically apply this solution there and continue compiling.


As you have seen it is incredibly easy to update existing Delphi projects to the latest Delphi version with the GDK Compiler Helper. You can also continue the existing development for the old version of the software during the conversion project. Because all changes are stored in actions you can just grab the latest codebase and restart the conversion every time.

How we can help

At GDK Software we want to share our knowledge with other developers, and we want to help companies to get and keep their Delphi software up to date. Therefore we have interesting options to use the GDK Compiler Helper for your software project as well.

Are you interested in a personal demo of the GDK Compiler Helper, or are you looking for help converting a Delphi project? Please contact me via info@gdksoftware.co.uk, or via our website GDK Software.

Thanks for reading!

Delphi tips and tricks

At GDK Software we have been working with Delphi for years. We have collected quite a few tricks and tips, which I would like to share with you. I have organized Delphi’s tips and tricks into the following topics:

  • Delphi plugins
  • Delphi IDE Shortcuts
  • Live Templates (or Code templates)
  • Various useful links

Enjoy!


Delphi plugins

As a Delphi developer, you are working with the Delphi IDE on a daily basis. And although the Delphi editor works fine by itself, with the following plugins you can make your work even easier:

Grep search dialog

GExperts adds some very useful features to Delphi, such as Grep search Alt + Shift + S, Procedure List Ctrl + G, Rename Components and other very handy shortcuts (see the shortcut section for more).

We love DDevExtensions for the Find Unit/Use Unit replacement dialog (Alt + F11). The default Delphi Use-Unit dialog only shows the files from the project group. DDevExtensions replaces the dialog with one that not only shows the project group files but also all files that the compiler can see. Never again navigate to the uses section and insert a unit by hand, just hit Alt-F11.
DDevExtensions also prevents the IDE from storing the ExplicitWidth and ExplicitHeight properties to the DFM.

The IDE Fix pack optimizations let the IDE start faster, open projects faster, optimizes the compiler’s file search algorithm, makes CodeInsight, the actual compilation and the debugger faster.

Parnassus Bookmarks replaces the IDE’s inbuilt functionality with new, improved navigation. Bookmarks are saved so that after a restart the bookmarks are still available. Installation can be done via the GetIt package manager.


Delphi IDE Shortcuts

IDE Shortcuts are the easiest way to speed up development. Most of us undoubtedly know the most important shortcuts in Delphi, but let’s share which ones we use regularly.

(Here you can find all the Delphi shortcuts)

The following shortcuts will be speed up your coding a lot:

  • Bookmarks: Save the points in code where you want to come back. Navigate easily through code. Set a bookmark with Ctrl + Shift + <Number> and use it with Ctrl + <Number>.
  • Jump between the methods interface and implementation with Ctrl + Shift + Arrow upor Ctrl + Shift + Arrow down.
  • Install and use the Grep Search from GExperts. Searching faster and representing the results in a better view than the Delphi IDE via Alt + Shift + S.
  • (GExperts) Search and go to a method with Ctrl + G
  • Use Alt + F11 to add a unit to your code (use with DDevExtensions).
  • Use a clipboard manager to copy several things without continuously swapping between copy/paste, copy/paste, etc. We prefer CLCL for clipboard history, you can easily use it by pressing Alt + C. Despite this not being a specific Delphi suggestion, I still want to share this. If you only want to use one of these tips, let it be this one.

Other popular shortcuts are:

  • The obvious ones 🙂
    Save: Ctrl + Sand save all: Ctrl + Shift + S
    Run: F9, compile: Ctrl + F9 and build: Shift + F9
    Stop run / debug: Ctrl + F2
  • Add a file to the project: Shift + F11
  • Complete a class: Ctrl + Shift + C(i.e. create the methods in the implementation section)
  • Declare a variable: Ctrl + Shift + V(type your statement, place cursor on variable and press the shortcut)
  • Declare a class variable: Ctrl + Shift + D (same as V, but instead of the local variable you’ll end up with a class variable)
  • Rename a variable: Ctrl + Shift + E
  • Go to unit: Ctrl + Enter(when your cursor is on a unit name). Faster than Ctrl + click , but only works if Delphi can locate the unit
  • Align your codelines with Ctrl + Alt + Z (GExperts)
  • Refactor code to new procedure: Ctrl + Shift + M
  • Synchronize procedure or function parameters: Ctrl + Alt + Shift + P

Live Templates

Live Templates (or Code templates, as they were formerly called) are a very useful feature of Delphi. Since Delphi 3 these templates are present in Delphi, but we still see that this handy feature is undervalued. Most developers are familiar with the code completing of if or while, where the structure of the statement is created automatically.

But with Live Templates you can automate much more. If you want to see a list of the available Live Templates, you can use the shortcut Ctrl + J.

Ctrl + J Live Templates

The more you can automate, the better it is. That’s why it is recommended to create your own live templates for frequently used code within your program. This can easily be done via File -> New -> Other -> Code Template. For more information about the structure of the templates, you can find more information on the wiki of Embarcadero.

Useful links

Delphi has been around for more than 25 years now. It is therefore impossible to put all possible tips and websites on this page. Below I will list some links to frameworks, tools or code libraries that we at GDK Software regularly use.

Inno setup for Delphi packages

As a Delphi developer, you’ve probably used Delphi packages before. Maybe you have also written your own packages. To simplify installation, we use our own Inno Setup script at GDK Software for the installation of these packages. This allows us to build and install Delphi packages via a setup tool, instead of building the packages ourselves. The biggest benefit is the ease of installation; you don’t have to specify the search paths and compile and install the packages yourself.

Below is a short explanation of the script. If you want to get started you can head directly to the Git repository and download the script.

Features:

  • Install, build and register Delphi packages
  • Support for win32 Delphi versions from Delphi 7 to Delphi 10.3 Rio
  • Detect installed Delphi versions, including non-default installation folders
Inno setup Delphi
Example setup for installed Delphi versions

To use the script you first need to clone the Git repository, or download the two required files (CompileSource.bat and Setup script.iss).

The next step is to configure the Inno Setup script so that the necessary Delphi files are added to the installer. To do that, add all the Delphi files (including the .dpk and.dproj) to the [Files] section of the script. The destination directory of all the source files must be in a subfolder of \Sourcecode\Package\.

Sample dpk and dproj

Make sure you also change the defines:

After you have changed these lines, it is possible to compile and test the script. The Inno Setup script uses the CompileSource.bat batch file to actually compile the specified package using MSBuild.exe. To debug or test the installation, change the last line of batch file from “rem pause” to “pause”.


Thanks to John Kouraklis for the first version of the script. You can find the original post and version here.