Friday, April 22, 2016

Real Time Workflow or Plugin?


I have been asked "should I use Real Time Workflows instead of Plugins?" many times since CRM2013 first introduced this valuable new feature. Real Time Workflows (RTWFs) certainly have many attractive benefits over Plugins including:
  • Uses the same interface as standard workflows making it very quick & simple to perform straightforward tasks.
  • Can be written & extended without coding skills
  • Easily extend using custom workflow activities that can be re-used in many places.
If we can use custom workflow activities to extend the native workflow designer functionality (e.g. making updates to records over 1:N and N:N relationships) then it raises the question why should we use Plugins at all?
I am a big fan of RTWFs – they add considerable power to the framework that ultimately makes the solution more effective and lowers the implementation costs. That said I still believe that considering plugins is still an important part of any Dynamics CRM Solution design - the reasons can be split into the following areas:

Performance

Performance is one of those areas that it is very tempting to get bogged down by too early by 'premature optimisation'. In most cases performance should be considered initially by adhering to best practices (e.g. not querying or updating more data than needed) and ensuring that you use supported & documented techniques. If we ensure that our system is structured in an easy to follow and logical way then Dynamics CRM will usually look after performance for us and enable us to scale up and out when it is needed (Dynamics CRM Online will even handle this scaling for you!). It is true there are some 'gotchas' that are the exception to this rule, but on the whole I think primarily it is better to design for maintainability and simplicity over performance in the first instance. Once you have a working design you can then identify the areas that are going to be the main bottle necks and then focus optimisation efforts on those areas alone. If we try to optimise all parts of the system from the start when there is no need I find that it can actually end up reducing overall performance and end up with an overly complex system that has a higher total cost of ownership.
It is true that Plugins will out performance RTWFs in terms of through-put but if the frequency of the transactions are going to be low then this usually will not be an issue. If you have logic that is going to be firing at a high frequency by many concurrent users then this is the time consider selecting a plugin over a RTWF.
In some simple tests I found that RTWFs took twice (x2) as long as a Plugin when performing a simple update. The main reason for this is that the plugin pipeline is a very efficient mechanism for inserting logic inside of the platform transaction. A RTWF inserts an additional transaction inside that parent transaction that contains many more database queries required to set up the workflow context. The component based nature of workflow activity steps means the same data must be read multiple times to make each step work in isolation from the others. Additionally, if you update a record in a RTWF, it will apply an update immediately to the database within this inner transaction. This database update is in addition to the overall plugin update. Using a plugin there will only be a single update since the plugin is updating the 'in transit' pipeline target rather than the database. 

Another reason that the RTWF takes longer to complete the transaction is that it appears to always retrieve the entire record from the database even when using only a single value.

Pre/Post Images

When using plugins you have a very fine control over determining what data is being updated and can see what the record looked like before the transaction and what it would look like after the transaction. RTWFs don't offer you this same control and so if you need to determine if a value has changed from a specific value to another specific value (say a specific state transition) it is harder to determine what the value was before the workflow started. When a RTWF reads a record from the database, it will load all values, but with a plugin you can select only a small number of attributes to include in the pipeline or query.

Impersonation

RTWFs allow you to select whether to run as the calling user or the owner of the workflow, where a Plugin gives you full control to execute an SDK call as the system user or an impersonated user at different points during the transaction.

Code vs Configuration

With RTWFs your business logic tends to become fragmented over a much higher surface area of multiple child RTWFs. This makes unit testing and configuration control much harder. With a plugin you can write unit tests and check the code into TFS. With every change you can quickly see the differences from the previous version and easily see the order that the code is executed.
I find that it is good practice to have a single RTWF per triggering event/entity combination and call child workflows rather than have many RTWFs kicked off by the same trigger, otherwise there is no way of determining the order that they will execute in.
A very compelling reason to use plugins is the deterministic nature of their execution. You can control the order that your code executes in by simply sequencing the logic in a single plugin and then unit test this sequence of events by using a mock pipeline completely outside of the Dynamics CRM Runtime.

So just tell me which is best?!

Which is best? Each have their strengths and weaknesses so the answer is "it depends" (as it so often is!).
After all this is said and done – a very compelling reason to use RTWS is the fact that business users can author and maintain them in a fraction of the time it takes to code and deploy a plugin and often will result in far fewer bugs due to the component based building blocks.
As a rule of thumb, I use two guiding principles:
  1. If there is already custom plugin code on an entity (or it is planned), then use a plugin over a RTWF to keep the landscape smaller and deterministic.
  2. If you know up-front that you need a very high throughput for a particular function with a high degree of concurrency, then consider a plugin over a RTWF for this specific area.

1 comment: