CAUTION: Today’s post is more like a fun experiment, not something production-ready and viable. However, this exercise confirmed my internal feelings about functional programming in general and provided me an interesting point about safety and correctness.
You have been warned. Below, you may read unpragmatic ramblings about types and monads.
I’m joking – we will talk about monads only. 😀
As a functional programmer by training and passion, I could not resist and test how AWS CDK cooperates with functional languages.
My choice fell on F# as AWS CDK contains a template for that language, which is available here:
$ cdk init app --language=fsharp
After initialization, we have received a typical F# project for .NET Core environment. Sweet!
The first experience is excellent. So far, so good.
What You See Is What You Get
The next one wasn’t so pleasant – and that’s not the fault of the language (you will see in the next section why).
The complete source code can be found in my repository with AWS CDK examples. However, let’s focus on the CDK Stack definition:
namespace FSharpCDK open Utils open Amazon.CDK open Amazon.CDK.AWS.S3 type FSharpCDKStack(scope, id, props) as this = inherit Stack(scope, id, props) let expireAfter30Days = LifecycleRule(Enabled = Utils.nl true, Expiration = Duration.Days(30.0)) let bucketProps = BucketProps( Versioned = Utils.nl true, LifecycleRules = [| expireAfter30Days |], PublicReadAccess = Utils.nl false, BlockPublicAccess = BlockPublicAccess.BLOCK_ALL, RemovalPolicy = Utils.nl RemovalPolicy.DESTROY) do Bucket(this, "TestBucket", bucketProps) |> ignore ()
At first sight, it does not look so different from the other languages (and for sure not so different from C#). But, some subtleties are pissing me off:
- Too much Nullables – well, this “pattern” from TypeScript leaks here and forces you to do painful conversions using Option<‘T> or helper functions as I did with Utils.nl.
Those elements are connected with the behavior of how SDKs for the other languages are generated. Libraries for the different programming languages are created with JSII, which means that JS definition is the foundation for all other SDKs. For sure, it had to introduce some compromises.
What I Liked Is What You Don’t See
However, the most significant benefit is related to the functional style of programming and type system. Fluency in writing caused by the combination of those two elements is very pleasant. Declarativeness, referential transparency, immutability, and type system itself help with writing more efficiently.
Even that I’m using Visual Studio Code on Linux, still creating smaller and bigger programs felt frictionless. Most of the time, autocompletion and compiler guided me through the whole process.
What about the other functional languages?
Based on my experience, I am sure that for Scala or Clojure, the feeling will be similar. You will face the very same obstacles (typical issues of interop with Java libraries).
The truth is that if we do not see additional libraries dedicated to cover imperative SDKs, functional programming languages will offer just the traits available in the language itself. In some cases, it may be beneficial, but only if you are familiar with it.
Peeking into declarative (functional) world
I hope this short blog post inspired you to look into the exciting world of functional programming languages. You may ask, why bother – and you are partially right. It was a fun exercise, definitely not pragmatic and not for production use.
However, I would like to encourage you to expand your horizons. You should know why some things are the way they are. And isn’t infrastructure as code all about declarative approach?