This year’s hackathon at Systemite is now finished! The challenge trophy is handed over to a new winner, Thorsten Jakobsson, and we’ve had 24 hours with a lot of fun!
For you who wonder what a hackathon is, please have a look at the first minutes of the greeting that Mark Zuckerberg sent us (didn’t he, Thorsten?):
The purpose of the Hackathon is to give the employees the possibility to explore and do hacks in any area, technically or businesswise. It is a way to encourage innovation and build a positive team culture. To give some inspiration we’ve chosen to have a special theme, and this year it was:
Take SystemWeaver to new platforms!
Explore the possibilities of the new api’s!
During last six months we’ve developed a REST API making it possible to access most of the features in the system from any platform. We’ve also ported the C# API to .Net Core so it can be accessed from e.g. Linux-based platforms.
SystemWeaver is opened up in many new ways, and we’re very curious to find out how this will be used both inside and outside the company!
Below you find the time schedule during the hackathon: From forming teams, to announce a winner:
Several ideás came up, and there were two that seemed to attract most participants:
Integrate SystemWeaver with test rigs using Ubuntu running on Docker and the new .Net Core API.
“Not only SystemWeaver at your hands – but in you hand”. A SystemWeaver mobile app.
Participants were joining the both teams, a great mix of developers, business analysts and business consultants, and the work begun!
The next day, everybody presented their hacks! The app team, which was the larger one, had managed to develop an app that used the REST API with the following features:
Display a dashboard with issues and items assigned to you.
View tests and fill in test cases
A bot (“Anna”) answering questions about SystemWeaver.
Providing help and information about releases (prototype)
The Docker team showed an integration with a test rig:
Export tests from SystemWeaver to the integration service on the Docker instance.
Import the tests to the rig, and send them back.
When everybody voted the Docker team turned out to be the winners and will get their names engraved on the challenge trophy!
~ A great thank you everyone for an exciting and productive Hackathon! ~
Extra thanks to Thorsten Jakobsson, my co-organiser, and the excellent help with food and snacks from Jan Söderberg.
Most of us have an idea of what functional programming is, and have at least used some of the functional features of our best known programming language such as Lamba or LINQ in .Net.
When I’ve tried to learn more about functional programming, I’ve always felt that something is missing. There is a lot focus on the functions themselves, but less on where to put them in a structure. I’ve asked fellow programmers, but even if they seem very confident in writing functions, they get quite fuzzy when it comes to implementation of a real business problem, and how to structure the code.
Since I’ve used reactjs for many years I have one good example of how to implement a functional code design. But I have troubles applying these principles to the server side, or to see them as a more common approach. So I applied to a workshop at DDDEurope: Lean and functional modelling, with Marcello Duarte. This is what I learned:
You have to start with the programming
To understand the functional design you need to start with the programming. By understanding some of the most fundamental concepts in functional programming it will be easier to grasp the modelling part later. Now, I’ll probably not be the best to explain this after just two days of learning, but I can give you an overview of what you need to dig into. We used Scala for the programming exercises, but I think this is something that you can find in several languages and some of it maybe even in C#.
Higher order function: “A higher order function is a function that takes a function as an argument, or returns a function. Higher order function is in contrast to first order functions, which don’t take a function as an argument or return a function as output”. Higher order functions.
Composition and currying: “A curried function is a function that takes multiple arguments one at a time. Given a function with 3 parameters, the curried version will take one argument and return a function that takes the next argument, which returns a function that takes the third argument. The last function returns the result of applying the function to all of its arguments.” Curry and function composition
Monads: “A monad is a way of composing functions that require context in addition to the return value, such as computation, branching, or I/O. Monads type lift, flatten and map so that the types line up for lifting functions a => M(b), making them composable. It’s a mapping from some type a to some type b along with some computational context, hidden in the implementation details of lift, flatten, and map.” Monads made simple
Abstractions and compositions: “Software solutions should be decomposable into their component parts, and recomposable into new solutions, without changing the internal component implementation details.” Abstraction and composition
Thanks to Eric Elliot for the descriptions and examples above!
When trying to write clean code there are things that I sometimes stumble on, e.g. keeping the number of parameters down and writing pure functions without side effects. To use a more functional approach is making it easier to write clean code.
Functional architecture and design is often based on events and event-driven development. Concepts like event sourcing and CQRS can be considered as functional architectures. These architectures can of course be implemented (and is implemented) with any programming language and a wide range of technologies, but functional programming is very well suited for implementing this kind of architecture.
With event-driven development you identify a business flow and let the system reflect that flow. Data might change shape during this flow; for example in a purchasing domain you talk about a price of a product you buy, but in the finance domain the same amount is considered a cost of the same product. It is not just a different status of the product; it is considered a totally different thing.
A common way of identifying the business flow, is to do an event storming. At the event storming business events are identified, and also roles that are involved in firing the events, and the data that is sent. The team can do the event storming by themselves, but if possible, it is good to involve the business. The events, roles and data is written on post-its and put on the wall to illustrate the flow.
During the event storming it is important to avoid too much talk about implementation details (which is hard), and use cases (also hard). Try to focus on how the business work, the flow, and why things are done in a certain way. Look out for the core domain, and try to understand how it contributes to the business. It is important to understand what the business makes money of!
When the flow is defined it is possible to identify the services. One service should reflect one part of the business (domain). The data flows between the services in form of events, and very often the user roles indicate where it is suitable to draw the boundary of the service:
The services can be implemented in many different ways and they have their own databases or data stores. E.g. one is using a SQL database, while the other is using Eventstore and a CQRS approach. Since the services in this example is part of the same deployable unit there are some limitations when it comes to choosing languages and technology. Each service is responsible for its business rules, and don’t know anything about the others. Each service owns its own data.
In functional programming it is crucial to separate responsibilities into different parts of the code. This has spread to the object oriented systems too, so for many of us this comes very natural. The business logic is considered as the core of the system, and if you change technical implementations around it (database, client api’s etc.), it should be possible to leave the business logic untouched.
The flow throughout the system
The business logic implementation is composed of many independent functions which are called in a fluent way. I like to think of a system in the form of streams where the data flow and via projections and usage of different functions the data take different forms depending on what is should be used for. The flow sometimes temporarily stop waiting for input and is then saved in queues or databases. With event sourcing the flow could be reset and replayed at any time.
As a simple example, think about using LINQ or Lambda for filtering and mapping the the data that flows throughout the system. Then you’ve taken a big step. But try to think beyond that; can your own functions be written and applied to the flow in an even better way? Maybe, if we learn how to use the monads, functors etc. that was described earlier in this text.
As an object oriented programmer I have some difficulties to stop thinking in objects with methods and properties. One problem with objects is that the functions often have side-effects, such as reading or modifying a property. Then the outcome of that function might not always be the same, with the same in-data. Side-effects must be avoided to make the functions composable.
The data that shall be modified in a function must be sent in as a variable, be recreated with the changes applied, and then sent back as the result of the function. The data is immutable. For those of us that has worked with reactjs, we’re quite familiar with this.
Microservices is a way of separating a system into smaller autonomous parts. This can be done in many ways, but I’m most into the event-driven architecture and think that is at least a good start.
Every system I’ve been working with has started as a monolith. Some of them written in old languages like Cobol or Delphi, but some of them also in C#. What in a business that drives rewrite of a system is a separate discussion, but if these systems had been modularised in any way, it would have been so much easier (and cheaper) to step-by-step modernize them.
To be able to deal with technology changes of a system is a good reason to use a microservice architecture. To be able to rewrite business logic without affecting the whole system is another.
The possibility to deploy each service separately, has not made sense practically to me yet. Of course it depends on what type of system you’re working with. I think that to make sure that the services communicate using events (e.g. with pub-sub) and have separate data sources is much more important. This makes it easier to split the system if or when it is needed.
In an event-driven architecture, business events are identified e.g. using event storming. A business event can be something like when a booking is done or cancelled, or a hotel is available for booking. When a business event is published other subscribing services are triggered and performing their tasks.
The publishing service don’t know anything more than that e.g. a booking is done. And the subscribing service, let’s say an accounting service, has no idea of how a booking is made, only that it is done and it is time to perform the accounting tasks that it is responsible for.
An event-driven system is loosely coupled and asynchronous. The different services does not now anything about each others, and have no dependencies. In this way logic is isolated and has clear responsibilities. They can easily be deployed and scaled separately.
CQRS and event sourcing are ways of taking event-driven design further and think of, and store, every performed task in the system as an event. All except the read of the CRUD operations are saved as created, updated and deleted events. Of course business events are saved as events as well. You get the traceability of everything that has happened in the system. You also get the possibility to generate and regenerate read data in different forms depending on what’s needed.
Microservices is the way forward
Microservices tend to decrease complexity in systems when performing changes in each service. When you look at the whole, though, it might increase complexity. Especially if you’re going to deploy them separately. The infrastructure gets more complex and, for example, if you have different languages in the services, the developers need a broad range of skills.
I suggest that you try to think in generations if you have services in different technologies. Try to keep the number of different technologies down. Develop one bunch of services that are very similar to each other when it comes to structure and technology. When that technology is getting less popular or starts to feel outdated, begin a new generation of services with a new set of technology choices and continue with these for the next period of time. Maybe rewrite some of the old ones, if needed. And continue like this over the years.
From my perspective, microservices (either compiled together or completely separated) is the only way of making a system survive over time. Even the most modern, high tech technology eventually gets old-fashioned. If we don’t want to completely rewrite the whole system every 20th year, we have to split them into smaller units.
One benefit of continuously rewrite the parts of a system instead of rewrite it all at once is that it is easier to attract developers who tends to choose jobs where they get the possibility to work with new technology. I’m sure it is easier to find a python developer rather than a COBOL developer today, for example.
I found it rather common that developers have only a vague idea of what business logic is. I also sometimes find it hard to describe it myself, even though I’ve spent many hours of my career working with it.
So let’s try to clarify things. Business logic is core logic, that doesn’t have anything to do with technology. It is the logic that can be found as rules in the business even though there were no digital system implemented. What is considered as core to a business, is the activities that they gain money of.
Let’s take the example of a booking that gets cancelled. Business logic are the rules that kicks in with freeing up resources (hotels, cars or whatever is booked), confirm cancellation to customer, and refund money. Technically how this is done; by updating a database, which technology that is used to send an email or which payment solution that is called to refund the money, is not business logic. The technology should be exchangeable.
Business logic should be kept separate from the other logic in the system and it is worth a considerable effort to have a lot of automated testing here to verify that the rules are not broken.
Business rules vs. Use case
Business logic is often divided into two different types: Business rules and Use cases. First, I will address that there might be some naming confusion here, when it comes to business rule vs. business logic. The business rule is something that exists in the business even without a computer, while the business logic is the code that implements the rule.
When implementing business rules, it is very common that it is some kind of flow in which the rules are called. This flow can be implemented in something called Use case. Other names might be Service or Domain service.
Use cases are easily mapped to the requirements which are preferably defined as test cases. If implementing automated acceptance tests following the test cases you get a good assurance that the functionality that you have agreed with the customer or business is working.
Use cases are classes containing the flow for a use case. They can call repositories to save data, or they might call the domain model classes that performs the business rules.
E.g. when a booking is cancelled the hotel rooms should be made available to other bookings. It is the responsibility of the use case to make sure that this is included in the flow, but it is the domain model’s responsibility to know how a hotel is marked as available (maybe by changing the status).
As I wrote earlier, there is much value in automated testing of business logic to make sure that these rules work according to spec. Write acceptance tests testing the Use cases, and write unit tests that tests the business rules:
As we know reality is often a lot more complex that these simple examples. But this can be used as a starting point from which we continuously search for more knowledge. Why not continue by reading this blogpost by Uncle Bob?