wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Backing up Salesforce Meta data


Clicks not code makes the Salesforce Admin a super hero, but might send jitters through the compliance and change management team's combined spines. How can you track all of these changes?

Tracking changes

Salesforce does record, when configured, changes in setup for 180 days. The format is a log that isn't actionable (e.g. rollback). An alternative to the build in function is BlueCanvas that stores meta data automatically into a git repository. It's part of their developer focused solution that also handles the deployment and rollback of source code

Downloading meta data

When you are not ready (or haven't allocated a budget yet) to fully automate this, there's a do-it-yourself alternative. A few steps:

  • Make sure you have Java8 installed
  • Deploy the Salesforce Ant Migration tool
  • Download and deploy into your path PackageBuilder.jar developer by my colleague Kim Galant
  • create a build.properties file (see below)
  • create a build.xml file (see below)
  • run the fetchSrc.sh shell command (see below)

PackageBuilder will, when called with no instructions read ALL meta data and create one or more package.xml files. Once created you can use ANT to retrieve the data.


Read more

Posted by on 08 November 2018 | Comments (0) | categories: Java Salesforce

Lightning Mini Forms


One of my favorite lightning features is the Lightning App Builder. It allows to tailor Salesforce for a given set of users, to show what they need, how they need it.

In the page editor the endless scrolling page, record details followed by related lists, we got to love, can be broken down into multiple tabs. For related lists, the OOTB controls already allow to just pick one. Placed multiple times on a page, the layout can fit a specific audience's precise need, avoiding information overload.

However there's no control to break down the record details. The OOTB record details control will faithfully reproduce the assigned page layout with all sections. Custom controls to the rescue!

Design options

There are two options to consider: where to pull design information from and how to render it. For the later you can consider lightning:recordEdit|ViewForm or lightning:recordForm. Both can be argued for.

The lightning:recordForm only needs the fields / layout options supplied and will take care of all rendering. However you are limited to one or two columns - just like page layouts.

The lightning:record[Edit|View]Form requires coding the fields, probably using an aura:iteration, but leaves you with the freedom of layout. Typically you would use a lightning:layoutItem and its size property to determine the number of columns (with 12 / size = number of columns).

To keep it simple I'll stick to the lightning:recordForm for now.

Next question: where to provision the list of fields from? When you want an universally usable mini form, you can't hardcode them, but provide them using a design property, so they can be provided in the page editor after you dragged the component onto the page.

Still you need to decide what attributes you provide:

  • List of field names
  • Name of a field set
  • Name of a section in a page layout

I'll start with the first one and relegate the other two approaches to future posts.

To make this work you will need a custom lightning component. Let's call it MiniForm. We will only need MiniForm.cmp, MiniFormController.js and MiniForm.design. No helper or Apex will be harmed.


Read more

Posted by on 06 November 2018 | Comments (0) | categories: Lightning Salesforce

My software stack


From time to time the question pops up: what's your software stack? I use cloud based tools like LucidChart, GitHub, Bitbucket and various other SDLC related tools (subject to a future post), but still quite a number of locally installed tools.

The essentials

Tools I use on, more or less, daily basis:


Read more

Posted by on 31 October 2018 | Comments (1) | categories: Software WebDevelopment

Creating a Lightning Service


When you develop in Lightning your client side architecture can benefit as much as the server from a separation of concerns. The component library is testimony to that.

Out of the box services

The Component Library features a growing number of services:

Building your own

There is more than one way to skin you cat. You can do:

  • Lightning Style
    Philippe Ozil described in detail how to use and create your own services ?lightning style'. You should check out his Server Side Actions Service that allows you cut down on boiler plate code substantially
  • JavaScript Style
    Establish a global service extending the Window object
  • ES6 Style
    Import a JavaScript module. This would need to setup Babel - not too practical for now

Extending the window object

When you extend the window object, which is the browser's top level object, the service becomes available "standalone", like alert() (which is actually window.alert()). A service could look like this:

window.demoLib = ( function() {
	let someMethod = () => {
		return 'Something'
	}

	let helloMethod = (paul) => {
		return `Hello ${paul}`;
	}

	return {someMethod, helloMethod};
}());

This will now provide you with demoLib.someMethod() returning Something and demoLib.helloMethod('World') returning "Hello World". The final step to enable such a library is to add ltng:require to your components: <ltng:require scripts="{!Resource.demoLib} afterScriptLoaded="someMethodIfRequired" /> presuming you stored your JS in resources as demoLib.js. The Aura framework will make sure that the library is loaded once only, regardless how many components define it as dependency.

What can go wrong?

There are a few caveats:

  • For hard core Apex developers: JavaScript is case sensitive
  • You need to be clearly communicating service names to other developers in your org. If someone has the idea to name a library the same as yours, things will break. Good practice is to check if your library and function is available: if (window.demoLib && window.demoLib.someMethod) {...}
  • Fat arrow functions () => {...} are not supported in legacy browsers, so you need the slightly more verbose function(){...} (beware the this keyword behaves different then).

As usual YMMV


Posted by on 19 October 2018 | Comments (0) | categories: JavaScript Lightning Salesforce

Structuring a Proof of Concept


A common practise in IT, as run up to a sale or a project is to proof that the intention of the undertaking can be fulfilled.

The challenge

A PoC needs to strike a challenge between effort and coverage. A final proof of a project is its completion, so the temptation lures to try to proof everything. On the flip side: if they core functionalities aren't covered the proof has little value.

The second challenge is to define concise successs criteria. Quite often, especially for standard product PoC, it is left to ?how users like it' - which isn't a really qantifiable result.

Use cases

A workable approach is to define use cases, that cover a typical scenario, like ?Sale of an ice cream'. This scenario needs to be broken down into business steps until a step can be looked at: ?did work / did not work'.
The breakdown needs to be business level, business language. So ?Can click on customer info' should rather read ?Customer info is retrievable'.

Use cases and steps are hierarchical, typically 2-3 levels are sufficient for most PoC. Deeper levels are a smell that you are looking at a pilot or full fledged project, not a PoC.

So, in a nutshell: A PoC line item needs to have a binary answer. If a binary answer isn't possible break the line item into smaller units. Stick to the domain specific language (usually: the business steps)

Measurements

When a use case line item has a binary outcome (works / doesn't work), the simplest measure is to check if everything worked to declare the PoC a success. Usually doesn't help.

The next level is to define a pass percentage. Like 70% of 200 line items must pass. Again a simple solution. Challenge there: nice to have and essential features have equal weight. You could end with an outcome that has all nice-to-have features, but might miss essentials.

So the next level is to define weights for each items, including a showstopper flag for must-have features. Weighting discussions are popular battle grounds for feuding fractions, since the weight determines outcomes, especially for concurrent PoC execution.

Another weakness of this approach: works/doesn't work as binary value doesn't cover: ?Does it work well?'. Like ?Is a pair of sneakers suitable to get from Boston to New York?' The binary answer: Yes you can walk, but the real answer: use a car, train, bus or plane.

Balanced Scorecard to the rescue

Looking at the definition of Usability, one can find 3 criteria:

  • Does it work?
  • Is it efficient?
  • Is the user pleased?

I would treat the first column as a binary value and the later two as scales from 1-5. This allows to generate a balanced score card that reflects important aspects of a proof. Depending on the nature of the system, you could add additional columns like ?failure resistance, error recovery, risk'.

While it doesn't relieve you from the weight bickering, it provides a clearer picture of actual outcomes.

As usual: YMMV


Posted by on 04 October 2018 | Comments (2) | categories: Salesforce Software

Adding Labels to Lightning Datatable


In Part 1 I described a way to make any SOQL result fit for use in a Datatable. The next step is to provide column labels. While it would be easy to just hardcode them, Abhishek suggested to use the original field names. The beauty of that approach: The admin can adjust and/or translate field labels without touching the code.

Going Meta

APEX has a rich API that allow querying an object's properties in the Schema name space. Getting the information for a collection of objects can be done using Schema.describeSObjects(sObjectTypes) or Schema.getGlobalDescribe() (see details here).

The interesting challenge is to find the object names of the relationships, the default field list will only tell you the name you gave it, but not the object you relate to. So some more code is required (see below).

Relationship fields can be identified by the part before the . either ending in __r or id. So we break a query apart and extract a List<String> for the field name and a String for the start object name. Our scenario doesn't cater to subqueries. These two parameters get fed into a utility function.

public without sharing class AuraLabelHelper {
    
    private static Map<String, Schema.SObjectType> globalDescribe = Schema.getGlobalDescribe();
    
    public static Map<String, String> retrieveFieldLablesFromFieldList(List<String> fieldList, String objName) {
        Map<String, String> result = new Map<String, String> ();
        Map<String, Schema.SObjectField> fieldDefinitions = internalFieldLablesFromFieldList(fieldList, objName, '');
        for (String key : fieldDefinitions.keySet()) {
            DescribeFieldResult dfr = fieldDefinitions.get(key).getDescribe();
            result.put(key, dfr.getLabel());
        }
        return result;
    }
    
    
    private static Map<String, Schema.SObjectField> internalFieldLablesFromFieldList(List<String> fieldList, String objName, String prefix) {
        Map<String, Schema.SObjectField> result = new Map<String, Schema.SObjectField> ();
        Schema.SObjectType objectType = AuraLabelHelper.globalDescribe.get(objName);
        Schema.DescribeSObjectResult describeResult = objectType.getDescribe();
        // Labels for the top level object - needs to be lowercased  
        Map<String, Schema.SObjectField> fieldMap = describeResult.fields.getMap();
        Map<String, Schema.SObjectField> fieldMapLower = new Map<String, Schema.SObjectField> ();
        
        for (String key : fieldMap.keySet()) {
            fieldMapLower.put(key.toLowerCase(), fieldMap.get(key));
        }
        
        for (String fieldName : fieldList) {
            String fieldNameLower = fieldName.toLowerCase();
            if (fieldMapLower.containsKey(fieldNameLower)) {
                result.put(prefix + fieldNameLower, fieldMapLower.get(fieldNameLower));
            } else if (fieldNameLower.contains('__r.')) {
                // We have a potential relationship field at hand
                String relationFieldName = fieldNameLower.left(fieldNameLower.indexOf('__r.')) + '__c';
                Schema.DescribeFieldResult relationDescribe = fieldMapLower.get(relationFieldName).getDescribe();
                Schema.SObjectType reference = relationDescribe.getReferenceTo().get(0);
                String objApiName = reference.getDescribe().getName();
                List<String> subFieldList = new List<String> ();
                String newPrefix = prefix + fieldNameLower.left(fieldNameLower.indexOf('.'))+'_';
                subFieldList.add(fieldNameLower.substring(fieldNameLower.indexOf('__r.') + 4));
                result.putAll(internalFieldLablesFromFieldList(subFieldList, objApiName, newPrefix));
            }
        }
        
        return result;
    }
}

Good boys and girls create a test class:

@IsTest
public class AuraLabelHelperTest {

    @IsTest
    public static void simpleAccountTest() {
        List<String> fieldNames = new List<String> ();
        fieldNames.add('Id');
        fieldNames.add('Name');
        fieldNames.add('Customer__c');
        fieldNames.add('Customer__r.Name');

        Map<String, String> result = AuraLabelHelper.retrieveFieldLablesFromFieldList(fieldNames, 'Address__c');
        System.debug(result);
        System.assert(result.containsKey('id'));
        System.assert(result.containsKey('customer__r_name'));

    }

}

Next stop is putting it all together. As usual YMMV.


Posted by on 31 August 2018 | Comments (0) | categories: JavaScript Lightning Salesforce

Lightning Datatable and Relationship Queries


The Lightning Datatable is a flexible component to show data in a sortable, actionable table. Formatting is automatic provided by the Lightning Design System. Data gets provided as JSON array.

The challenge

A prime use case for a data table is to show results returned via @AuraEnabled from a SOQL query. Ideally relationship identity fields should turn into links and data from relationship queries (something like MyCustomObj__r.Color) should be usable in the table as well.

The tricky part: Relationship fields are returned (IMHO properly) as JSON objects. Datatable can't deal with object values for their columns. A returned value might look like this (deliberately using a generic example):

[{
  Id: 'payloadid',
  Color__: 'Blue',
  Stuff__r: {
    Id: 'ToyId',
    Name: 'Teddy',
    Price__c: 34.5,
    Shape__r: {
      Size__c: 'XL',
      Geometry__c: 'round'
    }
  },
  Dance__c: 'Tango'
}];

Read more

Posted by on 29 August 2018 | Comments (0) | categories: JavaScript Lightning Salesforce

Designing Lightning Components for Reuse


This is a living document about a common sense approach to developing reusable Lightning components. It might change over time.

Salesforce documentation

As well as the instance specific component library

Principles

  • Components shall serve a single purpose, designed for reusability
  • Components shall use the most feasible least code approach
  • Components shall not contain country specific logic in the front-end
  • Components shall be documented and tested
  • Components shall use composition over inheritance. Inheritance is NOT forbidden, use it wisely
  • Components shall observe case sensitivity even for non case sensitive item (e.g. field names)
  • Components shall prefer component markup over html markup (e.g. lightning:card over div class="slds-...")
  • Components shall use component navigation (if navigation is needed)

Naming

Related files and components need to be named so they appear close to each other. E.g. a component "VehicleInfoList" that depends on inner components. Those would also start with "VehicleInfo" e.g. "VehicleInfoCard" "VehicleInfoLineItem", "VehicleInfoInterested" etc.
Files should be named like this:

  • SalesProcess.cmp
  • SalesProcessController.js
  • SalesProcessHelper.js
  • SalesProcess[WhatEvent].evt
  • SalesProcess.SVG

Interfaces

  • A component shall only implement the interfaces that it actually uses.
  • A component that relies on a current record, shall not use "availableForAllPageTypes" and must implement "hasRecordId" and the attribute "recordId".
  • Components that are not used on a page layout, but rather inside other components shall not implement interfaces ("availableFor?") that make them appear in the page editor
  • Components shall only implement the interfaces they actually use. Avoid interfaces the component "might use in future"

Data access

Components shall use the "least code" principles for data access. To be checked in this sequence:

  1. Does the component need data access or can the attributes of it provide all the input it requires?
  2. Can lightning:recordForm be used?
  3. Can lightning:recordEditForm and lightning:recordReadForm be used?
  4. Can force:recordData be used?
  5. Is a custom @AuraEnabled method in the controller needed for data provision?

This doesn't preclude fetching Meta data or configuration. Ensure to use storable actions where feasible. More principles:

  • Use data change handlers where appropriate
  • Use component events

Code principles

This section probably will expand over time

  • Code needs to be readable
  • The controllers (both client and server side) shall be light modules that marshall actual work to helper classes and helper functions
  • In Apex helper classes shall be instantiated using factory classes - this allows intoducing country specific behavior
  • All Apex helper classes shall be based on Interfaces
  • Methods and functions shall be single purpose and not exceed a page size. Break them down (makes them more testable anyway) if to big
  • Don't copy/paste
  • Run PMD (free download) on all Apex (eventually on JavaScript too)
  • Operations that can fail need to be handled with try/catch or its equivalent
  • Use @ApexDoc and @JSDoc style comments

Testing

  • All components need test code: both for Apex (natural) and the client side component.
  • A component is incomplete without a "Lightning testing service" test.
  • Use assertions generously!

Documentation

  • Lightning components have a description
  • Each lightning component comes with a documentation section - don't waste time documenting them outside Salesforce.
  • Use the documentation to briefly explain what it does (no Pulitzer price for this writing!).
  • Include at least one example in the documentation

Parameter

  • Components that can be dragged onto a page can benefit from having parameters the page maintainer can use to configure the component, thus increasing reusability and limit the number of components that need to show up in the palette.
  • Parameter documentation - Check the documentation for details.
  • If a component is usable only for a specific object page, add that to the Design Resource.

As usual YMMV


Posted by on 26 July 2018 | Comments (1) | categories: Lightning Salesforce

Postman and the Salesforce REST API


The Salesforce API is a great way to access Salesforce data and can be used with tools like SoqlXplore or the Salesforce Workbench. The API uses OAuth and a Bearer Authentication, so some steps are required to make that work in Postman

Prepare Salesforce

You will need a connected APP. I usually create one that is pre-approved for my user profile(s), so I don't need to bother with the approval steps in Postman. However you could opt for self-approval and access the app once to approve its use, before you continue with the command line. Note down the ClientId and ClientSecret values.

Prepare Postman

Postman has great build in support for all sorts of authorization interactively. However my goal here is to fully automate it, so you can run a test suite without manual intervention. First stop is the creation of one environment. You can have multiple environments to cater to different Salesforce instances.

Important Never ever ever store the environment into version control. It would contain credentials -> bad bad idea!

My environment variables look like this:

{
	"CLIENT_ID" : "the ClientId from Salesforce",
	"CLIENT_SECRET" : "The ClientSecret from Salesforce",
    "USER_ID" : "some@email.com",
    "PASSWORD" : "DontTell",
    "LOGIN_URL" : "https://login.salesforce.com/"
}

Providing the Login URL allows to reuse postman collections between Sandboxes, Developer Orgs or Production Orgs without the need to actually edit the postman entries. Next on the menu: getting a token


Read more

Posted by on 06 July 2018 | Comments (2) | categories: Salesforce Software WebDevelopment

Mime is where Legacy Systems go to die


Your new system went live. Migration of current, active data went well. A decision was made not to move historic data and keep the old system around in "read-only" mode, just in case some information needs to be looked up. Over time your zoo of legacy systems grows. I'll outline a way to put them to rest.

The challenges

All recent systems (that's younger than 30 years) data is stored more or less normalized. A business document, like a contract, is split over multiple tables like customer, address, header, line items, item details, product etc.

Dumping this data as is (csv rules supreme here) only creates a data graveyard instead of the much coveted data lake or data warehouse.

The issue gets aggravated by the prevalence of magic numbers and abbreviations that are only resolved inside the legacy system. So looking at one piece of data tells you squid. Only an old hand would be able to make sense of Status 82 or Flags x7D3z

Access to meaningful information is confined to the user interface of the legacy application. It provides search and assembly of business relevant context

The solution approach

Solving this puzzle requires a three step approach:

  • denormalize
  • transform
  • make accessible

Read more

Posted by on 22 June 2018 | Comments (1) | categories: Software Technology