What I always fail to understand is why developers (especially Delphi devs), tend to write programs using datasets with the normal RAD approach when all the benefits of Object Oriented Programming (OOP) are lost by doing so. Datasets were used back when I wrote Clipper programs in 1992. Clipper was not object oriented, so it’s like stepping back in time, and ignoring all the benefits that OOP has demonstrated over procedural programming.
When I was first learning OOP, I was taught “there are three pieces of PIE” where the acronym PIE stood for Polymorhpism, Inheritance, and Encapsulation. You could of course say there are slightly more than 3 pieces (3.14) in a Π, or perhaps its just a case where the whole is greater than the sum of the parts.
IMO the characteristic or benefit most often overlooked when writing Delphi code is Encapsulation. Encapsulation is what enables the de-coupling of classes, which affects your ability to maintain code over time with minimal breakage.
A good test of any code base is how easy it is to create a new application and re-use a class. Try it, and you will soon find out what the prerequisites are, and how intertwined the code is. Not only does this affect your ability to develop in an agile fashion, it means re-factoring the code for better performance is more difficult as well. One of the most common issues with legacy Delphi code is that all the work is done in a single thread (the main VCL thread). Progress reporting usually involves calls to Application.ProcessMessages() to ensure processing results are displayed in a timely fashion. What this means is that the processsing takes longer, and is even more difficult to move it to a background thread because it is tied to the VCL message loop as well as other objects in the main thread.
If I had to write an application from scratch I would:
1) use an ORM whenever possible. DataSets are compact and fast to retrieve. Where they fall down is the encapsulation of data and behaviour (business logic) which changes over time. ORM objects are more flexible, and they usually provide a validation framework as well as persistence. Sooner or later datasets will force you to break the DRY principle in anything but a trivial application.
2) use MVVM. While MVVM frameworks for Delphi are in their infancy, the concept can be implemented on a case by case basis. The idea is to keep as much code out of the View (form) as possible. What you really need for MVVM is some kind of object/data binding.
3) implement your data processing on a secondary thread. If you do so right off the bat, there is less of a chance that the data access will ever be tightly coupled with anything on the main thread, and parallelization becomes trivial.
4) use TDD to write at least the core classes in your onion architecture. The foundation on which you build an application needs to be bullet proof, otherwise you’re just building a house of cards, and when problems arise, or changes are required the termites start to come out of the woodwork. This also has the benefit that you can test and optimize the performance of each piece so once it’s all put together it should be as lean as possible. TDD forces developers to document the code they write in the form of tests.