No events, no activities in the field. How can your sales team still win new business?
22. April 2020Email Service Provider – Little movement in a fragmented market
18. August 2020Executing complex projects in Salesforce Marketing Cloud with SSJS
From design pattern to test-driven development
Modern web development requires a good code structure and should involve a test-driven development process. The tests to be written should ideally achieve test coverage of 100 per cent – only this ensures that the software will continue to run when modifications are made to the code in functions (changes to requests, refactoring, etc.). Common programming languages, in conjunction with appropriate frameworks, make the work of developers significantly easier and also provide corresponding test frameworks. At Publicare, we use test frameworks like this in Laravel (PHP, PHPUnit), vue.js, APEX (Salesforce) and golang.
For example, if someone wants to initiate deployment processes in Salesforce Sales Cloud using APEX code, they can’t avoid writing tests. If a minimum test coverage prescribed by Salesforce is not met, or the tests fail, the deployment will come to a screeching halt.
But it’s different in Salesforce Marketing Cloud. The programming languages there, AMPScript and SSJS, and the available platform libraries do not support test-driven development. There are also no requirements to write tests, either within CloudPages or automation scripts. The code required within the platform could theoretically be considered as not being very complex. But, practically speaking, development in Salesforce Marketing Cloud has a professional minimum standard in terms of approach and quality. There are multiple reasons for this:
- Errors in processes lead to potential data losses, for example in newsletter registrations, unsubscribing from mailing lists or transfers to third-party systems.
- Badly structured code presents problems in keeping track of changes to customer requests, which means it has to be completely redeveloped.
- Performance bottlenecks are difficult to detect in a messy “spaghetti code”.
- Maintaining this kind of code is complex and costly.
To avoid all of this, or to minimize the risk as much as possible, we also use test-driven development in Salesforce Marketing Cloud. But what can we actually do within the platform and, above all, how can we do justice to our own standards of professionalism with SSJS – a language that is based on the ECMA3 specifications published in December 1999 and that is therefore a relic from the last millennium? As a digital marketing agency, this question has been keeping us busy ever since our first project in Salesforce Marketing Cloud. Time and time again, we’ve adapted our own design patterns in this area and implemented them in a platform-specific way. The following key elements have supported us in implementing test-driven development.
DRY – Don’t Repeat Yourself
We structure code in the Marketing Cloud in an object-oriented way, but without ongoing inheritance. In this instance, objects are a cluster of methods and aim to make the paradigms or approaches more comprehensible when reading the code. To give an example: we often use a “controller” object (objects created by us begin with a “_” in the code, to avoid any naming conflicts later in the process). The controller possesses functions for processing requests (reading parameters, mapping parameters against a data extension, etc.). Because we use this object more often in CloudPages, which we employ in projects, we do not reimplement the object in each CloudPage. However, if there were a bug or a change needed for some other reason, we would have to manually update each CloudPage, which requires both time and patience.
Instead, we implement the reusable code in code snippets and ensure it is imported in CloudPages. This means we only have to make changes to the code in one place. The imports are similar to their equivalent in golang:
import (
“fmt”
“github.com/badoux/checkmail”
“github.com/devfacet/gocmd”
)
or the equivalent in PHP
use AppAbstractsDataExtensionDescriptionJob;
use AppBusinessUnit;
use AppData Extension;
use AppMarketingCloudReadDataExtensionReader;
This is also the first step in testing the code. Were we to work exclusively via copy and paste, we’d be unable to eliminate errors and would have no idea what a professional code-based test scenario needs to look like.
Make It Configurable
It’s assumed that you have to write a method for filtering contact data out of a data extension. In the context of SOAP, in order to do this, it’s necessary to explicitly specify the columns being accessed. This is no problem given that the method isn’t difficult to implement. The ID, EmailAddress, FirstName and LastName columns are entered as arrays in the request, as is the CustomerKey of the data extension. But in the next step, the written code is transferred to an additional business unit of the customer, which would also like to access the functionalities. However, in this second business unit, the columns to be called up are ID, EmailAddress and City, and the CustomerKey of the data extension is of course different. From this point on, you would have a method with two different paths across the various business units, although the intention of the method is always the same – from a code perspective, they are two parallel tracks. “n” further business units may also be added down the line.
From a maintenance perspective, this approach is clumsy; it’s better to work with variables. Here, both the CustomerKey of the data extension and the columns being queried become configuration variables in the code snippet; so, the path of the method remains the same. When deploying to other BUs, only one configuration variable must be modified per BU; the rest can be adopted as is.
These configuration variables are a critical component for testing database operations within the scope of test-driven development in Salesforce Marketing Cloud.
Test-Driven-Development
The execution of the first two patterns, “DRY – Don’t Repeat Yourself” and “Make It Configurable”, also allow us to adapt test-driven development as effectively as possible. Because we don’t have a terminal, we instead need to opt for implementation within CloudPages and express our test cases visually – if it’s green, it’s good
With the first pattern, “DRY – Don’t Repeat Yourself”, we’re able to integrate the code base already used by the other CloudPages in the test suite CloudPage. If something in the code base changes, the tests must continue to run successfully – or the changes will be defective too. By the way: to be able to execute changes like these without disrupting live operations, we save each version of the code base elements. A new version must first be validated by the test suite before it can be integrated by the controllers.
Because we share the URL of the test suite CloudPage and the tests can be initiated by any project participant at any time, it would make no sense to run data extension-based tests against the live database. But unfortunately, Salesforce Marketing Cloud does not understand the concept of live database versus test database. These kinds of distinctions simply don’t exist. This is where the “Make It Configurable” pattern helps. Before we request methods in the test suite for tests, we ensure that the configuration variables of the data extensions used are overwritten – so instead of potentially live data extensions, we use a model of the actual data extensions for testing purposes during development. This is also an extremely useful way to debug processes without disrupting live operations.
Everything else is then “normal” development work: writing methods, and developing and executing tests for them. From our perspective, this form of development is extremely reassuring: the better we write the tests, the more certain we can be that our software fulfils its purpose. However, if we test complex processes manually (which took a long time before the tools in Salesforce Marketing Cloud were created), it’s not only stressful (because it often requires many mouse clicks), it’s also extremely time-consuming – because with every change, the test must be restarted from the beginning to look for potential crossover effects.
But what should we do about special logic in individual business units?
One potential weak point, when modelling cross-business unit methods, are the exceptions from the rule. To enable us to model cross-business unit methods despite special logic, we’ve chosen to implement event objects. An event can occur in a method. It consists of an event name and an event data object, with both transferred from the method to the fire method of the event. From a method perspective, nothing more is needed. For example:
_Event.fire(“Contact.subscribed”, {Contact: Contact})
If the process is concluded in business unit A, but there is a request in business unit B to send a welcome email to the contact, shared use of the method code remains possible. In business unit B, code is added – a “listener” – which stands in an additional code snippet. A listener is a function that responds to to an event with a specific name. Each event can have a limitless number of listeners. In the code snippet, the listener and its callback function must be registered with the corresponding event:
var listenerFunction = function(eventData) {
var Contact = eventData.Contact,
//… logic here
}
_Event.addListener(“Contact.subscribed”, listenerFunction)
A welcome email will then be triggered in this listener and dispatched to the address of the contact.
This principle might seem straightforward, but it also provides plenty of leeway for modelling code across different business units because you work out the similarities and then process the specific characteristics for each event.
Outlook
In addition to the patterns described here, we have developed a range of other working methods that influence the approach we use to implement individual extensions in Salesforce Marketing Cloud. We strive throughout for a professional, modern and, above all, reliable implementation.
A well-structured code is the basis for every effective process. Projects in Salesforce Marketing Cloud will also be able to accommodate any recurring change requests from clients if they are clearly coded – which significantly simplifies maintenance and optimization of these processes.
If you would like to know more about this topic or are looking for professional services in this area, we’d be happy to advise you.