Übersicht

© 2020 Consultingwerk Ltd. All rights reserved. 1 Managing Dependencies in OOABL

Mike Fechner Director Übersicht

© 2020 Consultingwerk Ltd. All rights reserved. 4 Übersicht

Consultingwerk . Independent IT consulting organization . Focusing on OpenEdge and related technology . Located in Cologne, Germany, subsidiaries in UK and Romania . Customers in Europe, North America, Australia and South Africa . Vendor of developer tools and consulting services . Specialized in GUI for .NET, Angular, OO, Software Architecture, Application Integration . Experts in OpenEdge Application Modernization

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Mike Fechner . Director, Lead Modernization Architect and Product Manager of the SmartComponent Library and WinKit . Specialized on object oriented design, software architecture, desktop user interfaces and web technologies . 28 years of Progress experience (V5 … OE11) . Active member of the OpenEdge community . Frequent speaker at OpenEdge related conferences around the world

© 2020 Consultingwerk Ltd. All rights reserved. 6 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators .

© 2020 Consultingwerk Ltd. All rights reserved. 7 Übersicht

Introduction

. Object oriented (ABL) programming is more than just a bunch of new syntax elements . It’s easy to continue producing procedural spaghetti code in classes . Successful adoption of object oriented programming requires knowledge of a few key principles and patterns

© 2020 Consultingwerk Ltd. All rights reserved. 8 Übersicht

Definitions

Types type defines the set of requests (e.g. method calls or properties) to which it can respond. In the ABL, typically classes, interfaces, enums Strong typing compile-time enforcement of rules Member stuff "inside" a type - methods, properties, events, variables, etc Access control compile-time restriction on member visibility: public, protected, private Class type with executable code; implementation of a type Abstract class non-instantiable (non-runnable) class that may have executable code Static members loaded once per session. think GLOBAL SHARED Interface type with public members without implementations Enum strongly-typed name int64-value pairs Object running classes, aka instance

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Common terms

Software : SOLID principles general reusable solution to a S ingle responsibility commonly occurring problem Open-closed within a given context L iskov substitution . Parameter value I nterface segregation . Fluent Interfaces Dependency inversion . Factory method . Singleton http://en.wikipedia.org/wiki/Software_design_pattern

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Software goals

. Flexibility . Allow implementations to be swapped without changes to the calling/consuming code . Make testing (mocking) easier

. Modularity & extensibility . Allow independent (teams / companies) to develop frameworks and components or modules . Allow later / third-party extension of components without changing initial / core components

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Dependencies

. Modular programming leads to dependencies as most code requires other code to fulfill a purpose . Currency conversion service needs access to currency rates . Flexibility required to allow to swap implementation . Unit Testing . Customization in a single code base . Extention of the application . V1 vs V2 of an implementation

© 2020 Consultingwerk Ltd. All rights reserved. 12 Übersicht

Interface types

. “Classes” with no implementation, no executable code . Part of a programming contract (in the sense of contractual design) . Only PUBLIC members allowed, compiler enforced . Interfaces define a set of members a class needs to provide so that the class becomes compatible to the Interfaces type, compiler enforced . Classes can implement multiple interfaces . Interface types make different implementations exchangeable . Constructors not part of Interface types . Interfaces should be small, only few methods

© 2020 Consultingwerk Ltd. All rights reserved. 13 Übersicht

Interface vs. Implementation

. Prefer Interface types for parameters and return value definitions . Foundation for mocking (Unit Testing) . Foundation for customization through configuration . Interfaces define common type without requiring to inherit from a common base class . Inheritance should be an implementation detail . Interface may however be inherited from base class

CLASS Demo.CustomerBusinessEntity INHERITS Consultingwerk.OERA.BusinessEntity IMPLEMENTS Consultingwerk.OERA.IBusinessEntity:

© 2020 Consultingwerk Ltd. All rights reserved. 14 Übersicht

Naming standards

. Pick one … and live with that – as it must be clear to the whole team

. .NET: Interface names starting with a capital I, followed by another capital letter: IBusinessEntity, default implementation (if exists): BusinessEntity

. Java: Interface names with no prefix, default implementation sometimes suffixed with “Impl”: BusinessEntity and BusinessEntityImpl

© 2020 Consultingwerk Ltd. All rights reserved. 15 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 16 Übersicht

Temp-Table Definitions

. In modern ABL applications a lot of code depends on temp-table and ProDataset definitions . Temp-Table Parameters as part of Interface . Temp-Tables as part of implementation . Compile time dependency that caller and callee use identical definition

© 2020 Consultingwerk Ltd. All rights reserved. 17 Übersicht

Temp-Table Include Files

. Temp-Table definitions are well placed in include files . The easiest way in the ABL to treat a temp-table definition as a type . Temp-Table Include Files should provide to support reuse in difference scenarios

© 2020 Consultingwerk Ltd. All rights reserved. 18 Übersicht

Temp-Table Include File Parameters

. ACCESS . PRIVATE | PROTECTED | PUBLIC . STATIC . REFERENE-ONLY . To support temp-tables used for BIND and BY-REFERENCE parameters . SUFFIX . Allow to use same temp-table twice in one compile-unit . NO-BEFORE . ProDataset Temp-Tables with no BEFORE-TABLE considered read-only

© 2020 Consultingwerk Ltd. All rights reserved. 19 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 20 Übersicht

Factories

. Factories have the sole responsibility of creating object instances . They can/should be the only place knowing requirements to create object instances . Separate the concern of creating an Object instance from using it . May be based on configuration . May support Unit Testing and Mocking

© 2020 Consultingwerk Ltd. All rights reserved. 21 Übersicht

Different Implementations

. Factory Service: CreateObject (Type) – Type is typically an Interface or Enum etc. . Factory Methods . Abstract Factories

. Avoid direct usage of NEW on unrelated type in your code . Accept NEW on related code or parameter types . Calling into a Factory always provides overhead

© 2020 Consultingwerk Ltd. All rights reserved. 22 Übersicht

Consultingwerk Factory

© 2020 Consultingwerk Ltd. All rights reserved. 23 Übersicht

Factory Configuration File

. Mapping (Interface) Type to current implementation

© 2020 Consultingwerk Ltd. All rights reserved. 24 Übersicht

Demo

. Using the Factory Service

© 2020 Consultingwerk Ltd. All rights reserved. 25 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 26 Übersicht

Fluent Interfaces

In software engineering, a .. is a method for designing object oriented based extensively on method chaining with the goal of making the readability of the source code close to that of ordinary written prose, essentially creating a domain-specific language within the interface.

https://en.wikipedia.org/wiki/Fluent_interface

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Fluent Interfaces

. Useful when typically a sequence of calls into an object is required . Order of those calls typically not relevant . Might be used to initialize (parameter) objects . Typically more verbose than a number of parameters, makes understanding of code by other developers trivial . But – usually confusing to developers that haven’t seen this before

© 2020 Consultingwerk Ltd. All rights reserved. 28 Übersicht

Example

DEFINE VARIABLE oParameter AS FluentParameterSample NO-UNDO .

/* Constructor with parameters */ oParameter = NEW FluentParameterSample (11, 42, 1/1/2018, 12/31/2018) .

/* Fluent Interface in a single line */ oParameter = (NEW FluentParameterSample()):CustomerNumber(11):ItemNumber(42): StartDate (1/1/2018):EndDate (12/31/2018) .

/* Block formatting of Fluent Interface */ oParameter = (NEW FluentParameterSample()) :CustomerNumber (11) :ItemNumber (42) :StartDate (1/1/2018) :EndDate (12/31/2018) .

© 2020 Consultingwerk Ltd. All rights reserved. 29 Übersicht

Implementation of Example

. VOID methods simply return THIS-OBJECT instead . Use methods as alternative PROPERTY SET

METHOD PUBLIC FluentParameterSample ItemNumber (piItemNumber AS INTEGER):

ASSIGN THIS-OBJECT:ItemNumber = piItemNumber . RETURN THIS-OBJECT .

END METHOD.

© 2020 Consultingwerk Ltd. All rights reserved. 30 Übersicht

Builders

The Builder is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation. It is one of the Gang of Four design patterns.

https://en.wikipedia.org/wiki/Builder_pattern

© 2020 Consultingwerk Ltd. All rights reserved. 31 Übersicht

OpenEdge HTTP Client

. Extensive ABL implementation of the HTTP protocol . GET/POST/PUT/PATCH/DELETE to HTTP servers, REST services, SOAP, … . Object model similar to the Web Handlers (HTTP service implementation) . OpenEdge 11.6 + (available but unsupported in 11.5) . Many parameters …. . Basic syntax on next slide

© 2020 Consultingwerk Ltd. All rights reserved. 32 Übersicht

DEFINE VARIABLE oLibrary AS IHttpClientLibrary NO-UNDO . DEFINE VARIABLE oClient AS IHttpClient NO-UNDO . DEFINE VARIABLE oRequest AS IHttpRequest NO-UNDO . DEFINE VARIABLE oResponse AS IHttpResponse NO-UNDO . DEFINE VARIABLE oRequestBuilder AS RequestBuilder NO-UNDO . DEFINE VARIABLE cUri AS CHARACTER NO-UNDO .

oLibrary = ClientLibraryBuilder:Build():Library. oClient = ClientBuilder:Build():UsingLibrary(oLibrary):Client .

ASSIGN cUri = SUBSTITUTE ("http://data.fixer.io/api/latest?access_key=&1&&base=&2&&symbols=&3":U, FIXER_API_KEY, pcFromSymbol, pcToSymbol) .

oRequestBuilder = RequestBuilder:Get(cURI):AcceptJson() . oRequest = oRequestBuilder:Request. oResponse = oClient:Execute (oRequest).

RETURN CAST (oResponse:Entity, JsonObject):GetJsonObject ("rates":U):GetDecimal © 2020(pcToSymbol Consultingwerk Ltd.) All. rights reserved. 33 Übersicht

A closer look

. RequestBuilder – static reference to the RequestBuilder class . Each method returns an instance of the RequestBuilder . Request property returns reference to the IHttpRequest instance that was built . We don’t know, we don’t need to know the class implementing IHttpRequest – that’s if at all a concern of the RequestBuilder class

DEFINE VARIABLE oRequest AS IHttpRequest NO-UNDO . DEFINE VARIABLE oRequestBuilder AS RequestBuilder NO-UNDO .

oRequestBuilder = RequestBuilder:Get(cURI):AcceptJson() . oRequest = oRequestBuilder:Request.

© 2020 Consultingwerk Ltd. All rights reserved. 34 Übersicht

A simplification

. In many cases we don’t require the reference to the RequestBuilder

DEFINE VARIABLE oRequest AS IHttpRequest NO-UNDO .

oRequest = RequestBuilder:Get(cURI):AcceptJson():Request.

© 2020 Consultingwerk Ltd. All rights reserved. 35 Übersicht

© 2020 Consultingwerk Ltd. All rights reserved. 36 Übersicht

Fluent Builder Interface

. Builder may use Fluent Interfaces (previous section) to allow for method chaining

oRequest = RequestBuilder:Get(cURI) :AddHeader ("some-name", "42") :SupportsProxy() :AcceptJson() :Request .

© 2020 Consultingwerk Ltd. All rights reserved. 37 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 38 Übersicht

Services and Managers

. A Service is a self-contained unit of functionality . Well defined functionality and behavior . Well defined interfaces and life-cycle

. A Manager is a common infrastructure service

. A Business Service is a service implementing business domain specific functionality

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 39 Übersicht

Services and Managers

. Typically implementing Interfaces (provided by CCS) . Requires OO implementation or facade to procedural implementation or remote service

. References accessed through the Service Manager (Services) or Startup Manager (Managers)

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 40 Übersicht

Services

. All Services must provide a standard constructor . All Services must provide an initialize() method

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 41 Übersicht

Managers

. Same requirements as Services . Managers are specialized Services

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 42 Übersicht

Service Manager

. Service Manager provides access to Services (that are not Managers) . Factory for business services . Calls their initialize() method . Controls their life time . Services typically launched at first request . Services may be stopped (at the end of a request, after 1 hour, …)

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 43 Übersicht

Ccs.Common.IServiceManager

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 44 Übersicht

Sample Service Manager implementation

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 45 Übersicht

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 46 Übersicht

Sample Service Manager implementation

. services.xml file defines service types . -param services=path/to/services.xml

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 47 Übersicht

Accessing a Service . Ccs.Common.Application:ServiceManager reference to the IServiceManager

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 48 Übersicht

Service Manager in the SmartComponent Library

. ServiceContainer for (in session) services . Services typically implemented by Interface . We allowed for Services implemented by a Class . ServiceManager for business services (exposed to the Service Interface) since ever . Typically Business Entities and Business Tasks . Business Services identified by a string identifier . May be a class name, a short class name or an alias

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 49 Übersicht

Service Manager in the SmartComponent Library

. Two different registries . Different use-case . Different type of keys: Progress.Lang.Class vs. CHARACTER . ServiceContainer relies on external factory (or IServiceCreator registered instead of the Service) . ServiceManager may use Alias-Service and launch a Business Entity . Consultingwerk Service Container will not (always) error when requested Service type is not known; CCS requires to error when requested Service type is not known

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 50 Übersicht

Service Manager in the SmartComponent Library

. Implementation through a wrapper . Combining ServiceContainer and ServiceManager . Throwing error when requested service is not registered

. Service factories will invoke initialize method on new services, when Service implements CCS IService interface . Service wrapper can also be used for non CCS services…

© 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 51 Übersicht

FrameworkSettings is like our own Ccs.Common.Application class © 2020CCS Consultingwerk - A deep dive Ltd. All rights reserved. 52 Übersicht

Demo

. Implementing a Service and accessing it via the Service Manager

© 2020 Consultingwerk Ltd. All rights reserved. 53 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 54 Übersicht

Sample code on Github

. A simplified but working example of the CCS Managers including the Service Manager is available on Github: . https://github.com/consultingwerk/CCS_Samples

© 2020 Consultingwerk Ltd. All rights reserved. 55 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 56 Übersicht

Decorators

In object-oriented programming, the is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. https://en.wikipedia.org/wiki/Decorator_pattern

© 2020 Consultingwerk Ltd. All rights reserved. 57 Übersicht

Decorator Pattern

. Allows extension of an object instance through another object instance . Requires objects to implement the same Interface . Decorated object implementing with standard functionality . Decorator implementing behavior by calling into methods of the decorated object plus X . Decorator can replace or extend the original implementation . Multiple decorators may be applied to one object . Configuration/factory used to abstract the creation of decorator or base object

© 2020 Consultingwerk Ltd. All rights reserved. Übersicht

Decorator Example

CLASS Demo.OoInterfaces.Decorator.PriceCalculatorDiscountDecorator IMPLEMENTS IPriceCalculator:

DEFINE PRIVATE VARIABLE oDecorated AS IPriceCalculator NO-UNDO .

CONSTRUCTOR PUBLIC PriceCalculatorDiscountDecorator (poDecorated AS IPriceCalculator): ASSIGN oDecorated = poDecorated . END CONSTRUCTOR.

METHOD PUBLIC DECIMAL CalculateSalesPrice (poParameter AS IPriceCalculationParameter): DEFINE VARIABLE deResult AS DECIMAL NO-UNDO.

deResult = oDecorated:CalculateSalesPrice (poParameter) .

FIND Customer WHERE Customer.CustNum = poParameter:CustomerNumber .

RETURN deResult * (1 - Customer.Discount / 100) . END METHOD. © 2020 Consultingwerk Ltd. All rights reserved. 59 Übersicht

Decorator vs. Inheritance

. Inheritance is static – adding a decorator is more dynamic . Decorator can be added to an existing object instance at runtime . Decorator references decorated object, implements all methods, typically calling the method of the decorated object . Decorator pattern may serve as method to achieve multiple inheritance . Decorator is not the same instance/reference – whereas when using inheritance there’s only a single instance made from the base and child class

© 2020 Consultingwerk Ltd. All rights reserved. 60 Übersicht

Decorator sample

https://en.wikipedia.org/wiki/Decorator_pattern

© 2020 Consultingwerk Ltd. All rights reserved. 61 Übersicht

Decorator Demo

. Code Review . SmartHttpClient . SmartHttpClientBuilder . SmartHttpClientService

© 2020 Consultingwerk Ltd. All rights reserved. 62 Übersicht

Agenda

. Introduction . Temp-Table definitions as dependencies . Factories . Builders . Service Locators or Service Manager . CCS Demo Application . Decorators . Dependency Injection

© 2020 Consultingwerk Ltd. All rights reserved. 63 Übersicht

Dependency injection

In software engineering, dependency injection is a technique whereby one object supplies the dependencies of another object. A "dependency" is an object that can be used, for example as a service. Instead of a client specifying which service it will use, something tells the client what service to use. The "injection" refers to the passing of a dependency (a service) into the object (a client) that would use it. The service is made part of the client's state. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern. https://en.wikipedia.org/wiki/Dependency_injection

© 2020 Consultingwerk Ltd. All rights reserved. 64 Übersicht

Dependency Injection

. The intent behind dependency injection is to achieve Separation of Concerns of construction and use of objects . Dependency injection is one form of the broader technique of . The injector then injects passes services into the client which might already exist or may also be constructed by the injector. . This means the client does not need to know about the injector, how to construct the services, or even which actual services it is using. The client only needs to know about the intrinsic interfaces of the services. This separates the responsibility of "use" from the responsibility of

© 2020 "construction".Consultingwerk Ltd. All rights reserved. 65 Übersicht

Dependency Injection

. Two common kinds of implementations

. Constructor injection: The injector injects dependencies as parameters to the new objects constructor. The new object is supposed to keep the reference in private variables or properties. The constructor is supposed to expect service interface types as arguments

. Property injection: The injector injects dependencies through public properties of service interface types

© 2020 Consultingwerk Ltd. All rights reserved. 66 Übersicht

Sample Dependency Injection

. Sample of constructor based dependency injection

© 2020 Consultingwerk Ltd. All rights reserved. 67 Übersicht

Service Locator vs Dependency Injection

. Service Manager implements a pull of dependencies . Dependency Injection is a push of dependencies

. DI appears to be easier for code that has dependencies, but all dependencies are provided on object construction

. Service Manager allows to request dependencies only when needed . Service Manager supports different dependencies to be returned per AppServer call

© 2020 Consultingwerk Ltd. All rights reserved. 68 Übersicht

Questions

© 2020 Consultingwerk Ltd. All rights reserved. 69 Übersicht

© 2020 Consultingwerk Ltd. All rights reserved. 70