Delphi Event-based and Asynchronous Programming

Delphi Event-based and Asynchronous Programming

28/12/2020

Dalija Prasnikar, Neven Jr Prasnikar

Event-based programming is everywhere. Nowadays, you can hardly write any kind of application without leaning on events and messages.

This simple, yet extremely powerful mechanism is also the cornerstone of asynchronous and multithreaded programming. Without events, we would not know when some task was completed.

But, asynchronous and multithreaded programming consists of more than just handling multiple threads, protecting shared resources, and synchronization. It also includes designing and understanding program flow. That design aspect is often forgotten, taken for granted, and solving all the fine-grained nuances of multithreaded programming hogs the spotlight.

Without understanding asynchronous flow and the bigger picture it can be hard to properly solve all the other issues, including multithreading. What used to be plain spaghetti code, now becomes temporal spaghetti.

You can lose control over your objects, have bits of code creating and releasing them all over the place, even without adding multithreading into the mix. Memory leaks, crashes, and holding references to dead data long after its destruction are perfectly possible even in a singlethreaded environment.

While the starting point of this book is giving a proper introduction to event-based and asynchronous programming flow and design, it also provides the necessary implementation details, explanations and code examples needed to put those designs into practice.

Delphi Quality-Driven Development

Delphi Quality-Driven Development

12/02/2025

Dalija Prasnikar, Neven Jr Prasnikar

Software development is a complex and continuous process. The quality of the end result—the actual software—depends on many variables. Regardless of the size of the team, be it a solo developer, or a team with tens, hundreds, or even thousands of people involved, we cannot always fully control all the aspects of the software development process.

However, we can bring some order into the chaos, and by using well-established and proven practices, we can increase the quality of the software we are producing, and with that, increase customer satisfaction, ultimately improving the success of the software product.

There are always other factors that determine the success (viability) of the software, but a bug-ridden product is never going to be a successful one, unless users are forced to use it for reasons beyond their control.

When it comes to reducing the number of current and future bugs and other quality issues in the software, there is one thing in particular that can and will do more for improving software quality than all the others combined: automated testing.

In that light, the main title of this book could have easily been its subtitle alone: A practical guide to testing and writing testable code. However, the ability to test software requires way more than the mere act of testing or writing testable code, and covering only those two aspects would fail to address other significant factors that contribute not only to the overall quality of the produced software, but also our ability to successfully write and test its code.
While topics surrounding testing and writing testable code do comprise the most significant part of this book, all other parts of the development process that also contribute to the software quality are covered, to give a better understanding of their roles and impact in the whole process. From planning and designing, through development and testing, to deployment.

Besides that, every developer wants to produce high-quality and successful software, while not all of them are very fond of testing. Focusing on testing alone, which many of the testing-related books do, means losing some of the potential audience. What is worse, you lose those that would benefit from it the most.

Testing, you say. I don't have time for this. I have deadlines to meet.

Focusing on the end goal, producing high-quality software, instead of the journey and specific methodology, also allows us to adapt and change the process as we go, instead of sticking to some practice that is not fully applicable to a particular situation.

In our search for successful practices that will help us in doing our job better and faster, we tend to forget why we are using them. All those good practices don't exist in a void for their own sake: They evolved through our collective knowledge, being adapted, tweaked, and polished until they emerged under some name, to be more easily recognizable and approachable.

But in that effort to categorize and simplify the message we are sending to new generations of developers, we often fail to explain its origins and real purpose, passing only half of the knowledge until it degenerates into something that causes more harm than good. And then old practices are quickly abandoned without realizing the reasons for their failure, and new practices emerge, only to fail soon enough.

This is another reason for choosing the title Quality-Driven Development: it can be whatever you need it to be. It is a timeless reminder of your goals, insisting on practical know-how, instead of following and sticking with very specific, rigidly formed processes. And while you will still need to use at least some of those established practices to achieve your goals, you can more freely adapt them to serve you, rather than the other way around.

Larger companies and teams are more likely to use automated testing and other processes that contribute to software quality. Small teams and single developers, not so much. The need to ship a product on time, combined with a lack of resources to follow all the necessary steps to produce high-quality software, is always a great incentive to cut corners. Of course, larger teams are no strangers to cutting corners either, and this book is intended for all of the above, as its goal is not only to teach how to do something and how to apply a certain process, but also why all those pesky, time-consuming tasks are actually saving time and not wasting it. 

Delphi Thread Safety Patterns

Delphi Thread Safety Patterns

31/05/2022

Dalija Prasnikar, Neven Jr Prasnikar

While the thread safety of a particular piece of code depends on the surrounding context and how it is used, some data types are inherently unsafe, and for some of them, thread safety will depend on the use case and the specific code. Unfortunately, when you look at some class, type declaration, or API in isolation, there is very little information there that will tell you whether instances of that type can be safely used in multiple threads, or under which conditions.

The proper place to learn about the thread safety of an API is its documentation. However, most documentation will not explicitly give you that information. Occasionally, the documentation will mention that a particular feature is not thread-safe, or will tell you that a feature can be used in background threads, but for the most part, you will have to figure out thread safety on your own. One reason for this is that thread safety depends on the context. The number of features that are absolutely unsafe or are absolutely safe is very small.

The basic thread safety rules are simple, but applying those rules is more complicated. Just as design patterns give us general solutions to common coding problems, we can extract common coding patterns from various multithreaded code—thread safety patterns.

This book converts the thread safety rules into practice, and gives an overview of core Delphi frameworks and commonly used features from a thread safety perspective. You will find examples of how particular classes can be used in a thread-safe manner and how to perform some common tasks, following the already established thread safety patterns.

Besides elaborating on the thread safety of particular parts of Delphi frameworks, the book explores the thread safety of alternate solutions, along with general coding examples. Every explanation about why some code is thread-safe or not, also serves as an example of thread (un)safety patterns, and helps in recognizing thread-unsafe code, as well as establishing a working set of thread safety patterns that can later be applied in custom code.

Those examples, covering the most commonly used parts of Delphi frameworks, will also serve as learn by example pointers for determining the thread safety of other parts of the frameworks, and even of 3rd-party libraries that are not specifically covered in this book.

There are also implementations and examples of some commonly used concepts in asynchronous programming that are not part of the core Delphi frameworks, but can be indispensable when writing multithreaded code.

Delphi memory management for classic and ARC compilers

Delphi memory management for classic and ARC compilers

24/06/2018

Dalija Prasnikar, Neven Jr Prasnikar

Memory management. One of the most basic parts of software development, often kept on the side even though it has the most profound effect on how we write our code.

Delphi provides a variety of types with their own memory management logic, as well as two sets of compilers that provide different memory management systems for classes.

* Classic Delphi compiler currently supported on Windows and OSX platforms - using manual memory management while providing ARC for certain types.

* Next generation ARC Delphi compiler supported on mobile Android and iOS platforms, as well as Linux - using full ARC - Automatic Reference Counting memory management system.

Each memory management system has its good and bad sides. Each offers solutions to some problems, but creates a whole range of other problems. And each requires slightly different coding patterns and practices. Knowing the strengths and weaknesses and understanding how memory management system(s) work goes hand-in-hand with writing clean, bug-free and maintainable code.

Both compilers will be covered in detail, as well as coding patterns required for writing cross-compiler code that must run under both.

From manual memory management, to garbage collection, different memory management systems differ not only by the general category they fall in, but also by implementation. And all those fine implementation details also have a great impact on actual code. From the perspective of the everyday software development process discussing memory management is impossible without discussing its specific implementation in specific languages and toolsets.