Jekyll2023-11-26T20:10:25+01:00https://www.robertvejvoda.net/feed.xmlRobert’s blogI love development on .NET platform and occasionally blogging about it. Recently I focus on Dapr and Camunda and share learnt lessons.Robert VejvodaCustomer scoring with Camunda synchronous workflow2023-11-26T18:20:32+01:002023-11-26T18:20:32+01:00https://www.robertvejvoda.net/dev/customer-scoring-with-camunda-workflow<p>Within this demo we’re going to see once again how Dapr and Camunda Platform 8 works well together and provide language agnostic approach.
In this case with focus on synchronous workflow processing which can be triggered by REST calls.</p>
<p>Workflow handles a request to score customer according to his/her history and current monthly income.
Scoring result could be used later for pricing or similar.</p>
<p>Project with this demo is available on <a href="https://github.com/RobertVejvoda/customer-scoring-camunda">GitHub</a>.</p>Robert VejvodaWithin this demo we’re going to see once again how Dapr and Camunda Platform 8 works well together and provide language agnostic approach. In this case with focus on synchronous workflow processing which can be triggered by REST calls.Another demo of Dapr and Zeebe (Camunda)2023-06-04T19:35:40+02:002023-06-04T19:35:40+02:00https://www.robertvejvoda.net/dev/dapr-zeebe-demo<p>After some time I went back to Dapr (v10) and Zeebe engine used in Camunda Platform 8. Updated projects to .NET 7 and tried again what I learned before and realized, I have to look back and refresh my memories. Some are like trying from scratch again.</p>
<p>I noticed few changes:</p>
<ol>
<li>Controllers must return a value, otherwise ends with JSON parsing issue. For empty ones I used something like NullResponse class.</li>
<li>The method return value is automatically posted back to Camunda and becomes global.</li>
<li>To follow REST rules and versioning, JobTypes and Controller names must be exactly as implemented here.</li>
<li>There is a great Nuget <a href="https://www.nuget.org/packages/Man.Dapr.Sidekick.AspNetCore">Dapr Sidekick</a>, thanks guys for that!</li>
</ol>
<p>Project with this demo is available on <a href="https://github.com/RobertVejvoda/dapr-zeebe-demo">GitHub</a>.</p>Robert VejvodaAfter some time I went back to Dapr (v10) and Zeebe engine used in Camunda Platform 8. Updated projects to .NET 7 and tried again what I learned before and realized, I have to look back and refresh my memories. Some are like trying from scratch again.Greetings to Camunda, Zeebe and Dapr!2022-11-17T15:22:40+01:002022-11-17T15:22:40+01:00https://www.robertvejvoda.net/dev/greetings-to-camunda-zeebe-dapr<p>It’s awesome to see how Dapr and Camunda workflow engine work well together. By using BPMN and DMN we completely remove business logic from the code and only expose APIs to bind calls from Dapr Zeebe binding. The project can be found on <a href="https://github.com/robertvejvoda/greetings-camunda">GitHub</a>.</p>
<h2 id="story---the-business-process">Story - the business process</h2>
<p>Expecting a sad person having difficulties learning a new language and it would make her happier if someone greets her. But depending on her learning skills (Score Person Learning Curve) she may desire the greeting or not. If her score is more than 30% she receives greeting by email. If less, it generates a business error and sends email to administrator. Yes, cruel world.</p>
<h3 id="bpmn-workflow">BPMN Workflow</h3>
<p><img src="https://github.com/robertvejvoda/greetings-camunda/raw/main/greeting_workflow.png" alt="BPMN Workflow" /></p>
<h3 id="decide-how-to-greet">Decide how to greet</h3>
<p><img src="https://github.com/robertvejvoda/greetings-camunda/raw/main/greeting_dmn.png" alt="DMN Business Rules" /></p>
<p><img src="https://github.com/robertvejvoda/greetings-camunda/raw/main/decide_greeting_dmn.png" alt="DMN" /></p>
<h2 id="example">Example</h2>
<p>Since Dapr does all the hard work, we’re left with only few tasks to do. See the full solution on <a href="https://github.com/robertvejvoda/greetings-camunda">GitHub</a>.</p>
<p>Run infrastructure docker compose to start</p>
<p><img src="/assets/images/blogs/docker-desktop-camunda.png" alt="Docker Desktop" /></p>
<p>Using Camunda Modeler upload BPMN workflow to Camunda self-hosted instance</p>
<p><img src="/assets/images/blogs/camunda-upload.png" alt="Camunda upload" /></p>
<p>Have a config file to bind MQTT topic…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: greeting-request
namespace: greetings-camunda
spec:
type: bindings.mqtt
version: v1
metadata:
- name: url
value: mqtt://host.docker.internal:1883
- name: topic
value: camunda/greeting-requested
- name: consumerID
value: "{uuid}"
scopes:
- greetings-api
</code></pre></div></div>
<p>Have an API controller with endpoint…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/// <summary>
/// Receiving a message to MQTT pubsub and topic named "camunda/greeting-requested"
/// and it should start a new Camunda Greet process by invoking zeebe-command binding.
/// </summary>
[HttpPost("/greeting-request")]
public async Task<ActionResult> GreetingRequested([FromBody, Required] GreetingRequest request, [FromServices] DaprClient daprClient)
{
logger.LogInformation(request.ToString());
// serialize and deserialize request to get it into dictionary format.
var json = JsonConvert.SerializeObject(request, jsonSerializerSettings);
// start Camunda process by invoking a message to Camunda
await daprClient.InvokeBindingAsync<PublishMessageRequest, PublishMessageResponse>(Bindings.ZeebeCommand, Commands.PublishMessage,
new PublishMessageRequest("greeting-requested", request.GreetingId.ToString(), string.Concat("decide-greeting-", request.GreetingId), "10s", // TTL
JsonConvert.DeserializeObject<Dictionary<string, string>>(json)));
return Ok();
}
</code></pre></div></div>
<p>Build & start APIs</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose up -d --build
</code></pre></div></div>
<p>Run simulation from <em>sim</em> folder</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet run 10
</code></pre></div></div>
<p>Zeebe binding triggers a new process in BPMN workflow in Camunda</p>
<p><img src="/assets/images/blogs/camunda-operate.png" alt="Camunda Operate" /></p>
<h3 id="issues">Issues</h3>
<p>Throwing business error does not send the ErrorMessage to Camunda engine or at least it’s not accessible in “Send email to admin” task. Hence setting the property explicitly - feels a bit awkward to me.</p>
<p>Whatever I define in Input field is a string. Even though I’d expect it’s Time as on. Then using it in DMN diagram is impossible (or don’t know how) as it always ends with error comparing ValString and ValTime.</p>
<p><img src="https://github.com/robertvejvoda/greetings-camunda/raw/main/issue.png" alt="Issue" /></p>Robert VejvodaIt’s awesome to see how Dapr and Camunda workflow engine work well together. By using BPMN and DMN we completely remove business logic from the code and only expose APIs to bind calls from Dapr Zeebe binding. The project can be found on GitHub.Are your class constructors heavy?2021-09-20T10:21:34+02:002021-09-20T10:21:34+02:00https://www.robertvejvoda.net/dev/are-your-class-constructors-heavy<p>One of OOP principles says, that every class should enter valid states only. The bigger class it is, the harder to do. Typically we use class constructors so put class into that valid state. But it’s uncomfortable to have dozen of parameters as it becomes disorganized and difficult to use. Let’s say, your class is persisted to database, so typically has 2 constructors. First for a new instance and second one for the existing instance read from the database (and in that state). Hierarchical class structure adds even more complexity. How to simplify?</p>
<h3 id="example">Example</h3>
<p>Consider following example. We’re building a message queue and so it contains processing records. It can do anything, imagine it’s a job which is triggered at some point and results are written back to the database. The record has a message serialized in json, which tells the handler what to do, and then there is some message processor (handler of the message) responsible to deal with that. Retries counter is there to know how many times the processing failed in total or daily, and after xx fails it disables the job and notifies someone. The states are at least <em>New, Running, Finished, Failed</em>, etc..</p>
<p>On the SQL side:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE TABLE [dbo].[Processing](
[Id] [uniqueidentifier] NOT NULL,
[ProcessingId] [int] IDENTITY(1,1) NOT NULL,
[Message] [ntext] NOT NULL,
[ProcessingTypeId] [int] NOT NULL,
[ProcessingSubTypeId] [int] NULL,
[IsProcessing] [bit] NOT NULL,
[Retries] [int] NOT NULL,
[RetryCounter] [int] NOT NULL,
[IsEnabled] [bit] NOT NULL,
[StartDate] [datetime] NULL,
[FinishDate] [datetime] NULL,
[ProcessedDate] [datetime] NULL,
[ProcessingResult] [ntext] NULL)
</code></pre></div></div>
<p>… and domain object:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class ProcessingMessage
{
public ProcessingMessage(string processingType, string processingSubType, string message)
{
Id = Guid.NewGuid();
ProcessingType = processingType;
ProcessingSubType = processingSubType;
Message = message;
}
public ProcessingMessage(Guid id, DateTime? dateStarted, DateTime? dateFinished, DateTime? dateProcessed, string processingType, string processingSubType, string message, int retryCounter, int maxRetries, int retries, bool isEnabled, ProcessingResult result, bool isProcessing)
{
Id = id;
DateStarted = dateStarted;
DateFinished = dateFinished;
DateProcessed = dateProcessed;
ProcessingType = processingType;
ProcessingSubType = processingSubType;
Message = message;
RetryCounter = retryCounter;
MaxRetries = maxRetries;
Retries = retries;
IsEnabled = isEnabled;
Result = result;
IsProcessing = isProcessing;
}
// ...
}
</code></pre></div></div>
<p>The class has 2 constructors. Whilst the first constructor is not an issue and easy to use, the other is quite heavy. One solution is to break the class into several states, like <em>ProcessingMessageRunning, ProcessingMessageFailed</em>, etc. and have only relevant properties on each. <a href="https://en.wikipedia.org/wiki/State_pattern" target="_blank" rel="noopener">State pattern</a>. However, here it’s not worth the effort. Much simpler is <a href="https://en.wikipedia.org/wiki/Builder_pattern" target="_blank" rel="noopener">Builder pattern</a>. The idea is to leave the responsibility to correctly instantiate the class to someone else, who knows how. I always tend to have my Builder nested class so I can set private fields directly. Why not public methods or properties? Methods may have additional logic to keep your class in a valid state. Property setters are not public visible - almost never - again, don’t let anyone to change state of your class from outside directly.</p>
<p>Fluent interface then adds better readability to the code.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public class ProcessingMessage
{
private ProcessingMessage(Guid id, string processingType, string message, bool isProcessing, bool isEnabled)
{
Id = id;
ProcessingType = processingType;
Message = message;
IsProcessing = isProcessing;
IsEnabled = isEnabled;
}
public class Builder
{
private readonly ProcessingMessage message;
private Builder(ProcessingMessage message)
{
this.message = message;
}
public static Builder New(string processingType, string msg)
{
var pm = new ProcessingMessage(Guid.NewGuid(), processingType, msg, false, true)
{
IsEnabled = true
};
return new Builder(pm);
}
public static Builder Existing(Guid id, string processingType, string message, bool isProcessing, bool isEnabled)
{
var pm = new ProcessingMessage(id, processingType, message, isProcessing, isEnabled);
return new Builder(pm);
}
public Builder WithSubType(string processingSubType)
{
message.ProcessingSubType = processingSubType;
return this;
}
public Builder StartedOn(DateTime? dateStarted)
{
message.DateStarted = dateStarted;
return this;
}
public Builder TimesRetried(int totalRetries, int dailyRetries)
{
message.Retries = totalRetries;
message.RetryCounter = dailyRetries;
return this;
}
public Builder FinishedOn(DateTime? dateFinished)
{
message.DateFinished = dateFinished;
return this;
}
public Builder WithResult(ProcessingResult processingResult)
{
message.Result = processingResult;
return this;
}
public Builder WithResult(string jsonResult)
{
if (string.IsNullOrWhiteSpace(jsonResult))
return this;
message.Result = ProcessingResult.FromJson(jsonResult);
return this;
}
public ProcessingMessage Build()
{
return message;
}
}
}
</code></pre></div></div>
<p>Then it’s ProcessingRepository’s responsibility to retrieve data from database and create my domain object.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ProcessingMessage.Builder
.Existing(entity.Id, processingType, entity.Message, entity.IsProcessing, entity.IsEnabled)
.StartedOn(entity.StartDate)
.TimesRetried(entity.Retries, entity.RetryCounter)
.FinishedOn(entity.FinishDate)
.WithResult(entity.ProcessingResult)
.Build();
</code></pre></div></div>
<p>Again, important rule to follow is that your class should enter valid states only. Looking at the previous example we could say, when I call FinishedOn it should also have ProcessingResult as a parameter, because when the call is finished we must have some result.</p>Robert VejvodaOne of OOP principles says, that every class should enter valid states only. The bigger class it is, the harder to do. Typically we use class constructors so put class into that valid state. But it’s uncomfortable to have dozen of parameters as it becomes disorganized and difficult to use. Let’s say, your class is persisted to database, so typically has 2 constructors. First for a new instance and second one for the existing instance read from the database (and in that state). Hierarchical class structure adds even more complexity. How to simplify?Some thoughts and experience from implementing domain driven design2020-08-27T19:21:45+02:002020-08-27T19:21:45+02:00https://www.robertvejvoda.net/dev/some-thoughts-and-experience-implementing-ddd<p>A lot happened this and last year, so why not to share some thoughts and experience from implementing domain driven design on an existing monolithic application. Sounds like a nonsense already.</p>
<p><strong>Warning:</strong> it’s just a high level overview and probably will not make much sense without experiencing similar issues.</p>
<h3 id="about-the-project">About the project</h3>
<p>I’ve been mainly working on an ERP system called TCIS for a Czech manufacturing company engaged in processing metal sheets and profiles.The system consists of several modules like Customers, Suppliers, Base Items, Stock, Deliveries, Reporting and others.
pTechnically, backend it’s written in C#, .NET Framework 4.7, MS SQL database and Entity Framework as ORM, dependency injection everywhere.</p>
<p>Web frontend is written in <a href="https://www.dotvvm.com">DotVVM</a>, Javascript and is using SignalR, mobile frontend is in Xamarin and communicates with backend using web api and couple of external systems too.</p>
<p>To simplify typical common tasks used in forms (get list, display detail, update and save) we made a plugin to VS to design data using generators (dynamic data).
pSo the customer can even design and update forms directly by himself. All extendable with events of course.</p>
<p>The solution contains common patterns, like facades, services, repositories, separated data, business and presentation layer, all via interfaces and dependency injection, not bad at all.</p>
<h3 id="the-issues">The issues</h3>
<p>Now after a few years as the system grows up and business requirements are changing over time suddenly the system became very hard to maintain. One service now calls another service in a different context. Adding more if-else clauses only makes the problem worse. Changing one part of the application results in braking another part. Have you already been here as well?</p>
<p>So we decided to split functionality into modules (domains) in a microservice style, but with all the benefits from monolithic application for small teams (one solution, easier deployments). But to succeed, we must be very careful: Don’t touch code outside of your domain directly!But then, how to access data from another domain?</p>
<h3 id="ddd-and-cqrs">DDD and CQRS</h3>
<p>Reading data is simple. Use queries to retrieve data from the database (either from views or tables) and transform into some DTO objects.Updates are a bit more complicated, but not too much. Since we don’t want to use CRUD anymore, but strict DDD, there must be another DOMAIN layer to keep that logic.</p>
<p>Upon each change the domain object generates a domain event, which is handled by:
1/ event handler in repository - to persist changes to DB
2/ domain event handler - to perform another task. It can be whatever, some work on the same domain, enqueue a new integration event or something else.</p>
<p>Thanks to Jimmy Bogard and his <a href="https://github.com/jbogard/MediatR">Mediatr on GitHub</a>, which makes implementation very straightforward with Commands and Notifications.Many modules are now already separated and code is much easier to maintain.</p>
<h3 id="testing">Testing</h3>
<p>Since we now have simple domain objects without additional dependencies, unit testing becomes a lot easier! No excuses anymore.</p>
<h3 id="event-sourcing">Event Sourcing</h3>
<p>Thinking further. When all events have their own handles, why not to use event sourcing! The idea is it save the event first, then replay it.However, it’s a bit overhead on this project and doesn’t bring any customer value (apart of us geeks to try this juicy approach).We didn’t implement it.</p>
<h3 id="message-queue">Message Queue</h3>
<p>With an optimistic assumptions about importance of queues and amount of data being processed, I decided to build my own on SQL.After some time it turned out to be underestimated. I mean, it works fine, but not worth the effort and not bullet proof. I’d suggest to use some existing queue, even MSMQ, anything, custom queues will never be so perfect.</p>
<h3 id="lessons-learnt">Lessons learnt</h3>
<p>DDD is must simpler when starting from scratch. Implementing it into existing projects is very difficult.</p>
<p>Relational database is not the best option for DDD due to the fact, that it’s the aggregate root, which is loaded and it may spread across many tables (yes, we can always create views).</p>
<p>On the other hand, NoSQL databases are designed exactly for this purpose and may be a better choice.</p>
<p>With CQRS you can always build read model in relational SQL.</p>Robert VejvodaA lot happened this and last year, so why not to share some thoughts and experience from implementing domain driven design on an existing monolithic application. Sounds like a nonsense already.