<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Arjun Dhawan on Medium]]></title>
        <description><![CDATA[Stories by Arjun Dhawan on Medium]]></description>
        <link>https://medium.com/@arjun.dhawan?source=rss-ec31f55f44d9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*eGvSysLFKevarHw-I35fBw.jpeg</url>
            <title>Stories by Arjun Dhawan on Medium</title>
            <link>https://medium.com/@arjun.dhawan?source=rss-ec31f55f44d9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 15 Apr 2026 15:09:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@arjun.dhawan/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[KafkaGoSaur: a WebAssembly powered Kafka client]]></title>
            <link>https://medium.com/swlh/kafkagosaur-eac3c063388?source=rss-ec31f55f44d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/eac3c063388</guid>
            <category><![CDATA[go]]></category>
            <category><![CDATA[deno]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[webassembly]]></category>
            <category><![CDATA[kafka]]></category>
            <dc:creator><![CDATA[Arjun Dhawan]]></dc:creator>
            <pubDate>Mon, 14 Mar 2022 08:01:56 GMT</pubDate>
            <atom:updated>2022-03-18T15:47:58.580Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/256/1*5VMoieIVSID_Vl7rpejr2Q.png" /></figure><h4>A new Kafka client for Deno built using WebAssembly</h4><p><a href="https://github.com/arjun-1/kafkagosaur"><em>KafkaGoSaur</em></a><em> is a new Kafka client for Deno built with WebAssembly on top of </em><a href="https://github.com/segmentio/kafka-go"><em>kafka-go</em></a>, <em>the excellent Kafka client library written for Go. This article explains the basic usage of KafkaGoSaur and shines a light on some of its inner workings.</em></p><h4><strong>kafka-go</strong></h4><p><a href="https://go.dev/">Go</a> is a minimal yet powerful language. Its simplicity has driven its adoption in recent years by both startups and enterprises alike as it allows to build scalable and performant software fast. A useful standard library, modern tooling, and high-quality third-party libraries make it one of the <a href="https://insights.stackoverflow.com/survey/2021#most-loved-dreaded-and-wanted-language-want">most wanted</a> languages to work with.</p><p>One of these third-party libraries is kafka-go. An efficient and simple to use Kafka client developed by <a href="https://segment.com/">Segment</a>. It features both a low- and high-level API.</p><h4>Deno</h4><p>Lesser known is <a href="https://deno.land/">Deno</a>, a modern runtime for JavaScript and TypeScript focussing on great developer experience. Created by Ryan Dahl, it fixes long-standing issues and <a href="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;feature=youtu.be">regrets</a> that were introduced when he build Node.js. Deno is web-compatible wherever possible, meaning it runs WebAssembly binaries out of the box!</p><h4>WebAssembly</h4><p><a href="https://webassembly.org/">WebAssembly</a> (WASM) is a binary instruction format that serves as a universal compilation target. In simple terms, it allows code from almost any language to be run in the browser or any compatible environment like Deno.</p><p>Mix up all 3 technologies by compiling kafka-go to a WebAssembly binary and you get KafkaGoSaur: a new Kafka client for Deno that is ready to go.</p><h3>Usage</h3><h4>Producing</h4><p>Producing a message is simple. Message values are binary encoded and are produced in batch using <a href="https://doc.deno.land/https://deno.land/x/kafkagosaur/writer.ts/~/KafkaWriter#writeMessages">writeMessages</a>:</p><pre>import KafkaGoSaur from &quot;https://deno.land/x/kafkagosaur/mod.ts&quot;;</pre><pre>const kafkaGoSaur = new KafkaGoSaur();<br>const writer = await kafkaGoSaur.createWriter({<br>  broker: &quot;localhost:9092&quot;,<br>  topic: &quot;test-0&quot;,<br>});</pre><pre>const encoder = new TextEncoder();<br>const messages = [{ value: encoder.encode(&quot;Hello!&quot;) } ];</pre><pre>await writer.writeMessages(messages);</pre><p><strong>Consuming<br></strong>Messages are consumed one by one using <a href="https://doc.deno.land/https://deno.land/x/kafkagosaur/reader.ts/~/KafkaReader#readMessage">readMessage</a>:</p><pre>import KafkaGoSaur from &quot;https://deno.land/x/kafkagosaur/mod.ts&quot;;</pre><pre>const kafkaGoSaur = new KafkaGoSaur();<br>const reader = await kafkaGoSaur.createReader({<br>  brokers: [&quot;localhost:9092&quot;],<br>  topic: &quot;test-0&quot;,<br>});<br><br>const message = await reader.readMessage();</pre><h3>WebAssembly</h3><p>Can we use WebAssembly to port kafka-go to any language or runtime other than Deno? In principle, yes. But there is a limitation on WebAssembly stemming from the browser environment. Kafka communicates using <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP</a>, which is not supported by browsers. Even though browsers support <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API">WebSockets</a>, this web equivalent is not directly supported by Kafka brokers.</p><p>That’s why KafkaGoSaur exposes TCP functionality of its host — the Deno runtime — to kafka-go. Go exchanges the functions needed with the Deno runtime through the <a href="https://developer.mozilla.org/en-US/docs/Glossary/Global_object">global object</a> using <a href="https://pkg.go.dev/syscall/js">syscall/js</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9ZGeT_yyaRIsGXcvT1z2_w.png" /><figcaption>Example of functions exchanged in WebAssembly in KafkaGoSaur.</figcaption></figure><p>In essence, the exchange of functions is what happens when a new KafkaGoSaur instance is created. The constructor of KafkaGoSaur runs the WebAssembly binary that makes available the API of kafka-go in Deno.</p><p>KafkaGoSaur can use two different socket implementations for TCP: Deno’s <a href="https://deno.com/deploy/docs/runtime-sockets">Socket API</a> (Deno.connect) or the <a href="https://doc.deno.land/https://deno.land/std/node/net.ts">net module</a> (createConnection) from the Node.js compatibility layer. They are used to construct a DialFunc: a kafka-go function to create a <a href="https://pkg.go.dev/net#Conn">net.Conn</a>. By default, the node Node.js implementation is used but switching is easy. Just specify the one you want to use when creating the reader or writer:</p><pre>const reader = await kafkaGoSaur.createReader({<br>  brokers: [&quot;localhost:9092&quot;],<br>  topic: &quot;test-0&quot;,<br>  dialBackend: DialBackend.Node<br>});</pre><p>There is one limitation for DialBackend.Deno: producing messages is not supported yet. Somewhere in the implementation of Deno.connect seems to be a bug that causes broken pipe errors. The issue is being investigated.</p><h3>Promises and goroutines</h3><p>While Go achieves concurrency through <a href="https://gobyexample.com/goroutines">goroutines</a> which can spawn multiple threads, concurrency in JavaScript is modeled on a single-threaded <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop">event loop</a> using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>. That makes concurrency in JavaScript and Go inherently different.</p><p>Promises created in Deno need to be awaited in Go. That is done by sending its resolved value into a <a href="https://go.dev/tour/concurrency/2">channel</a>, which inherently blocks the current goroutine. Any function defined in Go can be invoked from JavaScript by wrapping it using <a href="https://pkg.go.dev/syscall/js#FuncOf">js.FuncOf</a>, turning it into a regular JavaScript value. Invoking the wrapped function in JavaScript affects the execution model in both languages:</p><ol><li>The event loop of the JavaScript runtime gets paused.</li><li>A new goroutine is spawned, executing the Go function.</li><li>The event loop resumes when this function returns.</li></ol><p>But there is a catch. Any other function wrapped using js.FuncOf will be executed on the very same new goroutine. This poses a problem when js.FuncOf wraps a Go function that calls (and awaits) a blocking JavaScript API. An example of such API would be fetch or read on a TCP connection. These APIs are <em>asynchronous</em>, meaning their return value resolves not now but some moment later in the future. Asynchronous functions in JavaScript rely on the event loop to process their return value whenever it resolves.</p><p>Thus when the event loop gets explicitly paused due to invocation of the wrapped function, it ends up in deadlock as the function defined in Go relies on the (never occurring) resumption of the event loop to return.</p><p>That’s why it is the responsibility of the caller of js.FuncOf to start a new goroutine to wrap any blocking function. This allows the wrapped Go function to return immediately with a Promise. This immediate return resumes the event loop so it can process the Promise when it resolves. Take a look at the <a href="https://github.com/arjun-1/kafkagosaur/blob/master/src/interop/promise.go">interop</a> package to see how functions NewPromise and Await respectively wrap blocking functions and await JavaScript Promises in Go.</p><h3>Performance</h3><p>KafkaGoSaur can write in batches nearly as fast as kafka-go, but reading suffers roughly a 50% performance penalty:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*kGmMKa2EsRYShWhcaweA6g.png" /><figcaption>Read and write performance comparison. Tested on a <a href="https://docs.confluent.io/cloud/current/clusters/cluster-types.html#basic-clusters">Confluent Cloud Basic cluster</a>.</figcaption></figure><p>The <a href="https://doc.deno.land/https://deno.land/x/kafkagosaur@v0.0.6/reader.ts/~/KafkaReader#stats">stats</a> function (backed by its <a href="https://pkg.go.dev/github.com/segmentio/kafka-go#Reader.Stats">Stats</a> counterpart) reports the so-called wait and read times and sheds a light on why this happens. The wait time is the time that is spent waiting for a batch of messages to arrive. The read time is the time it takes to read all the messages from this binary response. Kafka-go spends on average 15 ms waiting for a batch and 160 ms reading its messages. For KafkaGoSaur this is 20 ms waiting and 360 ms reading. Thus most of the performance penalty is incurred when KafkaGoSaur parses messages from the already fetched batch response.</p><h3>Next steps</h3><p>The exact cause for the performance degradation in the case of reading needs to be still uncovered. But a potential solution is luckily offered by the dual low- and high-level API that kafka-go offers. If the WebAssembly compiled function to read messages from the batch response is ill-performing, the same functionality can simply be reimplemented directly in Deno by making use of the low-level (but still performant) batch fetching.</p><p>Even though <a href="https://github.com/arjun-1/kafkagosaur">KafkgaGoSaur</a> is in the early stage of development, your contributions are highly valued and welcomed! Be an early adopter and feel free to ask for new features, report bugs, or submit your code 🙂.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eac3c063388" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/kafkagosaur-eac3c063388">KafkaGoSaur: a WebAssembly powered Kafka client</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pure and type safe error handling in Akka Streams]]></title>
            <link>https://medium.com/kaizo-engineering/pure-and-type-safe-error-handling-in-akka-streams-8acacf422d45?source=rss-ec31f55f44d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/8acacf422d45</guid>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[akka]]></category>
            <category><![CDATA[akka-streams]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Arjun Dhawan]]></dc:creator>
            <pubDate>Mon, 22 Feb 2021 15:25:49 GMT</pubDate>
            <atom:updated>2021-02-22T15:25:49.272Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/658/1*PVQs4Ofc5yN4Be0K4DBHmg.png" /></figure><h3>Pure and type-safe error handling in Akka Streams</h3><p><em>Want to know how to deal with errors in Akka streams in a type-safe way, rather than using </em>.recover<em>? You’ve come to the right place!</em></p><p>At Kaizo we process millions of ticket events per day. We subscribe to these events through the Zendesk API. Companies use <a href="https://www.zendesk.com/service/">Zendesk</a> to track, prioritize and solve customer support interactions. When companies use the <a href="https://www.zendesk.com/apps/support/kaizo/">Kaizo app</a> in Zendesk, they can evaluate and improve their team’s performance with unified and actionable real-time insights, QA, and gamification.</p><p>A ticket is a means through which end users communicate with customers&#39; agents. And real-time processing of ticket related events is required to provide fair, engaging, and leading metrics. Rather than using traditional reporting where you’re always playing catch-up.</p><p>To that end, we have to be <em>reactive. </em>We want to provide our agents with useful insights, always. That means designing around failure and expecting any kind of error to happen while processing an event.</p><h4>The problem</h4><p>We use <a href="https://doc.akka.io/docs/akka/current/stream/index.html">Akka streams</a> because of its performance characteristics compared to other streaming libraries. In Akka Streams, you traditionally use .recover to deal with failure:</p><pre>Source(1 to 10)<br>  .map(n =&gt;<br>     if (n == 3)<br>       throw new RuntimeException(s&quot;unexepted value: $n&quot;)<br>     else<br>       n.toString<br>  )<br>  .recover {<br>    case e: RuntimeException =&gt; e.getMessage<br>  }</pre><p>As you can see, Akka expects you to deal with errors by throwing exceptions (and therefore use side-effects). Not only that, the compiler has almost no means of pointing out any bugs due to lack of type-safety. Imagine accidentally removing .recover. Since the type of the resulting expression doesn’t change, bugs like this are impossible to catch by the compiler.</p><p>Our first step into improving this snippet is to <em>purify </em>it. Instead of modeling errors by throwing exceptions, we can use Either which results in an expression of type Source[Either[Exception, Int], _].</p><pre>Source(1 to 10)<br>  .map(n =&gt;<br>     if (n == 3)<br>       Left(new RuntimeException(s&quot;unexepted value: $n&quot;))<br>     else<br>       Right(n)<br>  )</pre><p>Due to the resulting type, the compiler now forces us to deal with any error at every processing stage. But this also creates another problem: at each moment of transforming the stream, we are now forced to introduce boilerplate which is a nested map: .map(_.map(n =&gt; ...)) . While other streaming libraries such as <a href="https://zio.dev/docs/datatypes/datatypes_stream">ZIO Streams</a> allow you to conveniently carry around typed errors by virtue of their type definition (Stream[E, A]), Akka streams is clearly not designed to do this. The solution we use at Kaizo to overcome this issue originates from <a href="https://www.scaladays.org/2018/new-york/schedule/patterns-for-streaming-telemetry-with-akka-streams">Colin Breck’s talk at Scala Days 2018</a>.</p><h4>Solution: use divertTo and collect</h4><p>First of all, we create a Sink specifically for dealing with errors. Secondly, we use divertTo and collect to divert any Left value to it:</p><pre>val errorSink: Sink[RuntimeException, NotUsed] =<br>  <em>Flow</em>[RuntimeException]<br>    .log(&quot;Error occurred&quot;)<br>    .to(Sink.<em>ignore</em>)</pre><pre>Source(1 to 10)<br>  .map(n =&gt;<br>     if (n == 3)<br>       Left(new RuntimeException(s&quot;unexepted value: $n&quot;))<br>     else<br>       Right(n)<br>  )<br>  .divertTo(<br>    errorsSink.contramap(<br>      _.left.getOrElse(sys.<em>error</em>(&quot;No left value&quot;))<br>    ),<br>    _.isLeft<br>  )<br>  .collect { case Right(a) =&gt; a }</pre><p>Here, contramap extracts the Left out of the Either before sending it to errorSink. The type of the resulting expression now is Source[Int, _] and we can use .map as we are used to. Note that we only use sys.error due to the Akka Streams API not having primitives to express what we are trying to achieve here. In reality, this error can never occur due to diversion happening if and only if _.isLeft.</p><p>Another way to approach this is to have an errorSink of slightly different definition:</p><pre>val errorSink: Sink[Either[RuntimeException, _], NotUsed] =<br>  Flow[Either[RuntimeException, _]]<br>    .collect { case Left(exception) =&gt; exception }<br>    .log(&quot;Error occurred&quot;)<br>    .to(Sink.ignore)</pre><p>Now we no longer need .contramap (together with the user of .left.getOrElse ) before sending errors to the sink. But we are forced to use nested .map to transform the error of the errorSink. And we have a type definition for errorSink that is slightly wider than needed: the errorSink should only deal with errors, but that is not reflected in its type definition.</p><p>We can abstract over this pattern, by creating a divertLeftTo function:</p><pre>Source(1 to 10)<br>  .map(n =&gt;<br>     if (n == 3)<br>       Left(new RuntimeException(s&quot;unexepted value: $n&quot;))<br>     else<br>       Right(n.toString)<br>  )<br>  .via(<em>divertLeftTo</em>(errorSink))</pre><pre>def divertLeftTo[E, A](<br>  sink: Sink[E, NotUsed]<br>): Flow[Either[E, A], A, NotUsed] = {<br> <br>  val sinkEither: Sink[Either[E, A], NotUsed] = sink.contramap(<br>    _.left.getOrElse(sys.<em>error</em>(&quot;No left value&quot;))<br>  )<br><br>  def shouldSendToSink(message: Either[E, A]): Boolean =<br>    message.isLeft<br><br>  <em>Flow</em>[Either[E, A]]<br>    .divertTo(sinkEither, shouldSendToSink)<br>    .collect { case <em>Right</em>(a) =&gt; a }<br><br>}</pre><p>Thanks to errorSink we don&#39;t need to convolute error handling with the main logic. Any error gets diverted to this sink, and handled separately. That means we don&#39;t need to deal with errors immediately when we extract them from Either. Essentially, this is a data-driven approach to error handling, reaping all the benefits of the compiler doing its type checking.</p><h4>Different ways of handling errors</h4><p>Let’s take a step back here, and imagine what kind of errorSink we would want to have. By default (as we have implemented in the example above using Sink.ignore), sending messages to errorSink is effectively the same as skipping<em> </em>a message. But one can think of other types of sinks: those that forwards messages to a dead letter queue to be processed again later (when the error contains sufficient information to do that) or sinks which halt the stream completely and shut down the service.</p><p>Skipping a message could make sense for an error that is not (re-)processable at all (think of business constraints). For other types of errors, you’d definitely want to reprocess your messages. Think of an error that occurs during deserialization suggesting that the used data model has evolved, but this service has not yet been updated.</p><p>The following example showcases a Sink that can skip or halt the stream completely:</p><pre>val errorSink: Sink[MyError, NotUsed] =<br>  Flow[RuntimeException]<br>    .takeWhile { case (e, _) =&gt; shouldSkip(e) }<br>    .log(&quot;skipping&quot;)<br>    .to(Sink.<em>ignore</em>)</pre><pre>def shouldSkip(e: MyError): Boolean =<br>  e match {<br>    case _: InvalidUserId  =&gt; true<br>    case e                  =&gt;<br>      <em>log</em>.error(s&quot;terminating - <em>$</em>e&quot;)<br>      false<br>  }</pre><h4>Special case: committing on skipped messages using Kafka</h4><p>We use <a href="https://kafka.apache.org/">Apache Kafka</a> as our streaming platform, and use <a href="https://doc.akka.io/docs/alpakka-kafka/current/index.html">Alpakka Kafka</a> to integrate with Scala. Imagine reading from a topic, and skipping certain events that we cannot process using only .collect :</p><pre>Consumer<br>  .sourceWithOffsetContext[String, String](consumerSettings, topics)<br>  .map(record =&gt; deserializeAs[MyEvent](record.value)<br>  .collect { case Right(event) =&gt; event }<br>  .toMat(Committer.sinkWithOffsetContext(committerSettings))(Keep.none)<br>  .run()</pre><pre>def deserializeAs[T](message: String): Either[DeserializationError, T]</pre><p>Can you spot the bug here?</p><p>We are not committing the skipped messages! This means we would re-read this message if we’d happen to restart the service while skipping occurs. Luckily, committing skipped messages using divertLeftTo is a breeze:</p><pre>val errorSink: Sink[DeserializationError, NotUsed] =<br>  Flow[DeserializationError]<br>    .log(&quot;skipping&quot;)<br>    .toMat(Committer.sinkWithOffsetContext(comitterSettings))(Keep.none)</pre><pre>Consumer<br>  .sourceWithOffsetContext[String, String](consumerSettings, topics)<br>  .map(record =&gt; deserializeAs[MyEvent](record.value)<br>  .via(divertLeftTo(errorSink))<br>  .toMat(Committer.sinkWithOffsetContext(committerSettings))(Keep.none)<br>  .run()</pre><pre>def deserializeAs[T](message: String): Either[DeserializationError, T]</pre><p>Thanks for reading! If you enjoyed this story, follow our Publication to stay tuned for more stories.</p><p>Interested in joining Kaizo? We are hiring (Scala) Software Engineers and Data engineers! Check the <a href="https://kaizo.recruitee.com/">recruitment page</a> for our open positions.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8acacf422d45" width="1" height="1" alt=""><hr><p><a href="https://medium.com/kaizo-engineering/pure-and-type-safe-error-handling-in-akka-streams-8acacf422d45">Pure and type safe error handling in Akka Streams</a> was originally published in <a href="https://medium.com/kaizo-engineering">Kaizo Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Combining Purely Functional Property Based and Docker Integration Tests in ZIO]]></title>
            <link>https://medium.com/swlh/combining-purely-functional-property-based-and-docker-integration-tests-in-zio-6a826c5e7e19?source=rss-ec31f55f44d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/6a826c5e7e19</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[integration-testing]]></category>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[zio]]></category>
            <category><![CDATA[property-based-testing]]></category>
            <dc:creator><![CDATA[Arjun Dhawan]]></dc:creator>
            <pubDate>Mon, 10 Aug 2020 06:35:47 GMT</pubDate>
            <atom:updated>2020-08-10T20:07:14.254Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/835/1*P3GYF9TgsFUG9koa3U7Prg.png" /></figure><p>Turning modules into law abiding citizens 😇</p><p><em>This article explains how to elegantly spin up Docker for property based tests and cleanup test cases making use of </em><a href="https://zio.dev/"><em>ZIO</em></a><em>’s </em>ZManaged<em>.</em></p><h3>Introduction</h3><h4>Laws</h4><p>Property based testing verifies correctness of programs in terms of <em>laws</em>: properties that arise from the domain and should always hold, also known as <em>invariants. </em>This reasoning about code in terms of expected and general behaviors is intuitive and leaves no edge case unturned.</p><p>While traditional testing requires you to manually construct test cases yourself, property based tests will randomly generate test cases (including edge cases!) for you. It greatly reduces human error in test development and makes them rely less on discipline and more on automation. It reinforces the principle that a test should actually give confidence about your code, rather than it being a ceremonial procedure.</p><p>These laws can range from the very simple:</p><blockquote>Semigroup instance<em> </em>stringSemigroup<em> </em>should be associative.</blockquote><p>to the more complex; for a DocumentClient module</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/573385736643ae14112e00f3722dcf31/href">https://medium.com/media/573385736643ae14112e00f3722dcf31/href</a></iframe><p>there could be a law</p><blockquote>Function call<em> </em>deleteDoc(docId: String)<em> </em>should delete the document with id docId<em> </em>at the remote document store.</blockquote><h4>External Interactions</h4><p>While the former law can be tested so easily that it doesn’t warrant an article, the latter is not so straightforward. Function deleteDoc requires an external interaction with the remote document store.</p><p>The external interaction could be mocked, allowing the law to become <em>unit tested</em>. If you’re lucky, the mock you just defined happens to coincide with the actual implementation of the document store. The deleteDoc function will be deployed and do its work as expected, always. Or in a more likely scenario, your mock will differ from the real implementation, allowing mistakes in the deleteDoc to go unnoticed during development. Another example is <a href="http://www.h2database.com/">H2</a>: while it might be similar enough to the actual DB system you use in 80% of the cases, it will for sure differ in behavior when dealing with for example PostGIS types or other more obscure features.<br>That is not the only thing: the mocks we usually define are stateless, meaning that the only interaction we can test is that some particular function of the mock was called in some particular way. These kind of mocks usually result in meaningless, non-intuitive expectations.</p><p>Instead the test could interact with the actual, deployed (development) instance of the remote document store, making it an <em>integration test</em>. This ensures that the deleteDoc function works as intended when deployed, but there are performance considerations: property based tests generate many, many test cases which would result in spikes of network traffic and increased load on the document store. The test cases would also need be cleaned afterwards. When this is a responsibility of the test itself it means that by accident the document store could be filled with garbage. Sometimes the cleaning of test cases is easy, as it is for PostgreSQL where a <em>rollback transactor </em>can be used (see for example the <a href="https://tpolecat.github.io/doobie/docs/14-Managing-Connections.html#customizing-transactors">doobie setup</a>).</p><p>The solution explored in this article, is to integrate the test not with the deployed instance of the document store, but to spin up a throwaway Docker container when running the integration test. The advantages are that the instance is thrown away after running the tests, as well as good performance given that the Docker instance resides on the same machine were the tests are being executed. It used to be the case that using such tests in a CI led to the bad practice of having Docker in Docker, meaning such tests could only be executed on the developers machine. Nowadays CI’s such as Azure DevOps allow pipelines to <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents">directly run on the VM</a>, making it no issue to spin up a Docker container inside the CI.</p><p>We should note there is another solution though not applicable here, where services’ endpoints are written in a pure description or <em>algebra</em>, from which it is possible to derive clients, service routes, OpenAPI documentation, etc. thus rendering tests obsolete. An example is <a href="https://endpoints4s.github.io/">endpoints4s</a>.</p><h3>Implementation</h3><h4>Testcontainers-scala</h4><p><a href="https://github.com/testcontainers/testcontainers-scala">Testcontainers-scala</a> is a wrapper for <a href="https://www.testcontainers.org/">Testcontainers</a> which supports lightweight throwaway Docker instances for tests. Let’s say our document store is actually a Couchbase NoSQL Database. We can easily setup a container for it in our tests:</p><pre>val c = CouchbaseContainer()</pre><p>In this case we chose a CouchbaseContainer, but in reality you can choose any kind of Docker image through GenericContainer. The container exposes start and stop methods, as well as fields getHost and getFirstMappedPort which hold the hostname and the randomized port on which the container starts. These fields are important as they allow us to initialize the DocumentClient with the proper configuration (DocumentClientConfig). These fields can only be accessed <strong>after</strong> starting and <strong>before </strong>stopping the container; any access outside of this span results in an exception. We can say that the configuration on which DocumentClient depends has a life cycle, which can be modeled using ZManaged:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dfc04a2505fe7a1843e31f67fc21c7d7/href">https://medium.com/media/dfc04a2505fe7a1843e31f67fc21c7d7/href</a></iframe><p>Using documentClientConfig we can easily a construct a DocumentClient Layer within the life cycle of the container:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/80fcbb7afeddb791ba5cf8d868cb3991/href">https://medium.com/media/80fcbb7afeddb791ba5cf8d868cb3991/href</a></iframe><p>Note the @@ TestAspect.Sequential: we want to ensure any test case is cleaned up per test, before proceeding to the next. And provideLayerShared ensures that the same documentClient instance, therefore a single life cycle of the container is used for the entire test suite. The container starts at the beginning of the test suite and stops at the end.</p><p>Before we proceed to write an actual test, we show how to achieve automated test case setup and clean up with separation of concerns; we don’t want to deal with setup and clean up in each and every individual test.</p><h4>Test Case Life Cycle Management</h4><p>Imagine the example of DocumentClient is extended with methods to create and get documents:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/03b382c46cd9946478227278c8f9d62e/href">https://medium.com/media/03b382c46cd9946478227278c8f9d62e/href</a></iframe><p>We can create a ZManaged which creates and gets a document, and deletes it as a cleanup action:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6dbdf962590efa8fd5c06f8e42e05802/href">https://medium.com/media/6dbdf962590efa8fd5c06f8e42e05802/href</a></iframe><p>This Zmanaged can be used to define a TestScenario1, to be used later as a Layer in our tests:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/85cf1b3b77a6c1683ab1977baf412a23/href">https://medium.com/media/85cf1b3b77a6c1683ab1977baf412a23/href</a></iframe><p>That’s all we need! All that remains is writing up the test. We want to assert that the delete function returned successfully, as well as the document being no longer available in the document store:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4b767481c984055a1322570f88b22be2/href">https://medium.com/media/4b767481c984055a1322570f88b22be2/href</a></iframe><p>If wanted we can easily combine test scenarios. Just combine them the same way you would combine layers:</p><pre>.provideSomeLayer(scenario1 ++ scenario2)</pre><p>Each test scenario is automatically cleaned before proceeding to the next test case generation, as well as before proceeding to the next test. We are cleaning the test cases not to prevent the Docker instance from being filled with garbage (the instance will be thrown away anyway), but to ensure it doesn’t affect any other test running in the same suite.</p><p>In reality we would check more laws for our DocumentClient module. Not just about deletion, but also about getting, creating, updating, copying, etc. of documents. Moreover the law postulated in the beginning is unlikely to hold, as it would fail for sure for a docId being the empty string &quot;&quot; . The solution is to redefine the algebra and the law using <em>refined types.</em></p><h4>Refined</h4><p><a href="https://github.com/fthomas/refined">Refined</a> is a library which allows narrowing down common types we use everyday (like String, List , etc.), to types that directly coincide with specific types of the domain. They could be refinements such as NonEmptyString, strings matching a particular RegEx, or even lists of particular length. They allow us to prevent the programs we write from entering an illegal state. This is guaranteed at compile time, rather than having to deal with those errors at runtime. For example we can enforce at compile time that deleteDoc is never called with an empty docId as argument.</p><p>The algebra looks as follows using Refined:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d0fa72bb33d1632b238503284a73038f/href">https://medium.com/media/d0fa72bb33d1632b238503284a73038f/href</a></iframe><p>When writing this article there is no interop available yet between Refined and ZIO Test, but we can easily define the interop ourselves:</p><pre>val anyNonEmptyString = Gen<br>  .string1(Gen.anyUnicodeChar)<br>  .map(refineV[NonEmpty](_).fold(sys.error, identity))</pre><p>And we are ready to start using the new algebra and generator in our tests.</p><h3>Discussion</h3><p>Property based and integration testing via Docker leads to relatively performant test suites which fully ensure modules are in accordance with intuitively defined and understandable behaviors.</p><p>Deciding what parts of our program need to be property based tested, integration tested or unit tested is admittedly more of an art than a strict science. Even though Docker integration tests don’t carry the overhead of trafficking back and forth data over the wire, they do carry the initial overhead of spinning up the container. And nothing beats unit tests in terms of performance.</p><p>As a rule of thumb, clients and (persistence) repositories are critical components that usually have clear laws which should be property based tested, and for which true confidence can only be brought using integration tests. It also makes sense to property based test type classes defined from scratch (unless they’re derived) which can be done through unit testing.</p><p>For other components it might not be straightforward to determine what exact laws they should abide by. It requires knowledge of the domain of the problem they solve to postulate them.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6a826c5e7e19" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/combining-purely-functional-property-based-and-docker-integration-tests-in-zio-6a826c5e7e19">Combining Purely Functional Property Based and Docker Integration Tests in ZIO</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Composing doobie programs using Cats]]></title>
            <link>https://medium.com/@arjun.dhawan/composing-doobie-programs-5337695fd77b?source=rss-ec31f55f44d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/5337695fd77b</guid>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[monads]]></category>
            <category><![CDATA[cats]]></category>
            <category><![CDATA[doobie]]></category>
            <category><![CDATA[typeclass]]></category>
            <dc:creator><![CDATA[Arjun Dhawan]]></dc:creator>
            <pubDate>Mon, 24 Feb 2020 22:05:20 GMT</pubDate>
            <atom:updated>2020-02-25T07:59:40.429Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/384/1*HcLHp4Gz-jxfahqu79xkWQ.png" /></figure><h4>type classes to the rescue</h4><h4>TL;DR</h4><p>If you want to combine ConnectionIO programs using |+| syntax:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1cca96d87cb5ac54a44fe9c1e4f8b54e/href">https://medium.com/media/1cca96d87cb5ac54a44fe9c1e4f8b54e/href</a></iframe><p>you need bring an implicit Semigroup in scope through</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/252380f568d63d2512ec7b27d0974229/href">https://medium.com/media/252380f568d63d2512ec7b27d0974229/href</a></iframe><h3>Introduction: doobie</h3><p><a href="https://tpolecat.github.io/doobie/">Doobie</a> is a functional library for Scala/Cats that allows us to write programs to interact with a database using the JDBC API.</p><h4>ConnectionIO</h4><p>All such programs are described in the form of ConnectionIO. An example of such a program:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/752aa287e4cdd1f0d5c22961c54859e0/href">https://medium.com/media/752aa287e4cdd1f0d5c22961c54859e0/href</a></iframe><p>Nice thing about ConnectionIO is that it forms a Monad. It has flatMap which enables us to sequence different ConnectionIO programs.</p><h4>Transaction</h4><p>A ConnectionIO has no interpretation in the outside world (it’s a construct having only significance to Doobie) and can therefore not directly be run. To interpret it to a meaningful effect (let’s say, to a ZIO <a href="https://zio.dev/docs/overview/overview_creating_effects">Task</a>) we need a Transactor:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7fbaa3e9055b73f5fe4e651d6a5a0e63/href">https://medium.com/media/7fbaa3e9055b73f5fe4e651d6a5a0e63/href</a></iframe><p>Here the <em>transaction boundary</em> is put around insertProgram1 and insertProgram2. Meaning that if something goes wrong at the database level for either insertProgram1 or insertProgram2, the entire transaction will be rolled back thus guaranteeing consistency in our database.</p><h3>The problem</h3><p>The construction of a ConnectionIO program itself might be modeled using another effect. Take the case where a UserService needs to make an http call before knowing what to insert:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/50252a47ea740df3cc3b87676a35adf1/href">https://medium.com/media/50252a47ea740df3cc3b87676a35adf1/href</a></iframe><p>See <a href="https://blog.softwaremill.com/from-transactional-to-type-safe-reasonable-transactions-a5019906245e#adec">this other example</a> showing how such nesting can arise. If we are dealing with only one such call, there is no issue transforming this into a Task:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d40a1e5ce549554dadcc9ba857b4c877/href">https://medium.com/media/d40a1e5ce549554dadcc9ba857b4c877/href</a></iframe><p>But what if we need to perform multiple calls from different services, and want to keep the transaction boundary around the resulting ConnectionIO’s?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4cda35437fe73626d4077f4ea3d388bb/href">https://medium.com/media/4cda35437fe73626d4077f4ea3d388bb/href</a></iframe><p>A nested for-comprehension? Yikes!</p><h3>The solution</h3><p>We seek to achieve an easy way to combine ConnectionIO programs. Semigroup is just the right abstraction for that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4a5ec2eb6bc85de0273b54152ed12037/href">https://medium.com/media/4a5ec2eb6bc85de0273b54152ed12037/href</a></iframe><p>But how do we create a Semigroup for ConnectionIO? Doobie provides us out of the box with a type class instance for <a href="https://typelevel.org/cats-effect/">cats-effect</a> for ConnectionIO: Async[ConnectionIO]. <a href="https://typelevel.org/cats-effect/typeclasses/async.html">Async</a> is a Monad, and is actually (being related through the <a href="https://typelevel.org/cats-effect/typeclasses/">type class hierarchy</a>) also an <a href="https://typelevel.org/cats/typeclasses/applicative.html#apply---a-weakened-applicative">Apply</a> which is a less powerful <a href="https://typelevel.org/cats/typeclasses/applicative.html">Applicative</a>. And Apply has defined a function to give us a Semigroup 😊:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/853e4283113603d09632a99ba0d5d12e/href">https://medium.com/media/853e4283113603d09632a99ba0d5d12e/href</a></iframe><p>So we can bring any implicit Semigroup[ConnectionIO[A]] in scope by defining</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/807784fd9d0246493a359450661613a1/href">https://medium.com/media/807784fd9d0246493a359450661613a1/href</a></iframe><p>In this case we are not interested in the return values of our ConnectionIO programs. Since ConnectionIO is also a <a href="https://typelevel.org/cats/typeclasses/functor.html">Functor</a>, we can ignore the result value through .void, meaning we can write:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4023fa4a365a89975a8d009f5ba6ed90/href">https://medium.com/media/4023fa4a365a89975a8d009f5ba6ed90/href</a></iframe><p>and gone is the nested for-comprehension 😊.<br>If our ConnectionIO programs return ADT’s which we would like to keep, we can use .widen on Functor to cast to the most common subtype:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac0280d053da6d1b095d2e8a9fd7a685/href">https://medium.com/media/ac0280d053da6d1b095d2e8a9fd7a685/href</a></iframe><p>Of course we would need a Semigroup instance for ADT.</p><h3>Closing thoughts</h3><p>We could also have defined a Semigroup for <a href="https://typelevel.org/cats/datatypes/freemonad.html">Free</a> (what ConnectionIO is) instead of Apply. But since Apply is less strict than Free (it has less laws to obey) it is preferable to define the Semigroup for Apply so we can model more behaviors.</p><p>Having interpreted ConnectionIO as a Semigroup also better conveys our intent: when ‘smashing’ together ConnectionIO’s we don’t care about the power to control computations based on the previous result (which is the power that flatMap gives). Instead, we want to merely combine ConnectionIO programs, which exactly fits the semantics of Semigroup.</p><h3>Acknowledgements</h3><p>Special thanks to <a href="https://github.com/Fristi">Mark de Jong</a> for his insights on the subject.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5337695fd77b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>