SlideShare a Scribd company logo
Software Architecture & Design
 Architecture
 From n-Tier to SOA
 From SOAP to REST
 Technical Debt
 Design
 From SQL to ORM, NoSQL and ODM
 From RAD to MVC
 SOLID principles
 Domain Driven Design (DDD)
Applying patterns on Delphi code using mORMot
Software Architecture & Design
From Interfaces to SOLID
From Interfaces to SOLID
 Delphi and interfaces
 SOLID design principles
 Dependency Injection, stubs and mocks
 Using mORMot features
 Delphi and Weak pointers
From Interfaces to SOLID
Delphi and interfaces
 In Delphi OOP model
 An interface defines a type
that comprises abstract virtual methods
 It is a declaration of functionality
without an implementation of that functionality
 It defines "what" is available,
not "how" it is made available
From Interfaces to SOLID
Delphi and interfaces
 Declaring an interface
 Naming convention: ICalculator
 No visibility attribute: all published
 No fields, just methods and properties
 Unique identifier by GUID (Ctrl Shift G)
From Interfaces to SOLID
type
ICalculator = interface(IInvokable)
['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
/// add two signed 32 bit integers
function Add(n1,n2: integer): integer;
end;
Delphi and interfaces
 Implementing an interface
 ICalculator added to the “inheritance chain”
 TCalculator implements a behavior
From Interfaces to SOLID
type
TServiceCalculator = class(TInterfacedObject, ICalculator)
protected
fBulk: string;
public
function Add(n1,n2: integer): integer;
procedure SetBulk(const aValue: string);
end;
function TServiceCalculator.Add(n1, n2: integer): integer;
begin
result := n1+n2;
end;
procedure TServiceCalculator.SetBulk(const aValue: string);
begin
fBulk := aValue;
end;
Delphi and interfaces
 Using an interface
 Strong typing
 The variable defines a behavior (contract)
 Path to abstraction
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
Delphi and interfaces
 Using an interface
 Strong typing
 The variable defines a behavior (contract)
 Path to abstraction
 Automatic try..finally
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: TServiceCalculator;
begin
Calculator := TServiceCalculator.Create;
try
result := Calculator.Add(a,b);
finally
Calculator.Free;
end;
end;
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
Delphi and interfaces
 Automatic try..finally
 Compiler generates
some hidden code…
 Behavior inherited from TInterfacedObject
 Similar to COM / ActiveX
From Interfaces to SOLID
function MyAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
Calculator := TServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
function MyAdd(a,b: integer): integer;
var Calculator: TServiceCalculator;
begin
Calculator := nil;
Calculator := TServiceCalculator.Create;
try
Calculator.FRefCount := 1;
result := Calculator.Add(a,b);
finally
dec(Calculator.FRefCount);
if Calculator.FRefCount=0 then
Calculator.Free;
end;
end;
Delphi and interfaces
 Interfaces are orthogonal to implementation
 There is more than one way to do it
From Interfaces to SOLID
type
TOtherServiceCalculator = class(TInterfacedObject, ICalculator)
protected
function Add(n1,n2: integer): integer;
end;
function TOtherServiceCalculator.Add(n1, n2: integer): integer;
begin
result := n2+n1;
end;
function MyOtherAdd(a,b: integer): integer;
var Calculator: ICalculator;
begin
ICalculator := TOtherServiceCalculator.Create;
result := Calculator.Add(a,b);
end;
SOLID design principles
 Single responsibility principle
 Open/closed principle
 Liskov substitution principle (design by contract)
 Interface segregation principle
 Dependency inversion principle
From Interfaces to SOLID
SOLID design principles
 Single responsibility
 Object should have only a single responsibility
 Open/closed
 Entities should be open for extension,
but closed for modification
 Liskov substitution (design by contract)
 Objects should be replaceable with instances of their
subtypes without altering the correctness of that program
 Interface segregation
 Many specific interfaces are better than one
 Dependency inversion
 Depend upon abstractions, not depend upon concretions
From Interfaces to SOLID
SOLID design principles
 Help to fight well-known weaknesses
 Rigidity
 Hard to change something because every change
affects too many other parts of the system
 Fragility
 When you make a change, unexpected parts of the
system break
 Immobility
 Hard to reuse in another application because it cannot
be disentangled from the current application
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 When you define a class, it shall be designed to
implement only one feature
 The so-called feature can be seen as
an "axis of change" or a "a reason for change"
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 One class shall have only one reason
that justifies changing its implementation
 Classes shall have few dependencies
on other classes
 Classes shall be abstracted
from the particular layer they are running
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Splitting classes
 Imagine a TBarCodeScanner class
to handle a serial bar-code scanner
 Later on, we want to implement USB support
 First idea may be to inherit
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Splitting classes
 Imagine a TBarCodeScanner class
to handle a serial bar-code scanner
 Later on, we want to implement USB support
 But we would rather split the class hierarchy
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Splitting classes
 Later on, the manufacturer updates its protocol
To add new features, e.g. 3D scanning or coffee making
 How do we implement this?
 We have two “axis of change”
so we would define two classes
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Splitting classes
 Later on, the manufacturer updates its protocol
To add new features, e.g. 3D scanning or coffee making
 We defined two classes, which will be joined/composed
in actual barcode scanner classes
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Splitting classes
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
...
constructor TSerialBarCodeScanner.Create(
const aComPort: string; aBitRate: integer);
begin
fConnection := TSerialBarcodeConnection(aComPort,aBitRate);
fProtocol := TBCP1BarcodeProtocol.Create(fConnection);
end;
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Another example
from SynDB class definitions:
 TSQLDBConnectionProperties
 TSQLDBConnection
 TSQLDBStatement
 Each class has its own purpose,
and axis of change
 And could be implemented via ODBC, OleDB,
direct client access…
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Do not mix GUI and logic
 Do not mix logic and database
 Do not couple your code to an OS
 Check your uses statement
 There should be no reference to the UI
(e.g. Dialogs) in your business class
 No dependency to DB libraries (this is a hard one)
 No reference to WinAPI.Windows
From Interfaces to SOLID
SOLID design principles
 Single Responsibility
 Code smells
 When abusing of:
FreeAndNil()
{$ifdef} … {$endif}
uses unit1, unit2, unit3, … unit1000;
 When you can’t find the right method in a class
 (mORMot may need some refactoring here) 
 When unitary tests are hard to write
From Interfaces to SOLID
SOLID design principles
 Open / Close principle
 When you define a class or an interface
 it shall be open for extension
 but closed for modification
From Interfaces to SOLID
SOLID design principles
 Open / Closed principle
 Open for extension
 Abstract class is overridden by implementations
 No singleton nor global variable – ever
 Rely on abstraction
 if aObject is aClass then … it stinks!
 Closed for modification
 E.g. via explicitly protected or private members
 RTTI is dangerous: it may open the closed door
From Interfaces to SOLID
SOLID design principles
 Open / Closed principle
 In practice
 Define meaningful interface types
 Following the Design By Contract principle
 Define Value objects (DTOs) to transfer the data
 With almost no methods, but for initialization
 With public members, to access the value
 Define Process objects to modify the data
 With public methods, abstracted in the interface
 With mostly private members
From Interfaces to SOLID
SOLID design principles
 Open / Close principle
type
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
public
property Protocol: TAbstractBarcodeProtocol read fProtocol;
property Connection: AbstractBarcodeConnection read fConnection;
...
 Protocol and Connection are read/only
 They are injected by the overridden class constructor
 So it will be Open for extension
From Interfaces to SOLID
SOLID design principles
 Open / Close principle
type
TAbstractBarcodeScanner = class(TComponent)
protected
fProtocol: TAbstractBarcodeProtocol;
fConnection: AbstractBarcodeConnection;
public
property Protocol: TAbstractBarcodeProtocol read fProtocol;
property Connection: AbstractBarcodeConnection read fConnection;
...
 Protocol and Connection are read/only
 You could not change the behavior of a class
 It is Closed for modification
From Interfaces to SOLID
SOLID design principles
 Liskov substitution principle
From Interfaces to SOLID
SOLID design principles
 Liskov substitution principle
From Interfaces to SOLID
SOLID design principles
 Liskov substitution principle
 If TChild is a subtype of TParent
 then objects of type TParent
may be replaced with objects of type TChild
 without altering any of the desirable properties
of that program (correctness, task performed, etc.)
From Interfaces to SOLID
SOLID design principles
 Liskov substitution principle
 Tied to the Open / Closed principle
 If you define a child, you should not modify the parent
 Code-reusability of the parent implementation
 You will be able
to stub or mock an interface or a class
 Allow correct testing of a whole system:
even if all single unit tests did pass,
real system may not work if this principle was broken
From Interfaces to SOLID
SOLID design principles
 Liskov substitution patterns
 Design by contract
 Meyer's (Eiffel language) rule:
“when redefining a routine [in a derivative],
you may only replace its precondition by a weaker
one, and its postcondition by a stronger one”
 Define assertions at method level:
 What does it expect, guarantee, and maintain?
 About input/output values or types, side effects,
invariants, errors/exceptions, performance…
From Interfaces to SOLID
SOLID design principles
 Liskov substitution patterns
 Write your code using abstract variables
 Rely on parents methods and properties
 Use interface variables
instead of class implementation
 Uncouple dependencies via class composition
From Interfaces to SOLID
SOLID design principles
 Liskov substitution patterns
 Factory pattern
 In strongly typed languages (Java, C#, Delphi),
the factory is the class/object type and its constructor
 Repository pattern
 Allow persistence agnosticism (e.g. via ORM)
 Service locator pattern
 Get a class instance implementing a given interface
 According to the given context (no global/singleton)
From Interfaces to SOLID
SOLID design principles
 Liskov substitution patterns
 Practical, not dogmatic LSP
 “Parent” and “Child” are not absolute
 Depending on the context, you may define a given level
as the “highest” LSP abstract class
 e.g. if you work on server side, you may need some
server-only properties and methods
 LSP idea is to be consistent,
once the abstraction level is defined
From Interfaces to SOLID
SOLID design principles
 Liskov substitution patterns
 Practical, not dogmatic LSP
 “Parent” and “Child” are not absolute
 Inheritance is often used as code sharing among classes,
not as an abstraction contract
 In this context, LSP may not apply at class level:
be pragmatic, and write efficient code
 But LSP may apply at interface level,
for a set of methods implemented by the class
From Interfaces to SOLID
SOLID design principles
 Liskov substitution code smells
if aObject is aClass then …
case aObject.EnumeratedType of …
function … abstract;
without further override;
unit parent;
uses child1,child2,child3;
From Interfaces to SOLID
SOLID design principles
 Interface segregation principle
 Once an interface has become too 'fat'
it shall be split into smaller
and more specific interfaces
so that any clients of the interface will only know
about the methods that pertain to them
 In a nutshell, no client should be forced
to depend on methods it does not use
From Interfaces to SOLID
SOLID design principles
 Interface segregation principle
 Smaller dedicated classes should be preferred
 Single Responsibility Principle
 Favor composition over inheritance
 Smaller dedicated interfaces
 Gather operations/methods per context
 Meaningful naming and conventions
 So that the contract would be easier to understand
From Interfaces to SOLID
SOLID design principles
 Interface segregation principle
 Perfectly fits the SOA uncoupling pattern
 Stateless MicroServices for horizontal scaling
 Allows to release memory and resources ASAP
 Smaller objects have more bounded dependencies
 Ease unit testing
 Less coverage
 Less coupling
From Interfaces to SOLID
SOLID design principles
 Interface segregation principle
 Excludes RAD
 Logic implemented in TForm TDataModule
where methods are procedural code in disguise
 Put your logic behind interfaces
and call them from your UI (over VCL and FMX)
 Favors DDD
 Segregation avoid domain leaking
 Dedicated interfaces, e.g. for third party consumption
From Interfaces to SOLID
SOLID design principles
 Dependency Inversion
 High-level modules
should not depend on low-level modules
 Both should depend on abstractions
 Following other SOLI principles
 Abstractions should not depend upon details
 Details should depend upon abstractions
 Business Logic should not depend on database
 Application Layer should not depend on client UI techno
From Interfaces to SOLID
SOLID design principles
 Dependency Inversion
 In most conventional programming style:
 You write low-level components (e.g. DB tables)
 Then you integrate them with high-level components
 But this limits the re-use of high-level code
 In fact, it breaks the Liskov substitution principle
 It reduces the testing abilities (e.g. need of a real DB)
From Interfaces to SOLID
SOLID design principles
 Dependency Inversion may be implemented
 Via a plug-in system
 e.g. external libraries (for embedded applications)
 Using a service locator
 e.g. SOA catalog (SaaS/cloud)
 class resolution from an interface type
From Interfaces to SOLID
SOLID design principles
 Dependency Inversion may be implemented
 Via Dependency Injection
 Concretions are injected to the objects using them
 Only abstractions are known at design/coding time
 Uncoupled implementation injected at runtime
 Modular coding
 Perfect for bigger/complex projects, with a set of teams
 Ease testing, via stub/mock dependencies injection
 e.g. a fake database, defined as a Repository service
 Scaling abilities
From Interfaces to SOLID
SOLID design principles
 Dependency Inversion may be implemented
 Via Dependency Injection
 A class will define its dependencies as read-only
interface members
 Implementation will be injected at constructor level
 via explicit constructor parameters
 via automated resolution via RTTI
 via service locator/resolver
From Interfaces to SOLID
DI, Stubs and Mocks
 Thanks to SOLID design principles
 All your code logic will now be abstracted
to the implementation underneath
 But you need to inject the implementation
 This is Dependency Injection purpose
 You can also create fake instances to implement
a given interface, and enhance testing
 Introducing Stubs and Mocks
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Define external dependencies as interface
 as (private / protected) read-only members
 To set the implementation instance:
 Either inject the interfaces as constructor parameters
 Or use a Factory / Service locator
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Purpose is to test the following class:
From Interfaces to SOLID
TLoginController = class(TInterfacedObject,ILoginController)
protected
fUserRepository: IUserRepository;
fSmsSender: ISmsSender;
public
constructor Create(const aUserRepository: IUserRepository;
const aSmsSender: ISmsSender);
procedure ForgotMyPassword(const UserName: RawUTF8);
end;
constructor TLoginController.Create(const aUserRepository: IUserRepository;
const aSmsSender: ISmsSender);
begin
fUserRepository := aUserRepository;
fSmsSender := aSmsSender;
end;
DI, Stubs and Mocks
 Dependency Injection
 Dependencies are defined as
 Two small, uncoupled, SOLID task-specific interfaces
From Interfaces to SOLID
IUserRepository = interface(IInvokable)
['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}']
function GetUserByName(const Name: RawUTF8): TUser;
procedure Save(const User: TUser);
end;
ISmsSender = interface(IInvokable)
['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}']
function Send(const Text, Number: RawUTF8): boolean;
end;
DI, Stubs and Mocks
 Dependency Injection
 Using a dedicated Data Transfer Object (DTO)
 No dependency against storage, nor other classes
From Interfaces to SOLID
IUserRepository = interface(IInvokable)
['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}']
function GetUserByName(const Name: RawUTF8): TUser;
procedure Save(const User: TUser);
end;
TUser = record
Name: RawUTF8;
Password: RawUTF8;
MobilePhoneNumber: RawUTF8;
ID: Integer;
end;
DI, Stubs and Mocks
 Dependency Injection
 The high-level method to be tested:
 Open/Closed, Liskov and mainly Dependency
Inversion principles are followed
 Will we need a full database and to send a SMS?
From Interfaces to SOLID
procedure TLoginController.ForgotMyPassword(const UserName: RawUTF8);
var U: TUser;
begin
U := fUserRepository.GetUserByName(UserName);
U.Password := Int32ToUtf8(Random(MaxInt));
if fSmsSender.Send('Your new password is '+U.Password,U.MobilePhoneNumber) then
fUserRepository.Save(U);
end;
DI, Stubs and Mocks
 "The Art of Unit Testing" (Osherove, Roy - 2009)
 Stubs are fake objects
implementing a given contract
and returning pre-arranged responses
 They just let the test pass
 They “emulate” some behavior (e.g. a database)
From Interfaces to SOLID
DI, Stubs and Mocks
 "The Art of Unit Testing" (Osherove, Roy - 2009)
 Mocks are fake objects like stubs
which will verify if an interaction occurred or not
 They help decide if a test failed or passed
 There should be only one mock per test
From Interfaces to SOLID
DI, Stubs and Mocks
From Interfaces to SOLID
DI, Stubs and Mocks
 Expect – Run – Verify pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
DI, Stubs and Mocks
 Expect – Run – Verify pattern
 TInterfaceStub / TInterfaceMock constructors
are in fact Factories for any interface
 Clear distinction between stub and mock
 Mock is linked to its test case (self: TMyTest)
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
DI, Stubs and Mocks
 Expect – Run – Verify pattern
 Execution code itself sounds like real-life code
 But all dependencies have been injected
 Stubs will emulate real behavior
 Mock will verify that all expectations are fulfilled
From Interfaces to SOLID
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
DI, Stubs and Mocks
 Expect – Run – Verify pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
TInterfaceMock.Create(IUserRepository,UserRepository,self).
ExpectsCount('Save',qoEqualTo,1);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
end;
DI, Stubs and Mocks
 Run – Verify (aka “Test spy”) pattern
From Interfaces to SOLID
procedure TMyTest.ForgotMyPassword;
var SmsSender: ISmsSender;
UserRepository: IUserRepository;
Spy: TInterfaceMockSpy;
begin
TInterfaceStub.Create(ISmsSender,SmsSender).
Returns('Send',[true]);
Spy := TInterfaceMockSpy.Create(IUserRepository,UserRepository,self);
with TLoginController.Create(UserRepository,SmsSender) do
try
ForgotMyPassword('toto');
finally
Free;
end;
Spy.Verify('Save');
end;
DI, Stubs and Mocks
 Another features:
 Return complex values (e.g. a DTO)
 Use a delegate to create a stub/mock
 Using named or indexed variant parameters
 Using JSON array of values
 Access the test case when mocking
 Trace and verify the calls
 With a fluent interface
 Log all calls (as JSON)
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Inheriting from TInjectableObject
type
TServiceToBeTested = class(TInjectableObject,IServiceToBeTested)
protected
fService: IInjectedService;
published
property Service: IInjectedService read fService;
end;
 Will auto-inject interface published properties
 At instance creation
 Handled by TSQLRest.Services
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Inheriting from TInjectableObject
var Test: IServiceToBeTested;
begin
Test := TServiceToBeTested.CreateInjected(
[ICalculator],
[TInterfaceMock.Create(IPersistence,self).
ExpectsCount('SaveItem',qoEqualTo,1),
RestInstance.Services],
[AnyInterfacedObject]);
...
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Inheriting from TInjectableObject
procedure TServiceToBeTested.AnyProcessMethod;
var Service: IInjectedService;
begin
Resolve(IInjectedService,Service);
Service.DoSomething;
end;
From Interfaces to SOLID
DI, Stubs and Mocks
 Dependency Injection
 Inheriting from TInjectableAutoCreateFields
type
TServiceToBeTested = class(TInjectableObjectAutoCreateFields,
IServiceToBeTested)
protected
fService: IInjectedService;
fNestedObject: TSynPersistentValue;
published
property Service: IInjectedService read fService;
property NestedObject: TSynPersistentValue read fNestedObject;
end;
 Will auto-define published properties
 Resolve interface services
 Create TPersistent TSynPersistent TAutoCreateField
From Interfaces to SOLID
Weak references
 Delphi type reference model
 class
 as weak references (plain pointer) and explicit Free
 with TComponent ownership for the VCL/FMX
 integer Int64 currency double record
widestring variant
 with explicit copy
 string or any dynamic array
 via copy-on-write (COW) with reference counting
 interface
 as strong reference with reference counting
From Interfaces to SOLID
Weak references
 Strong reference-counted types (OLE/ COM)
 Will increase the count at assignment
 And decrease the count at owner’s release
 When the count reaches 0, release the instance
 Issue comes when there are
 Circular references
 External list(s) of references
From Interfaces to SOLID
Weak references
 Managed languages (C# or Java)
 Will let the Garbage Collector handle
interface variable life time
 This is complex and resource consuming
 But easy to work with
 Unmanaged languages (Delphi or ObjectiveC)
 Need explicit weak reference behavior
 mORMot features zeroing weak pointers
 Like Apple’s ARC model
From Interfaces to SOLID
Weak references
 Zeroing weak pointers
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
Weak references
 Zeroing weak pointers
This code will leak memory
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
procedure TParent.SetChild(const Value: IChild);
begin
FChild := Value;
end;
procedure TChild.SetParent(const Value: IParent);
begin
FParent := Value;
end;
Weak references
 Zeroing weak pointers
This code won’t leak memory
FChild and FParent will be set to nil
when the stored instance will be freed
From Interfaces to SOLID
IParent = interface
procedure SetChild(const Value: IChild);
function GetChild: IChild;
function HasChild: boolean;
property Child: IChild read GetChild write SetChild;
end;
IChild = interface
procedure SetParent(const Value: IParent);
function GetParent: IParent;
property Parent: IParent read GetParent write SetParent;
end;
procedure TParent.SetChild(const Value: IChild);
begin
SetWeakZero(self,@FChild,Value);
end;
procedure TChild.SetParent(const Value: IParent);
begin
SetWeakZero(self,@FParent,Value);
end;
Weak references
 Delphi NextGen memory model
 Uses ARC for every TObject instance
 This is transparent for TComponent / FMX
 No try … finally Free block needed
 But breaks the proven weak reference model
and a lot of existing code
 Only UTF-16 string type
 Direct 8 bit string type disabled 
 UTF8String RawByteString back in 10.1 Berlin 
From Interfaces to SOLID
From Interfaces to SOLID

More Related Content

PPTX
Plant Phenotyping, a new scientific discipline to quantify plant traits
PPT
Status of Transgenics in Pest Management: Global and Indian Scenario
PPT
Herbicidas
PDF
Conservação dos solos aula 08 capacidade de uso das terras
PPTX
Reação
PPTX
Wide hybridization in cotton
PPTX
Aula 1 ciencia do solo na agronomia
PDF
Introdução fauna do solo
Plant Phenotyping, a new scientific discipline to quantify plant traits
Status of Transgenics in Pest Management: Global and Indian Scenario
Herbicidas
Conservação dos solos aula 08 capacidade de uso das terras
Reação
Wide hybridization in cotton
Aula 1 ciencia do solo na agronomia
Introdução fauna do solo

What's hot (7)

PPT
PPTX
Perkembangan Model Atom
PPTX
Método Clínico para os Cuidados Farmacêuticos
PDF
Allele mining in orphan underutilized crops
PDF
06 propriedades fisicas do solo ligadas a mecanização
PDF
Research Program Genetic Gains (RPGG) Review Meeting 2021: Forward Breeding: ...
PPT
Melhoramento Genético e Biotecnologias de Milho
Perkembangan Model Atom
Método Clínico para os Cuidados Farmacêuticos
Allele mining in orphan underutilized crops
06 propriedades fisicas do solo ligadas a mecanização
Research Program Genetic Gains (RPGG) Review Meeting 2021: Forward Breeding: ...
Melhoramento Genético e Biotecnologias de Milho
Ad

Viewers also liked (11)

PDF
A4 from rad to mvc
PDF
Ekon20 mORMot WorkShop Delphi
PDF
2016 mORMot
PDF
Ekon20 mORMot Legacy Code Technical Debt Delphi Conference
PDF
D2 domain driven-design
PDF
A1 from n tier to soa
PDF
Ekon20 mORMot SOA Delphi Conference
PDF
A3 from sql to orm
PDF
A2 from soap to rest
PDF
A Performance Comparison Of C# 2013, Delphi Xe6, And Python 3.4 Languages
PDF
Delphi ORM SOA MVC SQL NoSQL JSON REST mORMot
A4 from rad to mvc
Ekon20 mORMot WorkShop Delphi
2016 mORMot
Ekon20 mORMot Legacy Code Technical Debt Delphi Conference
D2 domain driven-design
A1 from n tier to soa
Ekon20 mORMot SOA Delphi Conference
A3 from sql to orm
A2 from soap to rest
A Performance Comparison Of C# 2013, Delphi Xe6, And Python 3.4 Languages
Delphi ORM SOA MVC SQL NoSQL JSON REST mORMot
Ad

Similar to D1 from interfaces to solid (20)

PDF
2024 DAPUG Conference Arnaud Bouchez From Classes to Interfaces
PDF
Ekon21 Microservices - SOLID Meets SOA
PPT
CSharp_03_ClassesStructs_and_introduction
DOCX
C# Unit 1 notes
PPTX
Framework Design Guidelines For Brussels Users Group
PPTX
OpenDaylight and YANG
PPT
C#3.0 & Vb 9.0 New Features
PPTX
Using advanced C# features in Sharepoint development
PPTX
Framework engineering JCO 2011
PPTX
Verilog
PPT
COM Introduction
PDF
Java and android 6 weeks Training in Noida
PPT
1.Philosophy of .NET
PPTX
An Introduction to the SOLID Principles
PPTX
C:\Fakepath\Combating Software Entropy 2
PPTX
C:\Fakepath\Combating Software Entropy 2
PPTX
PPTX
SOLID - Principles of Object Oriented Design
PPT
Object Oriented Concepts and Principles
PPT
16 implementation techniques
2024 DAPUG Conference Arnaud Bouchez From Classes to Interfaces
Ekon21 Microservices - SOLID Meets SOA
CSharp_03_ClassesStructs_and_introduction
C# Unit 1 notes
Framework Design Guidelines For Brussels Users Group
OpenDaylight and YANG
C#3.0 & Vb 9.0 New Features
Using advanced C# features in Sharepoint development
Framework engineering JCO 2011
Verilog
COM Introduction
Java and android 6 weeks Training in Noida
1.Philosophy of .NET
An Introduction to the SOLID Principles
C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2
SOLID - Principles of Object Oriented Design
Object Oriented Concepts and Principles
16 implementation techniques

More from Arnaud Bouchez (20)

PDF
mORMot 2 - Pascal Cafe 2025 in Nederlands
PDF
EKON28 - Beyond Legacy Apps with mORMot 2
PDF
EKON28 - Winning the 1BRC Challenge In Pascal
PDF
EKON28 - Diving Into X.509 Certificates with mORMot 2
PDF
2024 DAPUG Conference Arnaud Bouchez FPC and Lazarus
PDF
2024 DAPUG Conference Arnaud Bouchez mORMot Gems
PDF
2024 DAPUG Conference Arnaud Bouchez From RAD to REST and SOA
PDF
2024 DAPUG Conference Arnaud Bouchez ORM ODM and mORMot
PDF
2024 DAPUG Conference Arnaud Bouchez Technical Debt
PDF
2024 DAPUG Conference Arnaud Bouchez Test Driven Design
PDF
2024 DAPUG Conference Arnaud Bouchez mORMot as a ToolBox
PDF
EKON27-FrameworksTuning.pdf
PDF
EKON27-FrameworksExpressiveness.pdf
PDF
Ekon25 mORMot 2 Server-Side Notifications
PDF
Ekon25 mORMot 2 Cryptography
PDF
Ekon24 from Delphi to AVX2
PDF
Ekon24 mORMot 2
PDF
Ekon23 (2) Kingdom-Driven-Design applied to Social Media with mORMot
PDF
Ekon23 (1) Kingdom-Driven-Design
PDF
High Performance Object Pascal Code on Servers (at EKON 22)
mORMot 2 - Pascal Cafe 2025 in Nederlands
EKON28 - Beyond Legacy Apps with mORMot 2
EKON28 - Winning the 1BRC Challenge In Pascal
EKON28 - Diving Into X.509 Certificates with mORMot 2
2024 DAPUG Conference Arnaud Bouchez FPC and Lazarus
2024 DAPUG Conference Arnaud Bouchez mORMot Gems
2024 DAPUG Conference Arnaud Bouchez From RAD to REST and SOA
2024 DAPUG Conference Arnaud Bouchez ORM ODM and mORMot
2024 DAPUG Conference Arnaud Bouchez Technical Debt
2024 DAPUG Conference Arnaud Bouchez Test Driven Design
2024 DAPUG Conference Arnaud Bouchez mORMot as a ToolBox
EKON27-FrameworksTuning.pdf
EKON27-FrameworksExpressiveness.pdf
Ekon25 mORMot 2 Server-Side Notifications
Ekon25 mORMot 2 Cryptography
Ekon24 from Delphi to AVX2
Ekon24 mORMot 2
Ekon23 (2) Kingdom-Driven-Design applied to Social Media with mORMot
Ekon23 (1) Kingdom-Driven-Design
High Performance Object Pascal Code on Servers (at EKON 22)

Recently uploaded (20)

DOCX
Greta — No-Code AI for Building Full-Stack Web & Mobile Apps
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Computer Software and OS of computer science of grade 11.pptx
PPTX
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
iTop VPN Free 5.6.0.5262 Crack latest version 2025
PPTX
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
PDF
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
PPTX
Transform Your Business with a Software ERP System
PPTX
L1 - Introduction to python Backend.pptx
PDF
Download FL Studio Crack Latest version 2025 ?
PDF
Salesforce Agentforce AI Implementation.pdf
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
PDF
medical staffing services at VALiNTRY
PPTX
CHAPTER 2 - PM Management and IT Context
Greta — No-Code AI for Building Full-Stack Web & Mobile Apps
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Computer Software and OS of computer science of grade 11.pptx
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Operating system designcfffgfgggggggvggggggggg
iTop VPN Free 5.6.0.5262 Crack latest version 2025
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
Transform Your Business with a Software ERP System
L1 - Introduction to python Backend.pptx
Download FL Studio Crack Latest version 2025 ?
Salesforce Agentforce AI Implementation.pdf
Design an Analysis of Algorithms II-SECS-1021-03
CCleaner Pro 6.38.11537 Crack Final Latest Version 2025
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
medical staffing services at VALiNTRY
CHAPTER 2 - PM Management and IT Context

D1 from interfaces to solid

  • 1. Software Architecture & Design  Architecture  From n-Tier to SOA  From SOAP to REST  Technical Debt  Design  From SQL to ORM, NoSQL and ODM  From RAD to MVC  SOLID principles  Domain Driven Design (DDD) Applying patterns on Delphi code using mORMot Software Architecture & Design
  • 3. From Interfaces to SOLID  Delphi and interfaces  SOLID design principles  Dependency Injection, stubs and mocks  Using mORMot features  Delphi and Weak pointers From Interfaces to SOLID
  • 4. Delphi and interfaces  In Delphi OOP model  An interface defines a type that comprises abstract virtual methods  It is a declaration of functionality without an implementation of that functionality  It defines "what" is available, not "how" it is made available From Interfaces to SOLID
  • 5. Delphi and interfaces  Declaring an interface  Naming convention: ICalculator  No visibility attribute: all published  No fields, just methods and properties  Unique identifier by GUID (Ctrl Shift G) From Interfaces to SOLID type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32 bit integers function Add(n1,n2: integer): integer; end;
  • 6. Delphi and interfaces  Implementing an interface  ICalculator added to the “inheritance chain”  TCalculator implements a behavior From Interfaces to SOLID type TServiceCalculator = class(TInterfacedObject, ICalculator) protected fBulk: string; public function Add(n1,n2: integer): integer; procedure SetBulk(const aValue: string); end; function TServiceCalculator.Add(n1, n2: integer): integer; begin result := n1+n2; end; procedure TServiceCalculator.SetBulk(const aValue: string); begin fBulk := aValue; end;
  • 7. Delphi and interfaces  Using an interface  Strong typing  The variable defines a behavior (contract)  Path to abstraction From Interfaces to SOLID function MyAdd(a,b: integer): integer; var Calculator: ICalculator; begin Calculator := TServiceCalculator.Create; result := Calculator.Add(a,b); end;
  • 8. Delphi and interfaces  Using an interface  Strong typing  The variable defines a behavior (contract)  Path to abstraction  Automatic try..finally From Interfaces to SOLID function MyAdd(a,b: integer): integer; var Calculator: TServiceCalculator; begin Calculator := TServiceCalculator.Create; try result := Calculator.Add(a,b); finally Calculator.Free; end; end; function MyAdd(a,b: integer): integer; var Calculator: ICalculator; begin Calculator := TServiceCalculator.Create; result := Calculator.Add(a,b); end;
  • 9. Delphi and interfaces  Automatic try..finally  Compiler generates some hidden code…  Behavior inherited from TInterfacedObject  Similar to COM / ActiveX From Interfaces to SOLID function MyAdd(a,b: integer): integer; var Calculator: ICalculator; begin Calculator := TServiceCalculator.Create; result := Calculator.Add(a,b); end; function MyAdd(a,b: integer): integer; var Calculator: TServiceCalculator; begin Calculator := nil; Calculator := TServiceCalculator.Create; try Calculator.FRefCount := 1; result := Calculator.Add(a,b); finally dec(Calculator.FRefCount); if Calculator.FRefCount=0 then Calculator.Free; end; end;
  • 10. Delphi and interfaces  Interfaces are orthogonal to implementation  There is more than one way to do it From Interfaces to SOLID type TOtherServiceCalculator = class(TInterfacedObject, ICalculator) protected function Add(n1,n2: integer): integer; end; function TOtherServiceCalculator.Add(n1, n2: integer): integer; begin result := n2+n1; end; function MyOtherAdd(a,b: integer): integer; var Calculator: ICalculator; begin ICalculator := TOtherServiceCalculator.Create; result := Calculator.Add(a,b); end;
  • 11. SOLID design principles  Single responsibility principle  Open/closed principle  Liskov substitution principle (design by contract)  Interface segregation principle  Dependency inversion principle From Interfaces to SOLID
  • 12. SOLID design principles  Single responsibility  Object should have only a single responsibility  Open/closed  Entities should be open for extension, but closed for modification  Liskov substitution (design by contract)  Objects should be replaceable with instances of their subtypes without altering the correctness of that program  Interface segregation  Many specific interfaces are better than one  Dependency inversion  Depend upon abstractions, not depend upon concretions From Interfaces to SOLID
  • 13. SOLID design principles  Help to fight well-known weaknesses  Rigidity  Hard to change something because every change affects too many other parts of the system  Fragility  When you make a change, unexpected parts of the system break  Immobility  Hard to reuse in another application because it cannot be disentangled from the current application From Interfaces to SOLID
  • 14. SOLID design principles  Single Responsibility  When you define a class, it shall be designed to implement only one feature  The so-called feature can be seen as an "axis of change" or a "a reason for change" From Interfaces to SOLID
  • 15. SOLID design principles  Single Responsibility  One class shall have only one reason that justifies changing its implementation  Classes shall have few dependencies on other classes  Classes shall be abstracted from the particular layer they are running From Interfaces to SOLID
  • 16. SOLID design principles  Single Responsibility  Splitting classes  Imagine a TBarCodeScanner class to handle a serial bar-code scanner  Later on, we want to implement USB support  First idea may be to inherit From Interfaces to SOLID
  • 17. SOLID design principles  Single Responsibility  Splitting classes  Imagine a TBarCodeScanner class to handle a serial bar-code scanner  Later on, we want to implement USB support  But we would rather split the class hierarchy From Interfaces to SOLID
  • 18. SOLID design principles  Single Responsibility  Splitting classes  Later on, the manufacturer updates its protocol To add new features, e.g. 3D scanning or coffee making  How do we implement this?  We have two “axis of change” so we would define two classes From Interfaces to SOLID
  • 19. SOLID design principles  Single Responsibility  Splitting classes  Later on, the manufacturer updates its protocol To add new features, e.g. 3D scanning or coffee making  We defined two classes, which will be joined/composed in actual barcode scanner classes From Interfaces to SOLID
  • 20. SOLID design principles  Single Responsibility  Splitting classes TAbstractBarcodeScanner = class(TComponent) protected fProtocol: TAbstractBarcodeProtocol; fConnection: AbstractBarcodeConnection; ... constructor TSerialBarCodeScanner.Create( const aComPort: string; aBitRate: integer); begin fConnection := TSerialBarcodeConnection(aComPort,aBitRate); fProtocol := TBCP1BarcodeProtocol.Create(fConnection); end; From Interfaces to SOLID
  • 21. SOLID design principles  Single Responsibility  Another example from SynDB class definitions:  TSQLDBConnectionProperties  TSQLDBConnection  TSQLDBStatement  Each class has its own purpose, and axis of change  And could be implemented via ODBC, OleDB, direct client access… From Interfaces to SOLID
  • 22. SOLID design principles  Single Responsibility  Do not mix GUI and logic  Do not mix logic and database  Do not couple your code to an OS  Check your uses statement  There should be no reference to the UI (e.g. Dialogs) in your business class  No dependency to DB libraries (this is a hard one)  No reference to WinAPI.Windows From Interfaces to SOLID
  • 23. SOLID design principles  Single Responsibility  Code smells  When abusing of: FreeAndNil() {$ifdef} … {$endif} uses unit1, unit2, unit3, … unit1000;  When you can’t find the right method in a class  (mORMot may need some refactoring here)   When unitary tests are hard to write From Interfaces to SOLID
  • 24. SOLID design principles  Open / Close principle  When you define a class or an interface  it shall be open for extension  but closed for modification From Interfaces to SOLID
  • 25. SOLID design principles  Open / Closed principle  Open for extension  Abstract class is overridden by implementations  No singleton nor global variable – ever  Rely on abstraction  if aObject is aClass then … it stinks!  Closed for modification  E.g. via explicitly protected or private members  RTTI is dangerous: it may open the closed door From Interfaces to SOLID
  • 26. SOLID design principles  Open / Closed principle  In practice  Define meaningful interface types  Following the Design By Contract principle  Define Value objects (DTOs) to transfer the data  With almost no methods, but for initialization  With public members, to access the value  Define Process objects to modify the data  With public methods, abstracted in the interface  With mostly private members From Interfaces to SOLID
  • 27. SOLID design principles  Open / Close principle type TAbstractBarcodeScanner = class(TComponent) protected fProtocol: TAbstractBarcodeProtocol; fConnection: AbstractBarcodeConnection; public property Protocol: TAbstractBarcodeProtocol read fProtocol; property Connection: AbstractBarcodeConnection read fConnection; ...  Protocol and Connection are read/only  They are injected by the overridden class constructor  So it will be Open for extension From Interfaces to SOLID
  • 28. SOLID design principles  Open / Close principle type TAbstractBarcodeScanner = class(TComponent) protected fProtocol: TAbstractBarcodeProtocol; fConnection: AbstractBarcodeConnection; public property Protocol: TAbstractBarcodeProtocol read fProtocol; property Connection: AbstractBarcodeConnection read fConnection; ...  Protocol and Connection are read/only  You could not change the behavior of a class  It is Closed for modification From Interfaces to SOLID
  • 29. SOLID design principles  Liskov substitution principle From Interfaces to SOLID
  • 30. SOLID design principles  Liskov substitution principle From Interfaces to SOLID
  • 31. SOLID design principles  Liskov substitution principle  If TChild is a subtype of TParent  then objects of type TParent may be replaced with objects of type TChild  without altering any of the desirable properties of that program (correctness, task performed, etc.) From Interfaces to SOLID
  • 32. SOLID design principles  Liskov substitution principle  Tied to the Open / Closed principle  If you define a child, you should not modify the parent  Code-reusability of the parent implementation  You will be able to stub or mock an interface or a class  Allow correct testing of a whole system: even if all single unit tests did pass, real system may not work if this principle was broken From Interfaces to SOLID
  • 33. SOLID design principles  Liskov substitution patterns  Design by contract  Meyer's (Eiffel language) rule: “when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one”  Define assertions at method level:  What does it expect, guarantee, and maintain?  About input/output values or types, side effects, invariants, errors/exceptions, performance… From Interfaces to SOLID
  • 34. SOLID design principles  Liskov substitution patterns  Write your code using abstract variables  Rely on parents methods and properties  Use interface variables instead of class implementation  Uncouple dependencies via class composition From Interfaces to SOLID
  • 35. SOLID design principles  Liskov substitution patterns  Factory pattern  In strongly typed languages (Java, C#, Delphi), the factory is the class/object type and its constructor  Repository pattern  Allow persistence agnosticism (e.g. via ORM)  Service locator pattern  Get a class instance implementing a given interface  According to the given context (no global/singleton) From Interfaces to SOLID
  • 36. SOLID design principles  Liskov substitution patterns  Practical, not dogmatic LSP  “Parent” and “Child” are not absolute  Depending on the context, you may define a given level as the “highest” LSP abstract class  e.g. if you work on server side, you may need some server-only properties and methods  LSP idea is to be consistent, once the abstraction level is defined From Interfaces to SOLID
  • 37. SOLID design principles  Liskov substitution patterns  Practical, not dogmatic LSP  “Parent” and “Child” are not absolute  Inheritance is often used as code sharing among classes, not as an abstraction contract  In this context, LSP may not apply at class level: be pragmatic, and write efficient code  But LSP may apply at interface level, for a set of methods implemented by the class From Interfaces to SOLID
  • 38. SOLID design principles  Liskov substitution code smells if aObject is aClass then … case aObject.EnumeratedType of … function … abstract; without further override; unit parent; uses child1,child2,child3; From Interfaces to SOLID
  • 39. SOLID design principles  Interface segregation principle  Once an interface has become too 'fat' it shall be split into smaller and more specific interfaces so that any clients of the interface will only know about the methods that pertain to them  In a nutshell, no client should be forced to depend on methods it does not use From Interfaces to SOLID
  • 40. SOLID design principles  Interface segregation principle  Smaller dedicated classes should be preferred  Single Responsibility Principle  Favor composition over inheritance  Smaller dedicated interfaces  Gather operations/methods per context  Meaningful naming and conventions  So that the contract would be easier to understand From Interfaces to SOLID
  • 41. SOLID design principles  Interface segregation principle  Perfectly fits the SOA uncoupling pattern  Stateless MicroServices for horizontal scaling  Allows to release memory and resources ASAP  Smaller objects have more bounded dependencies  Ease unit testing  Less coverage  Less coupling From Interfaces to SOLID
  • 42. SOLID design principles  Interface segregation principle  Excludes RAD  Logic implemented in TForm TDataModule where methods are procedural code in disguise  Put your logic behind interfaces and call them from your UI (over VCL and FMX)  Favors DDD  Segregation avoid domain leaking  Dedicated interfaces, e.g. for third party consumption From Interfaces to SOLID
  • 43. SOLID design principles  Dependency Inversion  High-level modules should not depend on low-level modules  Both should depend on abstractions  Following other SOLI principles  Abstractions should not depend upon details  Details should depend upon abstractions  Business Logic should not depend on database  Application Layer should not depend on client UI techno From Interfaces to SOLID
  • 44. SOLID design principles  Dependency Inversion  In most conventional programming style:  You write low-level components (e.g. DB tables)  Then you integrate them with high-level components  But this limits the re-use of high-level code  In fact, it breaks the Liskov substitution principle  It reduces the testing abilities (e.g. need of a real DB) From Interfaces to SOLID
  • 45. SOLID design principles  Dependency Inversion may be implemented  Via a plug-in system  e.g. external libraries (for embedded applications)  Using a service locator  e.g. SOA catalog (SaaS/cloud)  class resolution from an interface type From Interfaces to SOLID
  • 46. SOLID design principles  Dependency Inversion may be implemented  Via Dependency Injection  Concretions are injected to the objects using them  Only abstractions are known at design/coding time  Uncoupled implementation injected at runtime  Modular coding  Perfect for bigger/complex projects, with a set of teams  Ease testing, via stub/mock dependencies injection  e.g. a fake database, defined as a Repository service  Scaling abilities From Interfaces to SOLID
  • 47. SOLID design principles  Dependency Inversion may be implemented  Via Dependency Injection  A class will define its dependencies as read-only interface members  Implementation will be injected at constructor level  via explicit constructor parameters  via automated resolution via RTTI  via service locator/resolver From Interfaces to SOLID
  • 48. DI, Stubs and Mocks  Thanks to SOLID design principles  All your code logic will now be abstracted to the implementation underneath  But you need to inject the implementation  This is Dependency Injection purpose  You can also create fake instances to implement a given interface, and enhance testing  Introducing Stubs and Mocks From Interfaces to SOLID
  • 49. DI, Stubs and Mocks  Dependency Injection  Define external dependencies as interface  as (private / protected) read-only members  To set the implementation instance:  Either inject the interfaces as constructor parameters  Or use a Factory / Service locator From Interfaces to SOLID
  • 50. DI, Stubs and Mocks  Dependency Injection  Purpose is to test the following class: From Interfaces to SOLID TLoginController = class(TInterfacedObject,ILoginController) protected fUserRepository: IUserRepository; fSmsSender: ISmsSender; public constructor Create(const aUserRepository: IUserRepository; const aSmsSender: ISmsSender); procedure ForgotMyPassword(const UserName: RawUTF8); end; constructor TLoginController.Create(const aUserRepository: IUserRepository; const aSmsSender: ISmsSender); begin fUserRepository := aUserRepository; fSmsSender := aSmsSender; end;
  • 51. DI, Stubs and Mocks  Dependency Injection  Dependencies are defined as  Two small, uncoupled, SOLID task-specific interfaces From Interfaces to SOLID IUserRepository = interface(IInvokable) ['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}'] function GetUserByName(const Name: RawUTF8): TUser; procedure Save(const User: TUser); end; ISmsSender = interface(IInvokable) ['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}'] function Send(const Text, Number: RawUTF8): boolean; end;
  • 52. DI, Stubs and Mocks  Dependency Injection  Using a dedicated Data Transfer Object (DTO)  No dependency against storage, nor other classes From Interfaces to SOLID IUserRepository = interface(IInvokable) ['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}'] function GetUserByName(const Name: RawUTF8): TUser; procedure Save(const User: TUser); end; TUser = record Name: RawUTF8; Password: RawUTF8; MobilePhoneNumber: RawUTF8; ID: Integer; end;
  • 53. DI, Stubs and Mocks  Dependency Injection  The high-level method to be tested:  Open/Closed, Liskov and mainly Dependency Inversion principles are followed  Will we need a full database and to send a SMS? From Interfaces to SOLID procedure TLoginController.ForgotMyPassword(const UserName: RawUTF8); var U: TUser; begin U := fUserRepository.GetUserByName(UserName); U.Password := Int32ToUtf8(Random(MaxInt)); if fSmsSender.Send('Your new password is '+U.Password,U.MobilePhoneNumber) then fUserRepository.Save(U); end;
  • 54. DI, Stubs and Mocks  "The Art of Unit Testing" (Osherove, Roy - 2009)  Stubs are fake objects implementing a given contract and returning pre-arranged responses  They just let the test pass  They “emulate” some behavior (e.g. a database) From Interfaces to SOLID
  • 55. DI, Stubs and Mocks  "The Art of Unit Testing" (Osherove, Roy - 2009)  Mocks are fake objects like stubs which will verify if an interaction occurred or not  They help decide if a test failed or passed  There should be only one mock per test From Interfaces to SOLID
  • 56. DI, Stubs and Mocks From Interfaces to SOLID
  • 57. DI, Stubs and Mocks  Expect – Run – Verify pattern From Interfaces to SOLID procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; begin TInterfaceStub.Create(ISmsSender,SmsSender). Returns('Send',[true]); TInterfaceMock.Create(IUserRepository,UserRepository,self). ExpectsCount('Save',qoEqualTo,1); with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; end;
  • 58. DI, Stubs and Mocks  Expect – Run – Verify pattern  TInterfaceStub / TInterfaceMock constructors are in fact Factories for any interface  Clear distinction between stub and mock  Mock is linked to its test case (self: TMyTest) From Interfaces to SOLID procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; begin TInterfaceStub.Create(ISmsSender,SmsSender). Returns('Send',[true]); TInterfaceMock.Create(IUserRepository,UserRepository,self). ExpectsCount('Save',qoEqualTo,1);
  • 59. DI, Stubs and Mocks  Expect – Run – Verify pattern  Execution code itself sounds like real-life code  But all dependencies have been injected  Stubs will emulate real behavior  Mock will verify that all expectations are fulfilled From Interfaces to SOLID with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; end;
  • 60. DI, Stubs and Mocks  Expect – Run – Verify pattern From Interfaces to SOLID procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; begin TInterfaceStub.Create(ISmsSender,SmsSender). Returns('Send',[true]); TInterfaceMock.Create(IUserRepository,UserRepository,self). ExpectsCount('Save',qoEqualTo,1); with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; end;
  • 61. DI, Stubs and Mocks  Run – Verify (aka “Test spy”) pattern From Interfaces to SOLID procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; Spy: TInterfaceMockSpy; begin TInterfaceStub.Create(ISmsSender,SmsSender). Returns('Send',[true]); Spy := TInterfaceMockSpy.Create(IUserRepository,UserRepository,self); with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; Spy.Verify('Save'); end;
  • 62. DI, Stubs and Mocks  Another features:  Return complex values (e.g. a DTO)  Use a delegate to create a stub/mock  Using named or indexed variant parameters  Using JSON array of values  Access the test case when mocking  Trace and verify the calls  With a fluent interface  Log all calls (as JSON) From Interfaces to SOLID
  • 63. DI, Stubs and Mocks  Dependency Injection  Inheriting from TInjectableObject type TServiceToBeTested = class(TInjectableObject,IServiceToBeTested) protected fService: IInjectedService; published property Service: IInjectedService read fService; end;  Will auto-inject interface published properties  At instance creation  Handled by TSQLRest.Services From Interfaces to SOLID
  • 64. DI, Stubs and Mocks  Dependency Injection  Inheriting from TInjectableObject var Test: IServiceToBeTested; begin Test := TServiceToBeTested.CreateInjected( [ICalculator], [TInterfaceMock.Create(IPersistence,self). ExpectsCount('SaveItem',qoEqualTo,1), RestInstance.Services], [AnyInterfacedObject]); ... From Interfaces to SOLID
  • 65. DI, Stubs and Mocks  Dependency Injection  Inheriting from TInjectableObject procedure TServiceToBeTested.AnyProcessMethod; var Service: IInjectedService; begin Resolve(IInjectedService,Service); Service.DoSomething; end; From Interfaces to SOLID
  • 66. DI, Stubs and Mocks  Dependency Injection  Inheriting from TInjectableAutoCreateFields type TServiceToBeTested = class(TInjectableObjectAutoCreateFields, IServiceToBeTested) protected fService: IInjectedService; fNestedObject: TSynPersistentValue; published property Service: IInjectedService read fService; property NestedObject: TSynPersistentValue read fNestedObject; end;  Will auto-define published properties  Resolve interface services  Create TPersistent TSynPersistent TAutoCreateField From Interfaces to SOLID
  • 67. Weak references  Delphi type reference model  class  as weak references (plain pointer) and explicit Free  with TComponent ownership for the VCL/FMX  integer Int64 currency double record widestring variant  with explicit copy  string or any dynamic array  via copy-on-write (COW) with reference counting  interface  as strong reference with reference counting From Interfaces to SOLID
  • 68. Weak references  Strong reference-counted types (OLE/ COM)  Will increase the count at assignment  And decrease the count at owner’s release  When the count reaches 0, release the instance  Issue comes when there are  Circular references  External list(s) of references From Interfaces to SOLID
  • 69. Weak references  Managed languages (C# or Java)  Will let the Garbage Collector handle interface variable life time  This is complex and resource consuming  But easy to work with  Unmanaged languages (Delphi or ObjectiveC)  Need explicit weak reference behavior  mORMot features zeroing weak pointers  Like Apple’s ARC model From Interfaces to SOLID
  • 70. Weak references  Zeroing weak pointers From Interfaces to SOLID IParent = interface procedure SetChild(const Value: IChild); function GetChild: IChild; function HasChild: boolean; property Child: IChild read GetChild write SetChild; end; IChild = interface procedure SetParent(const Value: IParent); function GetParent: IParent; property Parent: IParent read GetParent write SetParent; end;
  • 71. Weak references  Zeroing weak pointers This code will leak memory From Interfaces to SOLID IParent = interface procedure SetChild(const Value: IChild); function GetChild: IChild; function HasChild: boolean; property Child: IChild read GetChild write SetChild; end; IChild = interface procedure SetParent(const Value: IParent); function GetParent: IParent; property Parent: IParent read GetParent write SetParent; end; procedure TParent.SetChild(const Value: IChild); begin FChild := Value; end; procedure TChild.SetParent(const Value: IParent); begin FParent := Value; end;
  • 72. Weak references  Zeroing weak pointers This code won’t leak memory FChild and FParent will be set to nil when the stored instance will be freed From Interfaces to SOLID IParent = interface procedure SetChild(const Value: IChild); function GetChild: IChild; function HasChild: boolean; property Child: IChild read GetChild write SetChild; end; IChild = interface procedure SetParent(const Value: IParent); function GetParent: IParent; property Parent: IParent read GetParent write SetParent; end; procedure TParent.SetChild(const Value: IChild); begin SetWeakZero(self,@FChild,Value); end; procedure TChild.SetParent(const Value: IParent); begin SetWeakZero(self,@FParent,Value); end;
  • 73. Weak references  Delphi NextGen memory model  Uses ARC for every TObject instance  This is transparent for TComponent / FMX  No try … finally Free block needed  But breaks the proven weak reference model and a lot of existing code  Only UTF-16 string type  Direct 8 bit string type disabled   UTF8String RawByteString back in 10.1 Berlin  From Interfaces to SOLID