Programming Smart contracts - A look into Daml, Kotlin & Java
The terms smart contract and blockchain have taken the world by storm as a means to transform how we collaborate and share information. The promise of not having to reconcile with each other constantly to determine which copy of data is true, and allowing all participating entities to share a single version of the business processes are indeed important benefits for any digital transformation strategy.
In this blog, I’ll reflect upon some differences between two popular paradigms used to create smart contract applications that can run on a blockchain based persistence layer.
The first of these paradigms is that of using domain specific languages (domain being smart contracts and multi-party applications). For the purposes of this blog, we consider Daml, an open source smart contracts language created by Digital Asset. Through the Daml runtime – which manages the integration with the blockchain platform and exposes standard application API - Daml smart contracts can be deployed to multiple platforms without any changes. Daml uses a modified version of the Haskell GHC compiler. While the language constructs can be considered similar, Daml adds several important constructs relevant to smart contracts such as templates, rights and obligations, privacy checks etc.
It is not my intention to pit one paradigm or language against another. Rather I simply provide an analysis of the pros and cons of both approaches and their place in a typical enterprise technology strategy. Other developers and experts may weigh these parameters differently, or even consider new ones. Overall my goal is to enable an educated choice of tools as you embark on this exciting transformation journey for your organization.
Here are the key parameters I will use for this blog:
- Where does each language fit in the tech stack?
- Developer experience and time to business validation
- Interoperability across networks
This is a vast topic, but I think that these parameters will be useful to developers and business leaders without leading them down a rabbit hole.
Where does each language fit in the technical stack?
This first question also serves to ground the analysis. For simplicity, let’s consider the traditional 3-tiered business application architecture that we are all familiar with. The top layer is the user interface, the middle layer is the business logic + orchestration layer, and the bottom layer is the data layer (in our case the underlying ledger).
Our focus for this blog is on the middle layer.
Kotlin and Java are general-purpose languages so they can be used to write a generic middle orchestration layer above that can connect multiple services together using APIs or other means (e.g. ERP integration, banking system integration, API gateways). The underlying blockchain platform can also provide libraries so that these general-purpose languages can be used to write the smart contracts layer that then interacts as needed with the underlying ledger.
Daml, on the other hand, is a pure smart contracts layer. Being a domain specific language (the domain being smart contracts), it abstracts common implementation requirements for ledgers, intrinsically ensures multi-party rights and obligations, offers privacy guarantees, and provides connectors to existing implementations like Corda. The Daml runtime automatically exposes APIs that can be used by the application layer. However the Daml smart contracts layer also must be complemented by an application layer that can perform the business process orchestration and interfacing with non-Daml applications. For example, shipping data may need to be sent to an ERP, or IoT signals may need to be aggregated and cleaned before being stored on the ledger. That application layer can be written in Kotlin or Java, for example.
It must be noted that we can pursue a different architecture for the middle layer, viz. an event driven architecture as outlined in this blog by Eric Saraniecki. In that architecture, for every smart contract persisted to the underlying ledger, events can be bubbled to the orchestration layer (as automations) to invoke other services and do other housekeeping tasks. That doesn’t change the thrust of our analysis though. Daml must be used with an accompanying general-purpose language to support the orchestration layer. A general purpose language such as Kotlin and Java need to be used to create these automations.
To understand the need that Daml addresses you have to understand that by being domain-specific, Daml can enable developers and business users to quickly write a comprehensive business process that is self-contained. Then the orchestration layer can be integrated with the APIs that the Daml layer exposes. The code in Daml (not unlike other DSL languages such as solidity) can be several times shorter and much simpler allowing you to focus on the business use case.
Further, given this smart contracts foundation provided by Daml, Kotlin and Java developers can use their existing skills to create an enterprise scale orchestration layer. There is a clean separation of business rules and the complexity of the codebase can be reduced with this approach leading to a simplified enterprise architecture overall.
Developer experience and time to validation of business case
One of the advantages of Daml that I was impressed with is the speed with which I could convert a business hypothesis into a working prototype ready to be tested and validated by business users. Since it is a domain-specific language, I didn’t have to deal with cryptography, checking authorization, and even checking for a valid state of the data before creating a new operation. I could start with and focus only on the business problem in hand. If I wanted a similar outcome using Kotlin or Java I could use an existing technology like Corda by R3 but some of the comforts that Daml provides are not included. These comforts include being able to spin up a GUI and ledger environment with one command. This is valuable when interacting with your business users on a prototype.
In contrast, with a general-purpose language like Kotlin or Java, I see two scenarios: Either you wish to develop your own ledger technology, or you know the ledger technology you wish to extend that also offers Kotlin/Java libraries or an API. If you wish to develop your own ledger, then Daml is not very relevant to develop the ledger itself but can be used to develop the smart contracts layer for the ledger. In the event that you’re leveraging existing ledger technology for your application, you can use Kotlin / Java and integrate with the provided ledger framework to make it easier. You still need to set up the entire scaffolding before you can get to the business problem you are trying to solve. While most Java and Kotlin developers can probably pick up the skills necessary, it can also be quite complex.
To help understand this, let’s take an example. Here is how you would create a commercial paper in Daml and give it to a new owner.
To interact and demonstrate this ledger description it would be just a matter of running `daml start`, which exposes the Navigator and allows you to simulate ledger transactions - create a commercial paper, and then “Give” it to a new owner.
To do this in Kotlin or Java, we will use an existing framework like Corda by R3 which, like Daml, solves a lot of these problems but is written in a general-purpose language (Kotlin) that you can extend and implement with your own behaviors. This avoids introducing needless complexity of having to interact with the ledger yourself, especially when it doesn’t directly address your business use case.
In this paradigm of using a general purpose language that uses provided platform libraries, the Kotlin developer (Java is similar) must also take into account additional constructs required by the underlying ledger, and so the code is significantly more verbose. For example, for the Corda blockchain, a Kotlin developer must create 3 different classes to account for the commercial paper above:
- Contract class (immutable business rules).
- Flow class (logic and mutation of data).
- State class (the data on the ledger).
This also has the unintended initial drawback of making the above Kotlin or Java programs specific to the ledger for which they are written (in this case Corda). If you know you want to target Corda this may not be a problem of course. Equally it is wise, especially during the initial development phase where requirements can change, to architect your solution to reduce coupling to the ledger technology and allow for more flexibility.
In contrast, the Daml runtime abstracts the ledger semantics from the developer thus allowing for simple code which is also ledger independent (more on this in the next section). Being a smart contracts language, Daml also allows built in constructs for privacy, authorization, rights and obligations. E.g. only the “owner” in the code above can “Give” the commercial paper to a new owner. The “issuer” is not permitted to do that, unless they are also the owner. Daml also automatically ensures that a party cannot be put in an obligable position without their consent. All of these can also be done with Kotlin and Java but developers will need to rely on ledger specific libraries to validate their business processes. These implementations are naturally opinionated, like any framework, but that tradeoff for initial productivity is important to consider and evaluate based on your use case.
If the underlying ledger has been determined beyond question, then expert developers should not have a problem with either of the above approaches. Daml does allow you to quickly prototype and validate your business use case if you are already an expert.
The abstraction of ledger level complexity in the Daml architecture leads to a more streamlined developer experience in my view. For example, you can immediately test the above Daml code by simulating multiple parties in a sandbox ledger by using the built-in Navigator tool. Developers and business owners can sit together to review the business process that has been developed via a GUI rather than a command line. This level of collaboration is made possible by Daml’s syntax and focus on the business process itself.
Portability is the ability for your programs to run on multiple platforms without any changes. I consider portability from 2 perspectives:
- First, it is an advantage for business decision making. For example, given an identified business opportunity, selection of the underlying ledger has traditionally been required to be done at the beginning of a DLT project so that the application can be developed accordingly. Valuable time is lost even before the software can be developed and the business opportunity validated. Innovation thus far has needed to overcome a high level of inertia.
- Second, the notion of synchronizing business processes, minimizing reconciliation, and enabling a single golden source of truth is an enterprise problem that we have battled for years. So bringing this smart contracts paradigm to inside an enterprise, in addition to between enterprises, will yield significant benefits. If the smart contracts language can also run on traditional databases - deploying a blockchain within an enterprise may run up against performance and complexity considerations – then this will allow the business to use existing skills and open up opportunities to further improve their business functions. The underlying database or blockchain deployment option can be kept open.
In both these areas Daml has made great strides by abstracting away ledger level details into the Daml runtime. Your applications can be deployed on any Daml enabled ledger (e.g. Corda, VMware Blockchain, Hyperledger Sawtooth, Besu, and Fabric, etc.) and also traditional databases (e.g. AWS Aurora, PostgreSQL, AWS QLDB etc.) without any changes.
In contrast, programs developed in Kotlin or Java must be significantly revised to be able to execute on a new platform if selected, and only if that ledger integration exists. Typically this architecture looks like an API which sits on-top of the ledger, then your other services consume this API. Designing this API to abstract most blockchain behaviors means that changes to other services should be minimal if at all in this scenario. Remember that as your integration is general-purpose you have a large degree of control and responsibility within this API. There is an argument to be made for “native” programs in some cases which has been brought out nicely by Richard Brown, CTO of R3 in the interchange section of his blog titled “Whipping Up Your Market With The Five Ingredients Of Interoperability”.
In addition, because of Daml portability, the ledger selection step at the beginning of projects can be eliminated so the entire focus is dedicated to making the business process come alive. Once the process has been prototyped and discussed, then the appropriate ledger can be determined (e.g. R3 Corda). Since Daml allows for rapid prototyping and validation of business and technology needs, at this stage you make a choice to continue with Daml or choose another technology.
In Richard’s blog that I mentioned above, he brings out a nice analogy of using Facetime between Apple device owners, or even continuing your transactions from one Apple device to another.
Just like these users are underpinned by the Apple ecosystem, such interoperability has been traditionally achieved at the network or ledger level. For example, the Corda Network enables multiple groups of nodes running different applications to talk to each other.
The reason I bring out network interoperability in a blog that focuses on smart contract languages is that being a domain specific language, Daml bubbles up this interoperability feature to the applications. Regardless of the underlying ledger being used, Daml applications across multiple networks from different software providers will be able to transact seamlessly across each other. For example, a Hyperledger Fabric network can atomically transact tokens and assets with a Corda network. And either of these networks can exchange information with Daml applications running on PostgreSQL inside an enterprise.
Interoperability or portability comparisons don’t seem to be fair to Kotlin and Java which are general-purpose languages enabled by ledger specific libraries. However, I make these points to show the benefits of using a domain-specific language such as Daml at the smart contract layer in case these considerations are important to you. It is not to say that these interoperability concerns cannot be done in Java or Kotlin but the complexity in Daml is easier to manage because it is a specific focus of the Daml community.
As you can see, Kotlin / Java and Daml are complementary to each other if we consider the overall enterprise technology stack.
For complex applications that need heavy lifting and integrations with multiple enterprise systems, Kotlin and Java are well suited, and provide a wide range of existing integrations and libraries in addition to a vast developer base. If your underlying ledger is Corda, then libraries are already provided to make the smart contract development efficient in these languages.
When it comes to writing the smart contract layer itself, practitioners will do well to evaluate a DSL such as Daml to pair with a general-purpose language such as Kotlin or Java for the application layer. A DSL, specifically Daml provides important built-in constructs for privacy, rights and obligations, ledger portability and also interoperability. Both developer experience as well as speed of business innovation will be enhanced.
A dual approach offers huge productivity advantages to developers, and reduces risk for businesses. For complex enterprise technology architectures, it does not need extensive reskilling while offering benefits not easily possible today. Furthermore, you can always start with Daml for the productivity gains and as your prototype progresses, and when the use case demands it, migrate to the underlying ledger technology if you need to.
Views expressed in this blog are my own and do not represent the views of my employer. Many thanks to Manish Grover for his expert insights and editorial assistance for writing this blog. If you are also interested in a comparison with Daml and Solidity you can check this out:"The World of Smart Contracts using Daml & Solidity".
Daml has also a new learn section where you can begin to code online:
If you want to master Daml smart contracts, you should also read:
- Interoperability between different markets and how Daml fits,
- Programming Smart contracts - A look into Daml, Kotlin & Java
- How easy it is to learn Daml,
- Some of the reasons why Daml and not Java or Solidity,
- Daml brings a paradigm shift as a programming language,
- How privacy in Daml differs from the rest and why it’s better.