VCL Project Maintainability

I am a hobbyist using Delphi for a Membership DB
I understand it is useful to keep the user interface form separate from the datamodule. Over the recent years I have learnt to use DataSnap, REST, Frames and Classes. I have very little source code in classes.

Should I try to increase source code in classes?
Would it make the source code more maintainable?

I bought a book on breaking code into logical parts but it was too detailed and complicated for my liking. I also have experimented with dUnit testing but do not use it.

What was the book Erick ?

Robert

MVVM by John Kouraklis. Sounded good in theory. I don’t even have it anymore.

I have adopted a MVVM light architecture for my code. By light I mean that I haven’t implemented events for communicating between the different parts of the system.

Basically I use

  • View is generally a frame, which has no business knowledge
  • View model may contain data base access routines directly, or may use callbacks to get database information from another unit. This might be lists of values for combo boxes or actual data operations
  • Model contains the data and some business knowledge

These are used by a main form which is generally has a database object and responds to view, save, delete buttons. It manually sets data in the model and then calls the view to refresh.

It probably isn’t a standard way of doing things but it suits the application I have been writing.

My initial inspiration was a blog of @Malcolm . I think it might be his Menial Tasks project on github.

1 Like

For me there’s a lot to like about approaches like MVVM, MVC, MVP, etc, but sometimes you can get stuck on the purity and lose sight of getting something built.

Sue’s approach sounds very sensible to me. Without putting words in her mouth, to me it says: take the concepts from it that give some of the benefits you want (maintainability, testability, etc), but stay pragmatic to avoid throwing away the benefits of RAD.

Might make the book authors shudder, but if I’m getting value and getting work done, then I’ll sleep at night.

1 Like

@Eric_March if you are not using classes for your own code then you are missing out on a lot of the functionality of delphi.

I was going to suggest Nick Hodges Coding in Delphi but if you are not even using classes then this might be jumping ahead too far.

Refactoring code into classes is doable

  1. identify any common attributes or state
  2. identify any functions/procedures that operate on that state

The attributes being variables like

  FBookTitle: string;
  FBookAuthor : string;

state

  FPublished : boolean;

It might be good to take a refresher on object oriented programming (oop) - something like this to cover the basics - Learn Delphi Programming | Unit 5.4 | Understanding Classes and Objects - YouTube

I’m not sure which alphabet soups apply to my projects - they have evolved over time through many rounds of refactoring as I learned my craft.

There was a topic on delphipraxis a while back - “As a Delphi expert, do you ever need to refactor or improve your code?”

My reply was

I’ve been using Delphi for 25 years, I’m working on a 20 year old code base, I’ll let you know when I’m done refactoring!

I haven’t reached that point yet.

I use interfaces a lot - and I use messaging a lot too. I started with those a long time before I had ever heard of MVVM or MVC or XYZ.

I think people get too hung up on application architecture - if I were to look back on my code when I first started on FinalBuilder I know I would cringe :woozy_face:

1 Like

From your description I’m going to assume you’ve got a VCL application that is in the traditional Delphi RAD style using dataaware controls, with quite a bit of code in the actual forms themselves and probably a single datamodule. My apologies if these assumptions are not correct.

Reworking that sort of application to something like MVVM, MVP, MVC is not going to be easy. It’s more than likely a complete rewrite which you probably don’t want to do.

Assuming a complete rewrite is off the cards my advice would be incrementally improve your existing application from being a “hobbyist” RAD application to a more structured RAD application. It won’t be perfect but it will be more maintainable than it is now.

There actually is no universally accepted best practice for a Delphi RAD application but here’s a few rules of thumb to start the process of improving your code maintainability. The most important principle is to structure your application into layers.

At the Bottom - The user interface layer - your forms

  • Put as little code as possible in your form units. Ideally the code in your forms should all be about displaying things on screen.
  • TDataSource components can go on forms but TTable/TQuery components should go in the data access layer on datamodules.
  • All forms should be created on demand and freed once they are no longer needed. The main form is the only form that you should leave as auto-created.

In the Middle - The data access layer - your datamodule(s)

  • A single datamodule quickly becomes a maintenance nightmare for any non-trivial application.
  • Create multiple datamodules each one responsible for a specific aspect of your application. e.g. the person datamodule, the payment datamodule, the book borrowing data module. Each of these datamodules has the TTable/TQuery components for that area of the database on it.
  • Have just one DB connection component TDatabase/TFDConnection/TADOConnection in your application and put it on a single datamodule that is responsible only for maintaining that database connection.
  • Only that database connection datamodule should be autocreated, all the others should be created on demand and disposed of when you are finished with them.
  • Splitting the current single datamodule into multiple datamodules can be tricky. Be methodical and leave the original datamodule intact so you can easily switch between a new subsystem datamodule you’ve just created and the original single datamodule.
  • You’ll also need to leave your current single datamodule as being auto-created until you’re finished splitting it apart and are ready to dispose of it completely.

At the Top - The Logic layer - new units containing plain old Delphi classes (e.g. derived from TObject)

  • You will probably have code that you need to be shared between the different datamodules. Put this code in classes that are in their own separate units.
  • Don’t worry if you don’t have a lot of code to put in these classes, in a RAD style application a lot of the code that would be in this layer is replaced by dataset components and their event handlers.

Very importantly, keep your layering sound by making sure no unit never adds a unit to its uses clause from a lower layer. So a logic layer should never use a datamodule or a form, and a datamodule should never use a form.

And of course before embarking on any sort of major refactoring like this your project needs to be in a version control system, but that’s a whole other topic.

2 Likes

Thanks Sue,

That sound sensible and an improvement on my present structure

I like classes and find them useful. I suspect I am not getting best benefit from them.

Thank you Lachlan.

I use VCL 10.3

Your assumptions are correct

I have multiple forms but am moving to Frames on one form.

I create all forms and free them when finished

I have one data module

And You are absolutely correct I am too frequently using Find or Find in Files. Source s all over the place

Sue King idea seems a good place to start combined with your idea of levels, with no crossovers from higher to lower.

Multiple dmo’s is sensible. I have one data with components group for person, Member data, Reporting and the like.

Hi Eric - just a few comments.

There are quite a few Design Patterns (VM, MVM etc, DDD (Domain Driven Design) etc) - all typically used in Enterprise grade solutions these days (some will suit you better than others . In the old days I used to love ORM based architectures - still do. Delphi had it built in for a while (ModelMaker ?).

But for all solutions - no mater how trivial, it’s always good to separate your code between the GUI and the Business Rules / Implementation logic. Keeps the source code clean and more maintainable.

For the past few years all my work has been around Client and httpServer architectures. But for all my solutions (even on the Client side) I separate the program logic between handling the GUI and the domain logic (things like Business Rules, calculations etc). GUI objects (button clicks etc) should get and set params via the global class methods defined in your non GUI implementation (might be Data Modules - with or without DataSets).

Like Vincent, I use Interfaces for the implementation code, and I use Datasets (or Record Arrays on the Client Side for javascript) on the GUI Forms (data modules) side for caching query results or persistent records (using Data Modules for VCL front ends). Works well for one, two or three tier architectures. Methods for Getters and Setters go into my dedicated Business Rules modules (usually Data Modules for VCL) on the Client/GUI end.

This link might be of interest as a starting point for the framework stuff …

Cheers

Robert

Way back in the days of Turbo Pascal, I learned (the hard way) that it
was best to keep the user interface separate from the code that
manipulated data. Indeed, it was almost essential as TP compiled to COM
files rather than EXE. COM files could not be more than 64kb, so TP
allowed the use of overlays that were pulled into memory as needed. In
any complex program, some careful thought was needed to minimise memory
paging.

That problem does not exist with Delphi, but except in the simplest of
programs I still keep the GUI separate from data handling.

1 Like

Hello Eric,

we have a light version of Sue’s light version to keep as much upper case “R” of RAD alive as possible. List and entity forms/frames are separate. The data modules for lists and records are separated except for some simple lookup table. Most of the code is added to the DMOs. One datamodule per frame/form. Classes are used when the business logic gets complicated and sit in between the DMOs and FRMs. Data aware controls are used to avoid checking all sorts of silly characters being entered into a control/field. No dialogues are shown from a DMO, only published event handlers.

Everything is implemented in a way we can write test cases without needing a UI. In the end the FRMs do get rather simple.

A starting point for such a simple approach to separate data access, business logic and UI can be found in the project here:
https://bitbucket.org/mathias_burbach/dunit-on-db-apps/src/master/

The client/server version of the project will work in your Delphi Professional version too.

Salut,
Mathias

1 Like

@Eric_March I just did a quick browse through Mathias’s code and it appears to be quite a good example of the type of application I was describing. Take each one of my “rules of thumb” and you should find it well illustrated in Mathias’s code.

The biggest exception to that is that Mathias’s code doesn’t have a “Top Layer” with just classes. That’s primarily because it’s a demo application that doesn’t have need for any sophisticated common logic. It would be trivial to introduce such classes should they become necessary.

Goodo. Lockdown looks like ending, but I’ve got more time than usual at the moment.

In one application I’ve been developing over the past 10+ years, I’ve gone from 2 units originally to about 80 units now. It did require a fair bit of work to separate all of the classes into their own units, but the whole project is much more maintainable now. Most of the units are named in a way that means I can find what I need very quickly.

As for forms, I’ve been slowly refactoring them to make them more focused on GUI functions only. I auto create a few forms (that are always required) and create the other less used ones on demand.

Mine isn’t that large, but 8 years so far.

Seems like you action is popular

I just bought the Nick Hodges “Coding in Delphi” eBook as I’m always keen to improve my code and eliminate (or at least reduce) some of the horrors of my past coding.

That’s a good one for learning about how to apply advanced Delphi language features beyond just learning how they work.

If you haven’t read it already though I’d recommend “Code Complete” by Scott McConnell. If a programmer only ever reads one book, it should be this one.

Nick’s “Coding In Delphi” will help you in those parts of your program where you want to push the Delphi envelope. McConnell’s “Code Complete” will influence every line of code you write from the day you pick it up.

1 Like