Delivering the Expected - Solteq Developer Blog

Design Patterns in Not-Object-Oriented Programming World

Title image

If you are an experienced object-oriented programming (OOP) language developer (like this guy in the picture) then probably you are very familiar with design patterns. OOP is so popular that there are really many patterns and they are quite commonly used. But if you develop in another programming language, then design patterns concept might not sound very familiar to you.

Design pattern is a general reusable solution to a commonly occurring problem within a given context in software design [Wikipedia]. This is one of the best practice to use design patterns - instead of wasting time to reinvent the wheel, you just built the wheel in an already well-known way. Some design patterns are universal and some are more specific to the programming language. The famous Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) in their book (Design Patterns: Elements of Reusable Object-Oriented Software) have described 23 patterns and ilustrated it with Smalltalk and C++ examples.

If you are Microsoft Dynamics NAV developer and you think there are no design patterns you can use, you should better think it over!

Design Patterns Wiki

I am pretty sure that even if you are not familiar with the design patterns, you already use some of them. For instance, Document pattern. Even a junior NAV developer knows that when you implement new type of document you create header and lines structure, add a list page, a page of Document type and subpage to show the lines. This is the pattern - the standard way how to solve commonly occured problem.

On the Microsoft Dynamics Blog, there is a Design Patterns wiki listing different patterns for NAV:

https://community.dynamics.com/nav/w/designpatterns

There are many patterns published already and you can browse them by different categories (for instance: User eXperience, Setup, Error Handling). This is open community project, meaning that not only can you use design patterns, but also you are welcome to comment and even suggest new patterns.

Example - Variant Façade

In this blog text I would like to present just one pattern in NAV, which is not so obvious as a Document pattern. I will describe it briefly and show how we implemented that pattern in one of our projects.

In th OOP world, Façade design pattern was introduced by already mentioned Gang of Four. It is presented in the UML diagram in the following way:

Façade Design Pattern in OOP

The main reason to use Façade pattern is to hide complex set of functionality. Client does not have to know all the subsystems – it just calls the Façade and Façade takes care of the client’s request by calling subsystems.

Façade design pattern is so straightforward and general that can be used in NAV as well.

Background Story

In one of our projects, we were building interface to export data from NAV to external system. We used buffer table concept, meaning that before we generate the XML file with the data, first we copy the data from original tables to the buffer tables, e.g. Purchase Header table -> Purchase Header Buffer table -> file. The requirement was not only to export documents, but also master data, like Vendors (data flow was similar: Vendor table -> Vendor Buffer table -> file).

For purchase documents and vendors export we have separate codeunits with some helper functions (one codeunit per table). However, the flow of the export is the same, regardless of data type. Therefore, we have extracted one generic codeunit called Outbound Interface Mgt.. This is our Façade codeunit. At some stage of the export process, all table-specific codeunits refer to that codeunit and call a function ExportData. Neither of those two specific codeunits has to know precisely how export is done.

Client’s code

Now, as I am going to demonstrate this, I would like to ask you to use a little bit of imagination. For the sake of simplicity, I don’t want to present the whole solution and I will skip definitions of the variables, because it would be too long. Trust me, I am engineer :) Variables are self-explaining. Code of the ExportData function in those table-specific codeunits is following. For purchase documents:

RecordVariant := PurchaseHeaderBuffer;
OutboundInterfaceMgt.ExportData(RecordVariant);

(RecordVaraint is of type Variant.) For Vedors:

RecordVariant := VendorBuffer;
OutboundInterfaceMgt.ExportData(RecordVariant);

Only first line of code was changed. Both codeunits, although they are based on a different table type, call the same function in Façade codeunit - ExportData. This is the power of variant variable type. You can cast any record to variant and then pass it as a parameter to the function. Variants are often used with this Façade design pattern in NAV and this is the reason why this pattern is called in NAV Variant Façade, not just Façade.

Without Variant Façade pattern in place, most likely you would just create a piece of code for exporting Vendors and then copy-paste that code to other codeunits. However, this is a bad smell. If we can extract some blocks of commonly used code, let us do so and keep it simple.

Façade’s code

Going back to the example. In our Variant Façade codeunit Outbound Interface Mgt. function ExportData looks like this:

ExportData(VAR RecordVariant : Variant) : Boolean
DataTypeManagement.GetRecordRefAndFieldRef(RecordVariant, MessageStatusFieldNo, RecordRef, FieldRef);
FieldRef.TESTFIELD(MessageStatusOptions::Pending);
CASE RecordRef.NUMBER OF
  DATABASE::”Purchase Header Buffer”: IntegrationSetup.GET(‘PURCHASE’); 
  DATABASE::”Vendor Buffer”: IntegrationSetup.GET(‘VENDOR’);
END;
FileName := IntegrationSetup."File Path" + GenerateNewFileName;
XmlFile.CREATE(FileName);
XmlFile.CREATEOUTSTREAM(XmlStream);
IF NOT XMLPORT.EXPORT(IntegrationSetup."XmlPort ID to Run", XmlStream, RecordVariant) THEN
  ERROR(FileNotExportedErr)
CreateLogEntry(RecordVariant)

What happens here?

  1. First of all, Variant is casted to RecordRef type (functions from codeunit 701: Data Type Management are very helpful here).
  2. Having the RecordRef we know exactly what is the record type and which record it is pointing to (filters are preserved). Based on the record type, we can now read specific export settings from additional setup table Integration Setup. We have different setup per data type, so we use CASE expression to find relevant setup.
  3. Each Integration Setup record stores information about export path, file name and also XML Port ID that should be used for export XmlPort ID to Run.
  4. XmlPort is run. You can pass Variant to XmlPort and filters will be preserved.
  5. Log entry is created.

Conclusion

What are the implications? To put it in a nutshell: maintaining, extending and upgrading is cheaper. Why?

Does it have some drawbacks or weak points? Yes, I it might be more difficult to read and debug the code.

Learn more

The variant Façade has been described very well on the design pattern wiki It is based on the document printing functionality (the logic for printing purchase order and sales order is basically the same). Vjekoslav Babic (Microsoft Valuable Processional) is also describing another idea of the Façade pattern – TempBlob Façade pattern. I have never used that one, but it is also interesting. Vjeko is writing about Façade pattern in the context of polymorphism and you can read this on his blog.




Join us?

See what we have to offer - Careers