<?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[Cognizant Servian - Medium]]></title>
        <description><![CDATA[Cognizant Servian was formed on the deep expertise of two acquisitions: Servian and Contino. Together, we are experts in innovative data and analytics, digital, customer engagement and cloud solutions to evolve your competitive advantage. - Medium]]></description>
        <link>https://medium.com/weareservian?source=rss----1f080c3ceb95---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Cognizant Servian - Medium</title>
            <link>https://medium.com/weareservian?source=rss----1f080c3ceb95---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 02:35:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/weareservian" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Exploring Quarkus, Supersonic Subatomic Java]]></title>
            <link>https://medium.com/weareservian/exploring-quarkus-supersonic-subatomic-java-d70a2fcefe94?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/d70a2fcefe94</guid>
            <category><![CDATA[native-image]]></category>
            <category><![CDATA[quarkus]]></category>
            <category><![CDATA[quarkus-framework]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[nikfarjam]]></dc:creator>
            <pubDate>Mon, 14 Aug 2023 01:53:20 GMT</pubDate>
            <atom:updated>2023-08-14T01:53:19.943Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>History of Java</strong></h3><p>Java as one of the most influential programming languages was originally developed by Sun Microsystems in 1995. With its unique design, Java code is compiled into bytecode that can run on any platform that has a Java Virtual Machine (JVM). This revolution enabled developers to write code once and run it forever. The idea of “write once, run anywhere” made it the most popular programming language in the world at that time.</p><p>Java’s key characteristics, such as its object-oriented nature, platform independence, security, large community, and wide range of libraries and frameworks, make it the language of choice for developing large-scale applications. However, its slow startup time and huge memory footprint can be drawbacks for some use cases.</p><p>The rise of microservices architecture and containerization technologies that are based on increasing the number of running applications on demand, running applications on low memory and CPU environments, and fast development has reduced the popularity of Java.</p><h3><strong>Native Image</strong></h3><p>To fill this gap, Native Image is a technology to compile Java code ahead of time to a native executable that contains the required code, libraries, and runtime.</p><p>As Java Native Image don’t need to load full classes, JVM, and all dependencies, they have several advantages over legacy Java applications, for example:</p><ul><li>Faster startup</li><li>Less memory footprint</li><li>Higher security</li></ul><p>Migrating legacy applications to Native Image is not an easy task, for example, Spring Boot the leading Java framework uses reflection expensively. The problem with reflection is the JNI compiler is not able to know what classes and methods will be used at runtime. Moreover, the use of reflection with JNI increases security risk. When an attacker finds a way to inject malicious code into the application, they could use reflection to invoke methods and access fields that they should not be able to access.</p><h3><strong>Quarkus</strong></h3><p>One of the most successful open-source JNI solutions is Quarkus, a framework that aims to bring Java to modern Cloud-native and containerization architectures with a wide range of supported libraries. In this article, we will explore the basics of Quarkus.</p><p>Similar to Spring Boot, Quarkus comes with a collection of development tools to support the Agile way of working. Following the Service template, Quarkus gives you some options to create a new project from the template including CLI, code initializer, and Idea plugins. This not only saves time and effort but also makes services consistent with each other and with the overall organization.</p><h3><strong>Code Demo</strong></h3><p>The first step is to install <a href="https://quarkus.io/guides/cli-tooling">Quarkus CLI</a></p><p>For Mac or Linux, using brew</p><pre>brew install quarkusio/tap/quarkus</pre><p>Or using SDKMAN</p><pre>sdk install quarkus</pre><p>And Windows</p><pre>choco install quarkus</pre><p>Now, let’s start our first piece of work</p><pre>➜ quarkus create hello-quarkus<br><br>Creating an app (default project type, see --help).<br>Looking for the newly published extensions in registry.quarkus.io<br>-----------<br>applying codestarts...<br>📚 java<br>🔨 maven<br>📦 quarkus<br>📝 config-properties<br>🔧 dockerfiles<br>🔧 maven-wrapper<br>🚀 resteasy-reactive-codestart<br>-----------<br>[SUCCESS] ✅  quarkus project has been successfully generated in:<br>--&gt; /Users/quarkus/hello-quarkus<br>-----------<br>Navigate into this directory and get started: quarkus dev</pre><p>Easy, the CLI generated a sample project from a template. This project contains the skeleton of a Maven project, sample code, Docker files, and whatever is required to run an API.</p><p>Let’s have a look at it.</p><pre>➜ hello-quarkus<br>➜ tree <br><br>.<br>|____mvnw.cmd   -- Batch script to run maven<br>|____pom.xml   -- POM file<br>|____README.md  -- Default read me file with a basic guideline<br>|____.dockerignore  -- Docker ignore file to exclude generated files in docker image<br>|____.gitignore  -- Git ignore file to exclude generated files in Git repository<br>|____.mvn   -- Home for embadaded maven <br>| |____wrapper<br>| | |____MavenWrapperDownloader.java<br>| | |____maven-wrapper.properties<br>| | |____.gitignore<br>|____mvnw   -- Shell script to run maven<br>|____src   -- Prjoect <br>| |____test<br>| | |____java<br>| | | |____org<br>| | | | |____acme<br>| | | | | |____GreetingResourceIT.java  -- Sample test for native code <br>| | | | | |____GreetingResourceTest.java -- Sample integration test<br>| |____main<br>| | |____docker     -- Sample docker files<br>| | | |____Dockerfile.native<br>| | | |____Dockerfile.native-micro<br>| | | |____Dockerfile.legacy-jar<br>| | | |____Dockerfile.jvm<br>| | |____resources     -- Project resources<br>| | | |____META-INF<br>| | | | |____resources<br>| | | | | |____index.html<br>| | | |____application.properties<br>| | |____java<br>| | | |____org<br>| | | | |____acme<br>| | | | | |____GreetingResource.java  -- Sampel Rest API</pre><p>It’s time to run the project</p><pre>➜  mvn quarkus:dev<br><br>[INFO] Scanning for projects...<br><br>...<br><br>Tests paused<br>Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options&gt;</pre><p>Now, Quarkus embedded server is running on port 8080.</p><p>In a new terminal run the CURL command or visit <a href="http://localhost:8080/hello">http://localhost:8080/hello</a> in a browser.</p><pre>➜ curl http://localhost:8080/hello<br>Hello from RESTEasy Reactive%</pre><p>This application has a single and straightforward class, let’s take a look at it.</p><pre> ➜ bat ./src/main/java/org/acme/GreetingResource.java</pre><pre>1    │ package org.acme;<br>2    │<br>3    │ import jakarta.ws.rs.GET;<br>4    │ import jakarta.ws.rs.Path;<br>5    │ import jakarta.ws.rs.Produces;<br>6    │ import jakarta.ws.rs.core.MediaType;<br>7    │<br>8    │ @Path(&quot;/hello&quot;)<br>9    │ public class GreetingResource {<br>10   │<br>11   │     @GET<br>12   │     @Produces(MediaType.TEXT_PLAIN)<br>13   │     public String hello() {<br>14   │         return &quot;Hello from RESTEasy Reactive&quot;;<br>15   │     }<br>16   │ }</pre><p>Line 8: Path of endpoint</p><p>Line 11: Rest method type</p><p>Line 12: Response content type, in this case, text/plain</p><p>Line 14: Response value</p><p>To see how it works, edit GreetingResource.java in a text editor and change Line 14 to the following</p><pre>return &quot;Hello Quarkus&quot;;</pre><p>and save the file. Now check <a href="http://localhost:8080/hello">http://localhost:8080/hello</a> again.</p><pre>➜ curl http://localhost:8080/hello<br>Hello Quarkus%</pre><p>For people with a Java background, it’s impressive. Fast and easy, no need for an Idea or a chain of shell commands to re-compile and re-deploy.</p><p>In the previous section, we had a look at Quarkus template project. Let’s get more familiar with Quarkus by building a cool new application. We could start with a simple REST API that converts Celsius to Fahrenheit or Fahrenheit to Celsius.</p><h3><strong>Project description:</strong></h3><ol><li>The Restful API has only one end-point <em>/converter</em></li><li>The request payload is a JSON object with the following properties</li></ol><p>- value: The original value</p><p>- from: The original unit</p><p>- to The target unit</p><p>For example</p><pre>{<br>  &quot;value&quot;: 37,<br>  &quot;from&quot;: &quot;CELSIUS&quot;,<br>  &quot;to&quot;: &quot;FAHRENHEIT&quot;<br>}</pre><p>3. When inputs are valid, the API will return the converted value and expected unit, for instance</p><pre>{<br>  &quot;value&quot;: 100,<br>  &quot;unit&quot;: &quot;FAHRENHEIT&quot;<br>}</pre><p>4. In case one of the values are not valid or the server gets an internal error, the response would be a JSON object with a summary and description of the error, like</p><pre>{<br>  &quot;summary&quot;: &quot;Internal error&quot;<br>  &quot;description&quot;: &quot;Invalid Operation &#39;C&#39; to &#39;F&#39;&quot;,<br>}</pre><h3><strong>Implementation</strong></h3><p>The first step is to create a project by Quarkus CLI and remove generated sample classes.</p><pre>➜ quarkus create temperature-converter<br>➜ cd temperature-converter<br>➜ find ./src -type f -name &#39;*.java&#39; -exec rm -f {} \;</pre><p>Then create model objects. Thanks to Java 14+, instead of legacy POJO with lots of boilerplate code such as getters, setters, equals and hashcode methods, we can get the advantages of <a href="https://docs.oracle.com/en/java/javase/20/language/records.html">Record Classes</a></p><pre>public record ConvertRequest(Float value, String from, String to) {}</pre><pre>public record ConvertResponse(Float value, String unit) {}</pre><pre>public record ConvertError(String summary, String description){}</pre><p>It’s recommended to have a custom exception to have better error handling.</p><pre>public class ConverterException extends RuntimeException {<br>  public ConverterException(String message) {<br>    super(message);<br>  }<br>}</pre><p>Quarkus is a modern framework that includes some of the best features of other popular and successful frameworks, such as dependency injection, convention over configuration, and test utils. Step by step we’ll explore them. Now, It’s time to add the converter service to the project.</p><pre>public interface Converter {<br>    ConvertResponse convertUnit(ConvertRequest req);<br>}</pre><p>Obviously, we must have unit tests for each component of our application. We will see that automation tests are essential for ensuring the quality of native image applications.</p><pre>class ConverterImplTest {<br>  ConverterImpl converter = new ConverterImpl();<br>  <br>  @Test<br>  void whenRequestUnitsAreNotValid() {<br>    ConverterException exception = assertThrows(ConverterException.class,<br>      () -&gt; converter.convertUnit(new ConvertRequest(0F, &quot;TEST&quot;, &quot;test&quot;)));<br>    assertEquals(&quot;Invalid Operation &#39;TEST&#39; to &#39;test&#39;&quot;, exception.getMessage());<br>  }<br><br>  @Test<br>  void convertCelsiusToFahrenheit() {<br>    ConvertResponse result = converter.convertUnit(new ConvertRequest(100F, &quot;celsius&quot;, &quot;FAHRENHEIT&quot;));<br>    assertEquals(&quot;FAHRENHEIT&quot;, result.unit());<br>    assertEquals(212F, result.value());<br>  }<br>}</pre><p>Quarkus’s default dependency injection, ArC, is a lightweight and efficient library that is based on the Jakarta Dependency Injection specification. In comparison with Spring, it’s designed to be faster and smaller which makes it ideal for microservices. <strong>ArC</strong> is a build-time-oriented dependency injection which means it validates beans and dependencies during the build process, therefore the chance of runtime bean creation exceptions is minimum. On the other hand, it is more limited and does not support all features in Spring such as aspect-oriented programming and complex dependency graphs.</p><p>Although this article does not cover the generated POM file in detail, mastering it is essential for anyone who wants to use Quarkus effectively. If you looked at the <strong>pom.xml</strong> with a keen eye, you might find ArC in dependencies.</p><pre>&lt;dependency&gt;<br>  &lt;groupId&gt;io.quarkus&lt;/groupId&gt;<br>  &lt;artifactId&gt;quarkus-arc&lt;/artifactId&gt;<br>&lt;/dependency&gt;</pre><p>With the fancy Switch Expressions, implementation of the converter service is not very tedious. The <strong>@ApplicationScoped</strong> annotation indicates that <strong>ConverterImpl</strong> is a bean and its scope is application.</p><pre>@ApplicationScoped<br>public class ConverterImpl implements Converter {<br>    private Logger logger = LoggerFactory.getLogger(ConverterImpl.class);<br>    <br>    @Override<br>    public ConvertResponse convertUnit(ConvertRequest req) {<br>        logger.debug(&quot;Trying to process {}&quot;, req);<br>        final var from = Optional.of(req).map(ConvertRequest::from).orElse(&quot;&quot;);<br>        final var to = Optional.of(req).map(ConvertRequest::to).orElse(&quot;&quot;);<br>        <br>        final var value = switch (String.join(&quot;_&quot;, from, to).toUpperCase()) {<br>            case &quot;CELSIUS_FAHRENHEIT&quot; -&gt; ((Optional.of(req).map(ConvertRequest::value).orElse(0F)) * 9 / 5) + 32F;<br>            case &quot;FAHRENHEIT_CELSIUS&quot; -&gt; ((Optional.of(req).map(ConvertRequest::value).orElse(0F)) - 32) * 5 / 9;<br>            default -&gt; throw new ConverterException(&quot;Invalid Operation &#39;&quot; + from + &quot;&#39; to &#39;&quot; + to + &quot;&#39;&quot;);<br>        };<br>        return new ConvertResponse(value, to);<br>    }<br>}</pre><p>To support JSON in our application, we need to add the following to the Maven dependencies</p><pre> &lt;dependency&gt;<br>   &lt;groupId&gt;io.quarkus&lt;/groupId&gt;<br>   &lt;artifactId&gt;quarkus-resteasy-reactive-jsonb&lt;/artifactId&gt;<br> &lt;/dependency&gt;</pre><p>Everything is ready for the controller that handles JSON payload requests and returns results in JSON format. In order to have an instance of converter service in the controller, we use @Inject annotation to inject it into the controller. @Post indicates the API serves post requests and @Produces defines response type.</p><pre>@Path(&quot;/converter&quot;)<br>public class ConverterApi {<br><br>  @Inject<br>  private Converter converter;<br>    <br>  @POST<br>  @Produces(MediaType.APPLICATION_JSON)<br>  @Consumes(MediaType.APPLICATION_JSON)<br>  public ConvertResponse convert(ConvertRequest request) {<br>    return converter.convertUnit(request);<br>  }<br>}</pre><p>Consistency in error handling is one of REST API’s best practices. Exception mapper is a service that automatically maps validation and internal errors into a consistent response format, making it easier for clients to understand and handle errors.</p><pre>@Provider<br>public class ConverterExceptionMapper implements ExceptionMapper&lt;ConverterException&gt; {<br>  private final Logger logger = LoggerFactory.getLogger(ConverterExceptionMapper.class);<br>    <br>  @Override<br>  public Response toResponse(ConverterException e) {<br>    logger.error(&quot;An internal error occurred&quot;, e);<br>    return Response<br>             .status(Response.Status.INTERNAL_SERVER_ERROR)<br>             .entity(new ConvertError(&quot;Internal error&quot;, Optional.of(e).map(Throwable::getMessage).orElse(&quot;Internal error&quot;)))<br>             .build();<br>  }<br>}</pre><p>In addition to unit tests, integration tests are required to ensure applications in both JDK and native modes behave similarly.</p><pre>@QuarkusTest<br>class ConverterApiTest {<br><br>    private Jsonb jsonb = JsonbBuilder.create();<br><br>    @Test<br>    void whenConvertInputIsEmpty() {<br>        given()<br>                .header(ACCEPT, APPLICATION_JSON)<br>                .header(CONTENT_TYPE, APPLICATION_JSON)<br>                .body(jsonb.toJson(new ConvertRequest(0F, null, null)))<br>                .when()<br>                .post(&quot;/converter&quot;)<br>                .then()<br>                .statusCode(INTERNAL_SERVER_ERROR.getStatusCode())<br>                .body(is(jsonb.toJson(<br>                        new ConvertError(&quot;Internal error&quot;, &quot;Invalid Operation &#39;&#39; to &#39;&#39;&quot;))));<br>    }<br><br>    @Test<br>    void convertCelsiusToFahrenheit() {<br>        given()<br>                .header(ACCEPT, APPLICATION_JSON)<br>                .header(CONTENT_TYPE, APPLICATION_JSON)<br>                .body(jsonb.toJson(new ConvertRequest(100F, &quot;celsius&quot;, &quot;fahrenheit&quot;)))<br>                .when()<br>                .post(&quot;/converter&quot;)<br>                .then()<br>                .statusCode(OK.getStatusCode())<br>                .body(is(jsonb.toJson(new ConvertResponse(212F, &quot;fahrenheit&quot;))));<br>    }<br>}</pre><p>After running tests, let’s run the temperature converter and see how it works in action. From one terminal run the application.</p><pre>➜  mvn quarkus:dev<br>[INFO] Scanning for projects...<br><br>...<br><br>Listening for transport dt_socket at address: 5005<br>__  ____  __  _____   ___  __ ____  ______<br> --/ __ \/ / / / _ | / _ \/ //_/ / / / __/<br> -/ /_/ / /_/ / __ |/ , _/ ,&lt; / /_/ /\ \<br>--\___\_\____/_/ |_/_/|_/_/|_|\____/___/<br>2023-06-24 21:37:30,122 INFO  [io.quarkus] (Quarkus Main Thread) quarkus-unit-converter 1.0-SNAPSHOT on JVM (powered by Quarkus 3.1.1.Final) started in 2.389s. Listening on: http://localhost:8080<br>...<br>Tests paused<br>Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options&gt;</pre><p>From the other terminal, call the API with CURL command</p><pre>➜ curl -d &#39;{&quot;value&quot;:&quot;37&quot;, &quot;from&quot;:&quot;CELSIUS&quot;, &quot;to&quot;:&quot;FAHRENHEIT&quot;}&#39; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:8080/converter | jq<br>{<br>  &quot;unit&quot;: &quot;FAHRENHEIT&quot;,<br>  &quot;value&quot;: 98.6<br>}<br><br>➜ curl -d &#39;{&quot;value&quot;:&quot;150&quot;, &quot;from&quot;:&quot;FAHRENHEIT&quot;, &quot;to&quot;:&quot;CELSIUS&quot;}&#39; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:8080/converter | jq<br>{<br>  &quot;unit&quot;: &quot;CELSIUS&quot;,<br>  &quot;value&quot;: 65.55556<br>}<br><br>➜ curl -d &#39;{&quot;value&quot;:&quot;150&quot;, &quot;from&quot;:&quot;FROM&quot;, &quot;to&quot;:&quot;TO&quot;}&#39; -H &quot;Content-Type: application/json&quot; -X POST http://localhost:8080/converter | jq<br>{<br>  &quot;description&quot;: &quot;Invalid Operation &#39;FROM&#39; to &#39;TO&#39;&quot;,<br>  &quot;summary&quot;: &quot;Internal error&quot;<br>}</pre><p>Looks fantastic 🙌.</p><h3>Deployment</h3><p><strong>1- Jar</strong></p><p>The traditional way of packaging a Java application is to create a Jar file that contains the compiled code and add third-party libraries and other dependencies together. The generated POM file in the project makes everything easier and more efficient for us by adding an index of required third-party libraries to the Jar file, this means that we no longer need to specify a long list of other Jar files as dependencies in the JRE parameters. By runningmvn package maven will create all required resources under ./target/quarkus-app/</p><pre>➜ java -jar ./target/quarkus-app/quarkus-run.jar</pre><p><strong>2- Uber Jar</strong></p><p>Sometimes working with a collection of Jar files and dependencies is challenging, for example, we need to transfer all of them in the same folder structure. Uber Jar is another option to pack all classes and dependencies in a fat Jar file. To do that run the following command.</p><pre>➜ mvn package -Dquarkus.package.type=uber-jar</pre><p><strong>3- Docker Image</strong></p><p>Docker image is the most common way of packaging applications in the Software industry. Under ./src/main/docker there are some Docker files to create an optimum Docker Image.</p><pre>➜ docker build -f src/main/docker/Dockerfile.jvm -t quarkus-unit-converter-jvm .</pre><p>To run the Docker image</p><pre>➜ docker run -i --rm -p 8080:8080 quarkus-unit-converter-jvm</pre><p>In this article, we get familiar with Quarkus a lightweight, fast, and developer-friendly Java framework that facilitates the development of Microservices, distributed monologic and serverless applications. In the next article, we’ll explore how can we migrate our first Quarkus application to Native image. The source code for this article can be found on <a href="https://github.com/nikfarjam/quarkus-temperature-converter">GitHub</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d70a2fcefe94" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/exploring-quarkus-supersonic-subatomic-java-d70a2fcefe94">Exploring Quarkus, Supersonic Subatomic Java</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Terraform Local Providers and Registry Mirror Configuration]]></title>
            <link>https://medium.com/weareservian/terraform-local-providers-and-registry-mirror-configuration-b963117dfffa?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/b963117dfffa</guid>
            <category><![CDATA[terraform-modules]]></category>
            <category><![CDATA[terraform]]></category>
            <dc:creator><![CDATA[Jason Zhong]]></dc:creator>
            <pubDate>Thu, 27 Apr 2023 00:21:01 GMT</pubDate>
            <atom:updated>2023-04-27T00:21:01.309Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/770/0*XJFBoFIAYO2VHrYq.png" /></figure><p>Sometimes we need to run Terraform modules with a range of providers that we develop or customise to be used locally, or in an environment with a restricted network connection, for example, without access to the internet. In these cases, our <em>terraform init</em> may not be able to search and download providers from Hashicorp’s registry. Nevertheless, Terraform has introduced a <em>provider installation configuration</em> feature, as part of its <a href="https://developer.hashicorp.com/terraform/cli/config/config-file"><em>CLI configuration</em></a> since version 0.13, which could solve this issue.</p><p>This article will cover a provider overriding method and two types of provider registry mirrors in the provider installation configuration in a CLI configuration file:</p><ul><li><strong>Dev Overrides</strong>: overrides source path of particular providers with a local path (good for testing customised providers)</li><li><strong>File system mirror</strong>: directs installation of providers to a file system path (e.g. your local path)</li><li><strong>Network mirror</strong>: directs installation of providers to a URL (e.g. your internal package repositories)</li></ul><h3>CLI Configuration File</h3><p>Mirrors are configured in a CLI configuration file in the environment where Terraform commands will run. As described in Terraform document:</p><blockquote>The configuration can be placed in a single file whose location depends on the host operating system:</blockquote><blockquote><strong>-</strong> On Windows, the file must be named terraform.rc and placed in the relevant user&#39;s %APPDATA% directory. The physical location of this directory depends on your Windows version and system configuration; use $env:APPDATA in PowerShell to find its location on your system.</blockquote><blockquote>- On all other systems, the file must be named .terraformrc (note the leading period) and placed directly in the home directory of the relevant user.</blockquote><blockquote>The configuration file uses the same HCL syntax as .tf files, but with different attributes and blocks.</blockquote><h3>Dev Overrides</h3><p>The Dev Overrides was introduced from version 0.14, and is quite straightforward. To configure the dev_overrides, we need a provider_installation block in the CLI configuration like below:</p><pre>provider_installation {<br>  dev_overrides {<br>    &quot;registry.terraform.io/hashicorp/example&quot; = &quot;/home/(your user)/customised-providers/terraform-provider-example&quot;<br>  }<br>}</pre><p>This example is to tell Terraform to find the provider with the name <em>“example”</em> from the path <em>“/home/(your user)/customised-providers/terraform-provider-example”</em>. The path is where we should place our provider executables. The <em>“registry.terraform.io/hashicorp/”</em>, which can be kept the same as a prefix for all other providers, is the official hostname and namespace of Terraform’s Registry.</p><p>By using dev_overrides, the <em>terraform init</em> command is NOT needed, and you can go ahead with the plan or apply command.</p><h3>File System Mirror</h3><p>To configure the file system mirror, we need a provider_installation block in the CLI configuration like below:</p><pre>provider_installation {<br>  filesystem_mirror {<br>    path = &quot;/home/(your user)/.terraform.d/plugins&quot;<br>    include = [&quot;local.providers/*/*&quot;]<br>  }<br>  direct {<br>    exclude = [&quot;local.providers/*/*&quot;]<br>  }<br>}</pre><p>In this example, the configuration mirrors the provider registry to a file system with the path <em>“/home/(your user)/.terraform.d/plugins”</em>, and directs Terraform to find providers from <em>“/home/(your user)/.terraform.d/plugins/local.providers/*/(provider name)”</em> when <em>terraform init</em> is run (note that you <strong>cannot use <em>$HOME</em> or other environment variable</strong> to replace the path <em>“/home/(your user)”</em> since Terraform will not parse the variables).</p><p>Therefore, if your module requires the null provider, for example, you need to have it ready in the path so that the hierarchy looks like the following:</p><pre>.terraform.d<br>└── plugins<br>    └── local.providers<br>        └── local<br>            └── null<br>                └── 3.2.1<br>                    └── linux_amd64<br>                        └── terraform-provider-null_v3.2.1_x5</pre><p>In addition to the CLI configuration changes, we also need to specify the provider source in Terraform blocks from the module file to match the path. For example:</p><pre>terraform {<br>  required_providers {<br>    null = {<br>      source  = &quot;local.providers/local/null&quot;<br>      version = &quot;3.2.1&quot;<br>    }<br>  }<br>}</pre><p>After the above are set up, the <em>terraform init</em> command should install the provider for your module from that path and generate some output similar to below:</p><pre>Initializing the backend...<br><br>Initializing provider plugins...<br>- Finding local.providers/local/null versions matching &quot;3.2.1&quot;...<br>- Installing local.providers/local/null v3.2.1...<br>- Installed local.providers/local/null v3.2.1 (unauthenticated)</pre><p>Things to note:</p><ul><li>If you have multi-layer Terraform modules (e.g. module A calls module B from a different directory), <strong>ensure each module’s</strong> terraform.required_providers <strong>block has the source path</strong> like the example above. Otherwise, the module without the configuration will still try to search and download providers from Hashicorp’s registry.</li><li>If your Terraform environment does not have internet access, you may get a checkpoint failure from debug logs. To ignore that, you can add the line “disable_checkpoint = true” to your CLI configuration file.</li><li>The filesystem_mirror.include and direct.exclude are used to match only the providers you want to mirror. If you only want to mirror some particular providers, you can change the values from them. For the example above, the configuration will only mirror the providers which you have specified the source path as <em>“local.providers/xxxx/xxxx”</em>.</li><li>The source path (<em>“local.providers/xxxx/xxxx” </em>used in the example) is also called <em>provider address</em>. It is a three-level address with the syntax hostname/namespace/type (refer to the <a href="https://developer.hashicorp.com/terraform/internals/provider-registry-protocol#provider-addresses"><em>document</em></a> for more details). It can be named as whatever you like, as long as it <strong>does not exceed three levels and matches the hierarchy naming</strong> of your file system for providers. However, if the path has less than three levels (e.g. <em>source=“null”</em>), Terraform will <strong>automatically fill the missing levels with its default value</strong>. That is, if you specify <em>source=“null”</em> and run <em>terraform init</em>, Terraform will actually treat the provider address as <em>“registry.terraform.io/hashicorp/null”</em> which may differ from your hierarchy.</li></ul><h3>Network Mirror</h3><p>The network mirror is similar to the file system mirror, which is also configured from the provider_installation block in the CLI configuration. For example:</p><pre>provider_installation {<br>  network_mirror {<br>    url = &quot;https://artifactory.example.com/&quot;<br>    include = [&quot;artifactory/*/*&quot;]<br>  }<br>  direct {<br>    exclude = [&quot;artifactory/*/*&quot;]<br>  }<br>}</pre><p>In this example, Terraform will install providers from the URL <em>“https://artifactory.example.com/artifactory/xxxx/(provider name)”</em>, when the provider source matches the specified path, like the following:</p><pre>terraform {<br>  required_providers {<br>    null = {<br>      source  = &quot;artifactory/terraform_providers/null&quot;<br>      version = &quot;3.2.1&quot;<br>    }<br>  }<br>}</pre><p>When you run <em>terraform init</em> with the above configurations, Terraform will search and download the null provider by joining the mirror URL and the source path to form a full URL: <em>“https://artifactory.example.com/artifactory/terraform_providers/null”</em>.</p><p>Things to note:</p><ul><li>Like file system mirror, if you have multi-layer Terraform modules (e.g. module A calls module B from a different directory), <strong>ensure each module’s</strong> terraform.required_providers <strong>block has the source path</strong> like the example above. Otherwise, the module without the configuration will still try to search and download providers from Hashicorp’s registry.</li><li>Like file system mirror, if your Terraform environment does not have internet access, you may get a checkpoint failure from debug logs. To ignore that, you can add the line “disable_checkpoint = true” to your CLI configuration file.</li><li>Like file system mirror, network_mirror.include and direct.exclude are used to match only the providers you want to mirror. If you only want to mirror some particular providers, you can change the values from them. For the example above, the configuration will only mirror the providers which you have specified the source path as <em>“artifactory/xxxx/xxxx”</em>.</li><li>Similar to file system mirror, the source path (<em>“artifactory/xxxx/xxxx” </em>used in the example) is also called <em>provider address</em>. It is a three-level address with the syntax hostname/namespace/type (refer to the <a href="https://developer.hashicorp.com/terraform/internals/provider-registry-protocol#provider-addresses"><em>document</em></a> for more details). It can be named as whatever you like, as long as it <strong>does not exceed three levels and matches the hierarchy naming</strong> of the full URL for providers. However, if the path has less than three levels (e.g. <em>source=“null”</em>), Terraform will also <strong>automatically fill the missing levels with its default value</strong>. That is, if you specify <em>source=“null”</em> and run <em>terraform init</em>, Terraform will actually treat the provider address as <em>“registry.terraform.io/hashicorp/null”</em> and the full URL for the provider will become <em>“https://artifactory.example.com/registry.terraform.io/hashicorp/null”</em> instead of <em>“https://artifactory.example.com/null”</em>.</li></ul><h3>Conclusion</h3><p>These three approaches are all very useful but are aimed at different use cases. Based on your situation, pick the one that suits you best. For instance, if you need to test a customised provider without a mix with other Hashicorp providers, dev overrides could be a good fit. Or, if your environment only allows network traffic from some specific sources, you could consider one of the two mirror configurations.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b963117dfffa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/terraform-local-providers-and-registry-mirror-configuration-b963117dfffa">Terraform Local Providers and Registry Mirror Configuration</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Steps for Developing Data Quality Framework with Apache Airflow]]></title>
            <link>https://medium.com/weareservian/developing-5-step-data-quality-framework-with-apache-airflow-972488ddb65f?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/972488ddb65f</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[big-data]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[data-engineering]]></category>
            <dc:creator><![CDATA[Vachan Anand]]></dc:creator>
            <pubDate>Tue, 29 Nov 2022 22:02:38 GMT</pubDate>
            <atom:updated>2022-11-29T22:02:38.253Z</atom:updated>
            <content:encoded><![CDATA[<p>In the recent past, data has become one of the most valuable assets for organisations. Whether optimising an operation or managing a project, we see more and more use of data to make quality decisions in many organisations. Moreover, we see businesses adapting data-driven frameworks to get a competitive advantage in their respective industries. However, more than a large influx and use of data is needed to guarantee quality decision-making. Both the quality and quantity of data make it worthwhile for business intelligence reports or sophisticated machine learning models. This blog will look into practices to manage data quality for data platforms using Apache Airflow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fI5OjUx0uUo_hJRb" /><figcaption>Photo by <a href="https://unsplash.com/@pecarrolo?utm_source=medium&amp;utm_medium=referral">Paulo Carrolo</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Apache Airflow</h3><p>Simply put, Apache Airflow is an open-source workflow orchestration tool. Using Airflow, we build Directed Acyclic Graphs (DAGs) to orchestrate tasks/operations. To learn more about the tool or how to build pipelines for your data platforms using Airflow, look at the following blog.</p><p><a href="https://servian.dev/building-maintainable-data-pipelines-with-apache-airflow-1123aff37787">Building Maintainable Data Pipelines with Apache Airflow</a></p><p>Let us now explore some options for managing data quality using Airflow without further ado.</p><h3>Data Quality on Airflow</h3><p>There are several ways we can build a solution to manage data quality on Airflow. In this blog, we will build a pipeline that automates the process end-to-end. Before we get into the details of the solution, let us look at the essential ingredients for making such a pipeline.</p><ul><li><strong>Create / Implement Rules</strong>: Firstly, we require a mechanism to define and implement rules for data quality. This step involves interacting with the business users to gather requirements on their expectations of the data. For instance, in a database for an e-commerce website that captures user information, a rule could be that a customer’s age should be between 10 and 100.</li><li><strong>Logging and Monitoring</strong>: Once we have created and implemented business rules, we need the means to log if the batch/stream of data loaded into the platform complies with them. As part of the process, we should be able to log successful but, more importantly, instances where the data load fails the business checks.</li><li><strong>Trigger Event:</strong> Next, the pipeline should be able to trigger events based on the success or failure of data to meet specific standards. For instance, if the data breaches a business rule, we could start an event to add a record to the database. On the other hand, on success, we can load the data into the platform.</li><li><strong>Alert and Notification: </strong>As part of the pipeline, when the data does not meet specific standards, we want to notify the business users or data owners about the breach. The alert and notification can take many forms, as discussed later in the blog.</li><li><strong>Build Reports:</strong> Finally, we can build reports to get a glance at data reliability over time. It can be essential for organisations looking to implement strategies to manage organisation-wide data governance/quality. Moreover, It can help the organisation answer the questions such as: <strong><em>Is the organisation getting better with data governance over time or not?</em></strong></li></ul><p>This blog will now look into each component in greater detail and implement a solution on Apache Airflow.</p><h3><strong>Create / Implement Rules</strong></h3><p>Airflow offers several options to manage and implement business checks to allow the flow of good-quality data into data platforms. For instance, while developing a solution, we can use SQL Check or frameworks such as <a href="https://greatexpectations.io/">great expectations</a> to define and test our business rules. Moreover, having access to hundreds of providers such as Snowflake, dbt, etc., we can leverage their data quality frameworks, for instance, <a href="https://www.getdbt.com/product/data-testing/">dbt test</a>, in case the data platform uses dbt as a transformation tool. Additionally, Airflow integrates with some providers nicely and makes operators readily available for use. For instance, using Airflow, we can use a range of SQLCheck Operators to perform standard quality checks, such as whether a column meets data standards. Furthermore, with some operators, such as <a href="https://registry.astronomer.io/providers/apache-airflow/modules/sqlcheckoperator">SQLCheckOperator</a>, we can build complex rules by building custom SQL scripts to cater to complex use cases. Likewise, Airflow also offers <a href="https://registry.astronomer.io/providers/great-expectations/modules/greatexpectationsoperator">GreatExpectationsOperator</a> to integrate with the framework.</p><p>In this blog, we are going to make use of <a href="https://airflow.apache.org/docs/apache-airflow-providers-common-sql/stable/operators.html#check-sql-table-columns">SQL CheckOperators</a> for demonstration purposes. Let us look at an example where we have a table named <strong>ORDERS</strong>, and the expected value of the order amount is <strong>between 0 and 5000</strong>. In such a case, we can make use of SQLColumnCheckOperator as follows.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1dba7469680bede898efe01b3b33a903/href">https://medium.com/media/1dba7469680bede898efe01b3b33a903/href</a></iframe><p>The above code snippet looks for the column <em>ORD_AMOUNT</em> in the table <em>sandpit.dbo.ORDERS </em>and applies the rule so that the amount is between 0 and 5000. Although the snippet works, there are better practices to hardcode the values as part of pipelines. Therefore, as an improvement to make the data quality check more robust, we can tweak the pipeline as follows:</p><ul><li>Firstly we can create a <strong>configuration file</strong> to hold all data quality metrics for the entire dataset. It will act as a single source of truth for the business rules and make it easy to maintain the pipeline.</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fd5de459a3f866021eb83517c643bf64/href">https://medium.com/media/fd5de459a3f866021eb83517c643bf64/href</a></iframe><ul><li>Secondly, we can <strong>parameterise</strong> the script so that we do not have to change the code if the configuration changes. For instance, in the config file above, say the organisation expands and starts operating in France; just by adding an extra item to CUST_COUNTRY, the pipeline should be able to work.</li></ul><p>In Airflow, we can use Jinja templates to parameterise the script. However, in the case of SQLColumnOperator, the attribute column_mapping is not templated.</p><p>To do so, we can create <strong>custom operators</strong>, just like in the example below, to allow templating of fields using Jinja.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5b58a808e6e34ec8c88c122702e58837/href">https://medium.com/media/5b58a808e6e34ec8c88c122702e58837/href</a></iframe><p>Running the above CustomSQLColumnOperator produces the following log:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Yu9mnOkZnw7mcBV0xHJ6Uw.png" /></figure><p>From the task log above, we can observe that the test was evaluated correctly and passed the business rule provided in the configuration file.</p><p>Airflow offers several other SQL Check operators for different use cases. To learn more about each of these operators, check the <a href="https://docs.astronomer.io/learn/airflow-sql-data-quality#sql-check-operators">following link</a>.</p><h3><strong>Logging and Monitoring</strong></h3><p>Logging and monitoring are essential parts of any pipeline, especially for data quality frameworks. Airflow offers a mechanism like Callback to implement logging based on the operator’s state. For instance, in our pipeline above, we can log when the business rule succeeded or failed as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/860b91cc78c52d4f5e42da52eb135e27/href">https://medium.com/media/860b91cc78c52d4f5e42da52eb135e27/href</a></iframe><p>In the code snippet above, we can observe two callbacks for the success or failure of the task. If there is a breach of rules by the data, the CustomSQLColumnOperator will be marked as failed. On failure of the task, the operator calls the callback <strong><em>dq_log_order_fail </em></strong>that prints a short description of the failed task along with the dag’s run id.</p><h3>Trigger Events</h3><p>Now that we have looked into logging &amp; monitoring, the next thing while managing a data quality framework is to be able to <strong>orchestrate tasks based on the outcome of the quality checks</strong>. For instance, in the case of our example above, we would like to orchestrate the following tasks.</p><ul><li>Log an entry in the database to keep a historical track of data quality over time.</li><li>If the data load breaches a business rule, send an alert to a mailbox to notify the data owners/maintainers.</li><li>Load the data into the data platform in case the data aligns with the business rules</li></ul><p>Airflow offers a couple of ways to manage such use cases. In this blog, we will look at <strong><em>trigger rules</em></strong> that we can set at an operator level to start a series of tasks based on the check as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/852/1*aKEqq_HLVIRpMS5LgdOpGQ.png" /></figure><p>We can observe from the DAG above that the <strong><em>CHK_ORDER_AMT</em></strong> has two valid paths. If the check succeeds, we can log metadata into the database and start loading the data into the data platform. However, if there is a breach in business rules, we would like to log some metadata and then alert the data owner/maintainer about the breach. We can implement such a flow as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/474415483ba2b92a027584212811cf2a/href">https://medium.com/media/474415483ba2b92a027584212811cf2a/href</a></iframe><p>The code snippet above shows the task <strong><em>log_failure_db</em></strong> will only trigger if the operator preceding it fails. We can configure different trigger rules on the operators based on different use cases; to know more about the trigger rules, check out the <a href="https://docs.astronomer.io/learn/managing-dependencies#trigger-rules">following link</a>.</p><h3><strong>Alert and Notification</strong></h3><p>Now that we have looked into triggering tasks based on the outcome of the check operator let us look at the final piece of the puzzle. If a load of data fails the check, we would like to alert someone so the business can look into it and take necessary actions. Airflow integrates with several providers, such as Slack, Telegram, etc., to enable alerting and message notifications.</p><p>In this blog, we will create alerts using emails via email operators and <a href="https://sendgrid.com/">Sendgrid</a> as an email service to notify business users. We have to set some configurations before Airflow can successfully send the emails.</p><h4>Configuring Airflow</h4><p>To set up the Airflow for email notifications, we need to do the following:</p><ul><li>Add necessary configurations in airflow.cfg for the email operator to use.</li><li>Add a connection in the Airflow web user interface for the operator.</li></ul><p>We can make use of the following <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/email-config.html">instructions</a> to perform the above tasks.</p><h4>Configuring SendGrid</h4><p>Configuring SendGrid is an easy two-step process.</p><ul><li>Firstly, we create an API key in SendGrid using SMTP Relay. We can do so using the following link.</li></ul><p><a href="https://app.sendgrid.com/guide/integrate">SendGrid</a></p><ul><li>Next, we need to add senders to the account. Senders are email addresses the email operator will use to send notifications to business users. We can add senders as follows:</li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F366851411%3Fh%3D9cf74beb3c%26app_id%3D122963&amp;dntp=1&amp;display_name=Vimeo&amp;url=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F366851411&amp;image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F823031806-c25d7a2cfa80c5cbc1c28efc0a44544cbae94bc648a7e31f5f3a3199cc02e613-d_1280&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vimeo" width="1920" height="1080" frameborder="0" scrolling="no"><a href="https://medium.com/media/ec4cd6c762f54ffdf1616642985da068/href">https://medium.com/media/ec4cd6c762f54ffdf1616642985da068/href</a></iframe><p>Once we setup the configuration on Airflow and Sendgrid we can use the EmailOperator as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a9d0c1fc1cb2bac9f859520311db291f/href">https://medium.com/media/a9d0c1fc1cb2bac9f859520311db291f/href</a></iframe><h3><strong>Build Reports</strong></h3><p>Building a data platform is to have an organisation-wide reliable data source. With a tendency for organisations to become data-driven, it can be hard for non-technical users, especially directors, to get accurate metrics of data reliability. As part of the data quality framework, it is essential to have such metrics visualised so that the key stakeholders can strategise and come up with actionable outcomes to improve the organisation. Therefore, using the logging database, we can build dashboards to aggregate statistics on data quality and present them in an easy-to-understand manner to assist key stakeholders with their decision-making.</p><h3>Conclusion</h3><p>As a platitude, we often hear that garbage in is equal to garbage out, yet we can not stress enough the significance of it. It becomes crucial for organisations to build strategies to monitor data quality, especially as they move towards being data-driven. In this blog, we looked into a five-step data quality framework end-to-end to enable good quality and reliable data flow into the data platform.</p><h3>Read Other Blogs on Data</h3><p><a href="https://medium.com/@vachan15">Vachan Anand - Medium</a></p><h3>Connect On LinkedIn</h3><p><a href="https://www.linkedin.com/in/vachan-anand-26bb76b7/">https://www.linkedin.com/in/vachan-anand-26bb76b7/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=972488ddb65f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/developing-5-step-data-quality-framework-with-apache-airflow-972488ddb65f">5 Steps for Developing Data Quality Framework with Apache Airflow</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cost Effective Airflow tasks using AKS  spot instances]]></title>
            <link>https://medium.com/weareservian/cost-effective-airflow-tasks-using-aks-spot-instances-710dda1f4e99?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/710dda1f4e99</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[dev]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[airflow]]></category>
            <dc:creator><![CDATA[Ashley Rodan]]></dc:creator>
            <pubDate>Tue, 22 Nov 2022 23:54:36 GMT</pubDate>
            <atom:updated>2022-11-22T23:54:36.260Z</atom:updated>
            <content:encoded><![CDATA[<h3>Cost-effective Airflow tasks using AKS spot instances</h3><p>A colleague once said to me that “<em>Kubernetes</em> is the Rolls-Royce of compute”, and only after using it for the last 6 months have I started to realise what he might have meant. Yes it can be expensive to run and maintain, it has all the bells and whistles, but once you get it working, it&#39;s a thing of beauty!</p><p>To be upfront, my current lens of Kubernetes has been using it as a managed service on Microsoft Azure, which is known as AKS — Azure Kubernetes Service.</p><p>A particular feature of AKS which has enabled the project to take advantage of running resource-intensive jobs at a very cost-efficient rate has been <strong>Azure Spot Node Pool</strong>.</p><p>For further context, 10 months ago, the team and I were tasked to build cloud capabilities that could handle a variety of data-related execution tasks. The variety component is any unknown, future setups that could not yet be defined. This could be in the realm of executing data transformations such as dbt jobs, machine learning predictions, and data quality checks to name a few.</p><p>To solve this project variability we took a <em>Platform as a Product</em> approach in the hope it abstracts the complexity of deployment while providing a great developer experience. Choosing the right tools, and the way they interacted had to cater to a diverse set of data arrangements for a range of upcoming projects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dEnpK5MndZTCCVM1" /><figcaption>Photo by <a href="https://unsplash.com/@charles_forerunner?utm_source=medium&amp;utm_medium=referral">Charles Forerunner</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4>The setup we landed on was using Apache Airflow deployed on Azure Kubernetes Service.</h4><p>Further taking advantage of Kubernetes, our Airflow Tasks are run exclusively using the <a href="https://airflow.apache.org/docs/apache-airflow/stable/executor/kubernetes.html">Kubernetes Pod executor</a>.</p><p>The Kubernetes pod executor is in place of other Airflow tasks, such as the Python executor or bash executor, providing you with a verbose yet flexible way to define Kubernetes pods. In essence, to define your Kubernetes pod operator you <em>just</em> point to an image, such as a registered Docker container, define some simple metadata, and optionally add bespoke Kubernetes configurations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b6Q9WNmxOC2zUcMnBZiyKA.png" /><figcaption>Airflow Kubernetes Executor. Source: <a href="https://airflow.apache.org/docs/apache-airflow/stable/executor/kubernetes.html">Official Docs</a>.</figcaption></figure><blockquote>Using Airflow Kubernetes Pod Executor in conjunction with Azure AKS Spot Node pool has allowed us to access large compute resources at a fraction of the cost. (i.e 8GB → 32GB RAM)</blockquote><p>An estimated 1/10th of the costs if we’d not be using a spot instance.</p><p>For most of the data workloads running on our cluster, the shared node resource group works fine. It also meets the need of having a non-spot instance as a default node pool.</p><p>However while running a particular task, which pre-processes data for a machine learning model, the task would consistently error out resulting in an unsuccessful execution 🙅‍♂️.</p><pre>{<br>  &quot;status&quot;: {<br>    &quot;message&quot;: &quot;The node was low on resource: memory.<br>                Container base was using 2200***Ki,<br>                which exceeds its request of 0.&quot;,<br>    &quot;phase&quot;: &quot;Failed&quot;,<br>    &quot;reason&quot;: &quot;Evicted&quot;<br>  }<br>}</pre><p>We maxed out on our shared node resource group (Standard_D2_v3 — 8GB RAM) and had to get access to a lot more RAM. Slightly perplexed at first as the Standard_D2_v3 box technically has enough RAM, we soon understood that there is a fair amount being used for system processors. This resulted in turning to a much larger box (Standard_D8s_v3 – 32GB RAM) to meet the needs of the job. At the time of writing, D8s_v3 is priced at $320 per month within the US, and dearer outside. D8s_v3 spot instance however brings the <a href="https://azureprice.net/?filter=Standard_D8s_v3&amp;tier=spot&amp;timeoption=month&amp;region=centralus&amp;currency=USD">costs down to $32</a>. (<strong><em>Please note</em></strong>: there are <a href="https://learn.microsoft.com/en-us/azure/aks/spot-node-pool">limitations</a> using spot instances &amp; costs are subject to usage.)</p><p>After configuring our new node pool in Terraform (<a href="https://registry.terraform.io/modules/bcochofel/aks/azurerm/latest/examples/spot-node-pool">example</a>), and a peer lookover in a GitLab merge request, our CI deployment pipelines were provisioning our new beefy spot instance!</p><p>With a few trials and errors in understanding, Kubernetes <a href="https://kubernetes.io/docs/reference/labels-annotations-taints/">taints &amp; labels</a>, I was able to knuckle down a winning Airflow task configuration that consistently targets &amp; spins up the pod on the target resource.</p><pre>example_task = KubernetesPodOperator(<br>  image = &#39;acr.azurecr.io/my-image:latest&#39;,<br>  name = &quot;example task&quot;,<br>  task_id = &quot;example-task&quot;,<br>  resources = k8s.V1ResourceRequirements(<br>    requests = {<br>      &#39;memory&#39;: &#39;16000M&#39;,<br>    },<br>  ),<br>  node_selector = {<br>      &quot;node-pool&quot;: &quot;d8sv3spot&quot;<br>  },<br>  tolerations = [<br>    {<br>      &quot;key&quot;: &quot;node-pool&quot;,<br>      &quot;operator&quot;: &quot;Equal&quot;,<br>      &quot;value&quot;: &quot;d8sv3spot&quot;,<br>      &quot;effect&quot;: &quot;NoExecute&quot;,<br>    },<br>    {<br>      &quot;key&quot;: &quot;kubernetes.azure.com/scalesetpriority&quot;,<br>      &quot;operator&quot;: &quot;Equal&quot;,<br>      &quot;value&quot;: &quot;spot&quot;,<br>      &quot;effect&quot;: &quot;NoSchedule&quot;<br>    }<br>  ]<br>)</pre><p>Let me highlight the important components of this Airflow task. After the general arguments, we can define our needed resources, node selectors &amp; and tolerations.</p><p>The <strong>resources</strong> might not always be required, but will help ensure Kubernetes is providing the appropriate compute configuration. <a href="https://codingshower.com/airflow-kubernetespodoperator-set-resource-requests-and-limits/">CodingShower</a> has a great set of examples of resource definitions allowing you to specify CPU, RAM, and storage needs.</p><p>We then configure the <strong>node selector</strong>, which is otherwise known as the node pool label. This is like putting in a preference as to where you want pods to be deployed.</p><p>Lastly, detailing the task pod <a href="https://kubernetes.io/docs/reference/labels-annotations-taints/"><strong>tolerations</strong></a>, as to which taint it can tolerate. Kubernetes is strict on this, and AKS will add taints by default to spot instances. To target a node pool, you’ll need to <strong>add a toleration for each taint</strong>.</p><p>Although there are compelling alternatives to running Airflow, such as <a href="https://www.astronomer.io/">Astronomer</a> and GCP <a href="https://cloud.google.com/composer">Cloud Composer</a>, out-of-the-box Apache Airflow on Azure Kubernetes Service can work great for a range of tasks providing flexible resources and ways to control costs.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=710dda1f4e99" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/cost-effective-airflow-tasks-using-aks-spot-instances-710dda1f4e99">Cost Effective Airflow tasks using AKS  spot instances</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Consulting with Executive Dysfunction]]></title>
            <link>https://medium.com/weareservian/consulting-with-executive-dysfunction-8ffb39dce00b?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/8ffb39dce00b</guid>
            <category><![CDATA[executive-dysfunction]]></category>
            <category><![CDATA[consulting]]></category>
            <category><![CDATA[neurodiversity]]></category>
            <dc:creator><![CDATA[Luna Andreux]]></dc:creator>
            <pubDate>Tue, 22 Nov 2022 01:50:11 GMT</pubDate>
            <atom:updated>2022-11-22T01:50:11.483Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ViLTMy3Yw1yRcggv" /></figure><h3>Introduction</h3><p>You are probably wondering why am I connecting these two concepts together, the answer is: “This is my <em>work</em>-life”.</p><p>To give further context, I was recently diagnosed with ADHD and Autism, which coincidentally sits me in that neuro-divergent sweet spot where my brain doesn’t know what an executive function is and at this point, it’s afraid to ask. I am also a full-time experience and visual design consultant, and in this article I’ll be sharing with you my experience with executive dysfunction and how I’ve learned to overcome its many challenges within the professional consultant industry.</p><h3>What is it?</h3><h4>Description</h4><p>To better understand Executive <strong>Dysfunction</strong>, I think we need to understand what an Executive <strong>Function</strong> is: <em>“Executive function refers to a set of cognitive processes and mental skills that help us plan, monitor, and successfully execute goals.”</em></p><p>Executive functions include basic cognitive processes such as <strong>plan and prioritise, set goals, organise, control impulses, control emotions, think flexibly, initiate tasks and complete, access working memory, and self-monitor.</strong></p><p>To experience<strong> Executive Dysfunction </strong>or EFD: Executive Function Deficit, is to <strong>struggle</strong> with those processes and skills.</p><h4>Cause and coexisting conditions</h4><p>The cause of poor executive functioning has been difficult to pinpoint, as there are many neurocognitive processes in the executive system and each could be compromised by a range of genetic and environmental factors.</p><p>Executive dysfunction is often found in people with disorders including anxiety disorder, major depressive disorder, bipolar disorder, attention deficit hyperactivity disorder, schizophrenia, and autism.</p><h4>Experiencing executive dysfunction can look like</h4><p>Someone who struggles with executive functioning will likely:</p><ul><li>Frequently misplace or lose things</li><li>Find it difficult to manage time, make plans, multitask, stick to a schedule or finish projects</li><li>Often forget appointments and tasks</li><li>Find it challenging to get started on tasks, even for things you want to do</li><li>Have a hard time keeping your office, workspace, and home organised</li><li>Frequently lose or misplace personal items</li><li>Find it challenging to navigate frustration or setbacks</li><li>Have difficulty remembering information or following directions that involve multiple steps</li><li>Find it challenging to control impulses, emotions and changes in mood, or behaviour</li><li>Have trouble putting complex thoughts or abstract concepts into words</li><li>Have difficulty getting organised, as well as avoiding or delaying getting started on tasks</li><li>Make careless mistakes</li><li>Often talk too much or blurt things out</li></ul><p>Please mind that these are some examples, this list is not a checklist. Some people experience all or a number of these. Executive dysfunction can look and feel different to everyone. One of the very common coping mechanisms that people have while having these experiences is to pretend nothing is wrong, better known as <em>masking. </em>This makes it easy to fly under the radar and harder to spot on other people unless they open up about it.</p><h3>What it looks like in the workplace</h3><h4>Examples</h4><p>We can see Executive Dysfunction rear its nasty head within the workplace in intrinsically damaging ways as being:</p><ul><li><strong>Chronic problems with punctuality — being too late OR too early.</strong></li><li><strong>Poor attention to detail</strong></li><li><strong>Poor managing skills (self-management, time-management)</strong></li><li><strong>Unable to scope tasks effectively</strong></li><li><strong>Untidy workstations</strong></li><li><strong>Trouble understanding tasks lacking detail</strong></li><li><strong>Appearing too distracted or lazy</strong></li><li><strong>Difficulty explaining/articulating thought</strong></li><li><strong>Not being flexible</strong></li><li><strong>Difficulty regulating emotional responses and appearing too/highly emotional</strong></li></ul><h4>What it feels like</h4><p>When almost all of those examples have been used in previous annual reviews or informal assessments, this can affect people’s careers significantly and add to an already poor self-esteem:</p><ul><li><strong>Feelings of shame driven by comparing self to others, or by unmet expectations</strong></li><li><strong>Feeling like a failure or a fraud </strong><em>(imposter syndrome)</em></li><li><strong>Constant fear of getting fired</strong></li><li><strong>Feeling like you constantly need to “catch up” to everyone else</strong></li><li><strong>Feeling annoyed at yourself because you can’t ‘insert comparison here’ even though you try your darndest</strong></li><li><strong>Burnout from trying hard every day, but being unable to give yourself a break because of aforementioned reasons</strong></li></ul><p>These are some of the feelings I personally have had and still have every other day. I need to be conscious of them and push them aside to be able to do my job. Often these feelings come from having bad experiences in a previous job or situation. This makes us more prone to “trying harder” which can look like working overtime, on weekends to try to “balance out” our feelings with actions. This usually leads to burnout, where everything just gets magnified and we are left staring at the wall for 7 hours.</p><h3>What are some strategies to work around it</h3><p>Aside from those horrible feelings I shared in the previous section, it also happened that I developed ways of working <strong>around</strong> my brain. These ways are a big bowl of strategies I keep on hand to be able to problem-solve and navigate everyday life as well as work.</p><h4>Strategies based on research</h4><p>Having done some research you will be able to find a vast resource of tips and advice articles, books, videos, etc. The key here is understanding that none of these need to fit you exactly, nor should you think that you <strong>should </strong>be able to use them and thus fix your whole life.</p><p>When doing research, pick and choose whatever resonates with you. But don’t stop there, see how you can change it, reduce steps, add steps and make it your own.</p><blockquote>While there aren’t <em>one-size-fits-all</em> strategies around, the good news is that it <strong>doesn’t matter</strong> what strategy you choose if it works for<strong> you</strong>.</blockquote><p>There are a large number of strategies that float around the internet that are worth a try:</p><ul><li><strong>Cognitive Behavioural Therapy: </strong>You may have heard of this one, a therapy style based on changing specific behaviours.</li><li><strong>Redesign environment: </strong>Change things around!</li><li><strong>Make information external: </strong>Use post-its, a notebook, a kanban board, mural, trello. Have everything visible and easy to reach.</li><li><strong>Use external motivation:</strong> Gamify your life, work towards rewards, celebrate even the little things <em>(get that dopamine!)</em>.</li><li><strong>Break down tasks: </strong>Whenever you get a task and you don’t know where to start, deconstruct it, and look for the task you can start with to get momentum.</li><li><strong>Anticipate inevitable collapse: </strong>Sounds serious but, have multiple plans as well as a retreat strategy up your sleeve. This helps reduce anxiety and makes it easier to improvise, adapt and overcome!</li><li><strong>Multitasking is ok: </strong>It’s important to remember to be kind to yourself, multitasking is not everyone’s cup of tea, but if it is, don’t punish yourself for it. Have music on, belt out musicals or have an audiobook while working if that helps you concentrate.</li><li><strong>Take note of how and where you work best: </strong>Doesn’t need to be a physical note but if your working memory is not great, maybe do write it down. Mainly to know what worked and what didn’t, kind of like a retrospective activity of your different strategies.</li><li><strong>If you get bored of a technique, try a new one:</strong> If you get easily bored or find that suddenly a strategy isn’t working anymore, it’s ok! It’s not a reflection of you being able to use that, but more like your brain may be done with that one. So, the quest begins to find a new one (free dopamine!).</li></ul><h4>Strategies that have worked for me</h4><p>After writing the last section I realise that I have tried all of them at one point or another. However, I still wanted to go through the ones that are currently working for me:</p><ul><li><strong>Create structure EVERYWHERE (or processes):</strong> I have named myself the process gremlin of my team, if you leave something on my lap, I’ll make a process out of it. This has helped me reduce anxiety and know that even when I don’t have a process, I can still make one on the spot. Not really from scratch though, but using deconstructed elements of the other structures I created previously that can help create this new one. (Sounding a lot like Lego)</li><li><strong>Simplify thoughts:</strong> Tricky one, but whenever I have a matted idea or task, I make a Mural braindump where I make post-its of all the elements I am sure of and follow my train of thought or explanation if I’m with someone else. Once everything is laid out in the virtual table, it makes it easier to see the common denominators and patterns. I use this one a LOT.</li><li><strong>Strategise all the things:</strong> I feel strategies are a big common denominator, close relative of structure and processes. As I mentioned in the previous section, this has been something I’ve practised my whole life, mainly because I’m an over-thinker. I know what you will say, over-thinking will make you anxious! Oh I know. However, you can use it as a tool: think of all the ways your task can go, how people can react and think of how you can navigate those situations. In my experience, it has helped me transform all my meetings gone wrong into learning opportunities and I can have a strategy to steer conversations better the next time.</li><li><strong>Deconstruct tasks alone or with someone: </strong>Having used this one a fair bit in my life, there are always situations where I find myself in task paralysis even after I deconstruct a task. Whenever this happens, I reach out to one of my peers and run them through my task and explain where I’m feeling stuck. Then two things could happen: once you explain the task you will see what is getting you stuck and will be able to sort it out. Or, your peer will be able to give you their way of going around it (new strategy alert!).</li><li><strong>Research and exchanging experiences: </strong>Anticipating you will get bored of your strategies and always have an ear out for what works for other people has been the most helpful I think.</li></ul><h3>What can you do to help your peers</h3><p>Arguably most of the strategies and workarounds that I lightly covered in this article will be helpful for people who experience Executive Dysfunction as well as people who don’t.</p><p>These being ideas, advices, brainstorm items, let’s assume I’m adding a please before every statement and that we would be trying our best to:</p><ul><li><strong>Remember everyone approaches tasks differently, including what they find difficult and how they approach problem-solving.</strong> <em>(Things that may be second nature to us may not be for someone else)</em></li><li><strong>Promote safe spaces where it is ok to ask questions and offer support at any level of the organisation. </strong><em>(Moderating knowledge expectations in a team meeting will help people feel at ease asking questions and not feel pressured to understand or know everything)</em></li><li><strong>Expand and clarify task descriptions and steps — both verbally and in writing..</strong> <em>(This helps when your working memory or auditory reception is not the best)</em></li><li><strong>Explain roles, responsibilities and expectations in detail</strong>. <em>(Better understanding what is expected of you and what is your role helps reduce uncertainty and clarify what other roles mean as well. Eg: when and who to ask for help)</em></li><li><strong>Share strategies, frameworks, structures or checklists to complete a task.</strong> <em>(Share with others what works for you if you see them struggling, or if they come for you to help)</em></li><li><strong><em>Avoid making assumptions — check team members’ understanding of the task. </em></strong><em>(e.g. ask them to explain it back to you)</em></li><li><strong>Lean on others and let others lean on you.</strong> <em>(Teamwork makes the dream work, right? Making yourself available to help others deconstruct tasks or go over their task paralysis can save a lot of time and anxiety)</em></li><li><strong>Don’t encourage working overtime.</strong> <em>(Overtime happens, but it’s important that people don’t think they should do it as it could lead to burnout)</em></li><li><strong>Be kind to yourself and others, we are all trying our best.</strong></li></ul><h3>Key Takeaways</h3><ul><li><strong>Executive function</strong> is a term used to describe a range of skills your brain uses to help you organise and access information and emotions. They enable you to plan and prioritise, organise, control impulses, control emotions, think flexibly, initiate tasks, access working memory, and self-monitor.</li><li><strong>Executive dysfunction</strong> (or EFD, Executive Function Deficit) is the term used to refer to difficulties with executive functions.</li><li><strong>Experiencing EFD </strong>can deteriorate a person’s self-esteem and mental health. It can keep you in constant fight-or-flight mode and drive you to burnout.</li><li><strong>Working around EFD</strong> can look like a set of strategies, frameworks or processes that you can trial and iterate as you go along. There is no one-size-fits-all solution, the best way is to take on what works for you and create a bespoke solution for yourself.</li><li><strong>You can help peers with EFD</strong> by following up conversations with emails or written explanations, explaining roles and responsibilities, keeping in mind not everyone’s brain works the same and being patient. Creating a safe and transparent environment for people to speak up can help them seek guidance and support when they need it.</li></ul><p>Thank you so much for reading and do let me know if you found this helpful or if there are things I should add or take out.</p><h3>Resources</h3><p>The following are some references I used to create this article.</p><h4>Articles</h4><ul><li><strong>Healthline:</strong> Understanding Executive Dysfunction and How It Shows Up: <a href="https://www.healthline.com/health/executive-dysfunction">https://www.healthline.com/health/executive-dysfunction</a></li><li><strong>ADDitude Mag: </strong>What Is Executive Dysfunction? Sign and Symptoms of EFD: <a href="https://www.additudemag.com/what-is-executive-function-disorder/#:~:text=Executive%20dysfunction%20is%20a%20term,%2C%20organization%2C%20and%20time%20management">https://www.additudemag.com/what-is-executive-function-disorder/#:~:text=Executive%20dysfunction%20is%20a%20term,%2C%20organization%2C%20and%20time%20management</a>.</li><li><strong>ADHD Australia: </strong>The role of Executive Functions: <a href="https://www.adhdaustralia.org.au/about-adhd/the-role-of-executive-functioning-in-adhd/">https://www.adhdaustralia.org.au/about-adhd/the-role-of-executive-functioning-in-adhd/</a></li><li><strong>Positive Partnerships: </strong>Executive Functioning <a href="https://www.positivepartnerships.com.au/resources/practical-tools-information-sheets/executive-functioning">https://www.positivepartnerships.com.au/resources/practical-tools-information-sheets/executive-functioning</a></li><li><strong>Autism Awareness:</strong> Common things people with autism find difficult <a href="https://www.autismawareness.com.au/adults/common-features">https://www.autismawareness.com.au/adults/common-features</a></li><li><strong>Psychology Today: </strong>Executive Function: <a href="https://www.psychologytoday.com/au/basics/executive-function">https://www.psychologytoday.com/au/basics/executive-function</a></li><li><strong>Wikipedia:</strong> Executive dysfunction: <a href="https://en.wikipedia.org/wiki/Executive_dysfunction">https://en.wikipedia.org/wiki/Executive_dysfunction</a></li><li><strong>Wikipedia: </strong>Executive function: <a href="https://en.wikipedia.org/wiki/Executive_functions">https://en.wikipedia.org/wiki/Executive_functions</a></li></ul><h4>Books</h4><ul><li><strong>Driven to Distraction </strong>(Revised) Recognizing and Coping with Attention Deficit Disorder by Edward M. Hallowell John J. Ratey</li><li><strong>Thriving with ADHD Workbook </strong>for Teens Improve Focus, Get Organized, and Succeed l by Allison Tyler LCSW</li><li><strong>Thriving with Adult ADHD </strong>Skills to Strengthen Executive Functioning by Phil Boissiere MFT [Boissiere MFT, Phil]</li><li><strong>Order from Chaos</strong> The Everyday Grind of Staying Organized with Adult ADHD by Jaclyn Paul</li></ul><h4>Videos</h4><ul><li><strong>ADHD Spotlight — Em Rusciano: </strong><a href="https://youtu.be/4v88Wd20GiU">https://youtu.be/4v88Wd20GiU</a></li><li><strong>Autism in Tech:</strong> on being autistic and building neuroinclusive workplaces in the technology industry: <a href="https://www.youtube.com/watch?v=k9X5tkVyM_A">https://www.youtube.com/watch?v=k9X5tkVyM_A</a></li><li><strong>ADHD in Digital: </strong>webinar with Ani Møller (Professional Audie) and Julia Birks: <a href="https://www.youtube.com/watch?v=96tqUPhG5qs">https://www.youtube.com/watch?v=96tqUPhG5qs</a></li></ul><h4>Helpful links</h4><ul><li><strong>Beyond Blue:</strong> Free support for anxiety, depression and suicide prevention including 6 free sessions with a mental health coach: <a href="https://www.beyondblue.org.au/get-support/newaccess-mental-health-coaching">https://www.beyondblue.org.au/get-support/newaccess-mental-health-coaching</a></li><li><strong>Eating Disorders Victoria: </strong>Free individual, group sessions and registered nurse to help make a recovery plan:</li><li><strong>QLife: </strong>Free call or chat connection support for LGBTQI+ and allies: <a href="https://www.qlife.org.au/get-help">https://www.qlife.org.au/get-help</a></li><li><strong>RUOK:</strong> More links for immediate support, useful tools &amp; resource and other services: <a href="https://www.ruok.org.au/findhelp">https://www.ruok.org.au/findhelp</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8ffb39dce00b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/consulting-with-executive-dysfunction-8ffb39dce00b">Consulting with Executive Dysfunction</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to design CI/CD pipelines]]></title>
            <link>https://medium.com/weareservian/how-to-design-ci-cd-pipelines-8b12188d775?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/8b12188d775</guid>
            <dc:creator><![CDATA[Pat Conheady]]></dc:creator>
            <pubDate>Wed, 16 Nov 2022 22:45:18 GMT</pubDate>
            <atom:updated>2022-11-16T22:45:18.851Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kTPMx5D3LvUqLC4v" /><figcaption>Photo by <a href="https://unsplash.com/@sigmund?utm_source=medium&amp;utm_medium=referral">Sigmund</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In 2010 when <em>Continuous Delivery</em> was published, the job was to take manual build and deployment processes and automate them. Today your organisation is more likely to already have ‘CI/CD pipelines’ but find that they are not fit for purpose — for example, the release cycle requires multiple pipelines to be run in ‘just’ the right order, with the right variables set by hand, etc. In this context the job is to design new or refactored pipelines in an environment where ‘pipelines’ already exist; the key word there being ‘design’.</p><p>Now if you send a DevOps engineer off to design a pipeline, it’s quite possible that they come back a week later with a 1,000-line pull request containing a mix of YAML, Bash, Haskell, and unvetted third-party components. ‘It just needs testing’, i.e. ‘debugging’, i.e. ‘the other 95% of the development effort.’ No design in sight. (Or at least this is how I did CI/CD pipelines when my seniors asked me to do them.)</p><p>Therefore there is a need to put some structure around the process of designing CI/CD pipelines, which this article will set out.</p><h3>Understanding the platform</h3><p>The term ‘CI/CD pipeline’ is a much-abused phrase which really just means some automation that helps you build, test and deploy your code (regardless of whether you’re actually doing CI and/or CD). In practice, this usually means writing some YAML to define a ‘pipeline’ in something like Jenkins, TeamCity, Azure DevOps, etc.</p><p>The structure of the pipeline is based on a few common concepts. The names of these concepts vary across platforms but they should be pretty easy to map.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/844/1*0_cv_57xjYA4YO2Cg3fbFg.png" /></figure><p>The terms ‘server’ and ‘agent’ need to be defined. The ‘server’ is sometimes called an ‘orchestrator’, and may be hidden in the cloud. The ‘agent’ is what runs your jobs, e.g. a physical machine, virtual machine, or container. The architecture usually looks something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rVLpqhvzzwGEahZ0bUfHOQ.png" /></figure><p>In the simplest case, all of this is encapsulated in a vendor’s SaaS offering. As your situation becomes slightly less simple, you grapple with issues like authentication. In the simple case, you click ‘give me a pipeline for this repo’ and it just works. In a less-simple case, you need to provision an access token from your source control repository and get this into the agent’s hands so that it can pull your source code. Related issues include setting up webhooks so that the pipeline server knows about new PRs, merges to trunk, and other events which might serve as triggers. The list could go on forever: you will need to feel your way to a certain extent.</p><p>However, there are some questions you should ask up-front when adopting or setting up a ‘CI/CD pipelines’ platform, and again before adding a new pipeline to your estate:</p><p>How are agents provisioned?</p><ul><li>Manually?</li><li>Infrastructure-as-code outside of the ‘pipelines’ platform?</li><li>Provisioned by the server?</li><li>Single-use (transient) or long-lasting?</li><li>Do jobs run concurrently on the one agent?</li><li>What software and configuration needs to be provisioned on each agent, and how will this be done?</li><li>Do agents need to be segregated, e.g. separate ‘production’ agents?</li></ul><p>How does networking work?</p><ul><li>From the developer to the portal?</li><li>From agents to the server?</li><li>From agents to source code repositories, artifact repositories, etc?</li></ul><p>How do authentication and secret management work (for all components in the architecture)?</p><p>Ideally, these questions are answered once and form the basis for a set of documented patterns for ‘how we do CI/CD pipelines at [insert your organisation’s name here]’. This frees up brain space to deal with the issues specific to a particular pipeline, which we will discuss next.</p><h3>Design process for a pipeline</h3><p>Every pipeline is different (somehow!) but I find that the design process involves much the same steps each time.</p><h4>Step 0: Understand the architecture of the software being built/deployed</h4><p>It’s easy to say ‘let’s automate the build’ without a proper understanding of the thing being built. Look for documentation about the following:</p><ul><li>software components and their relationships (e.g. this library depends on that library)</li><li>runtime components and their relationships (e.g. this service talks to that service)</li><li>technologies in use (e.g. Kubernetes, .NET, PHP, React) and their respective roles.</li></ul><h4>Step 1: Requirements gathering for the pipeline</h4><p>Use the following as a checklist:</p><ul><li>Business value and the ‘customer’ for the pipeline. Ideally, you will have done a ‘value stream mapping’ workshop to get a comprehensive view of what is important about this pipeline and how it fits into the broader picture.</li><li>Inputs such as source code (one or perhaps several repos/branches) and build artifacts.</li><li>Outputs such as build artifacts and deployed services. (This is really the point of the pipeline, I suppose. But, refer again to the ‘business value’ and ‘customer’ for the pipeline, because it may be more complicated than that.)</li><li>Triggers, e.g. on a schedule, upon a commit to trunk, when a new build is published to the artifact repository, etc. Where multiple source repos are involved, you have to decide which one(s) trigger the pipeline to run.</li><li>When triggered by a commit, be clear about which branches should be considered and whether there are any other conditions, e.g. only run the pipeline if certain paths were changed since the last pipeline run.</li><li>Whether multiple concurrent pipeline runs are allowed, and whether multiple concurrent trigger events should cause multiple concurrent pipeline runs, or whether runs should be ‘batched’.</li></ul><h4>Step 2: Sketch the pipeline as a diagram</h4><p>This can just be a set of boxes with arrows between them to denote “after this, do that”. The basic questions are:</p><ul><li>What needs to be done?</li><li>In what order?</li><li>Is there any conditional logic (e.g. skipping steps in certain circumstances)? Make sure to account for all possibilities (‘if X then Y else Z’) — don’t leave the ‘else’ part implicit, or at least document it.</li><li>Are any approval gates required? Note that approval gates should be driven by requirements collected in step 1, not added just because they seem like ‘good practice’ for a pipeline. Approval gates serve specific purposes, such as recording the outcome of manual testing or protecting an environment from unauthorised deployments. If the purpose of an approval gate is not clearly documented, each person will make up their own explanation, leading to conflict later.</li></ul><p>This diagram is important because this is the visual aid you use in conversations about scope. ‘Is X included?’ ‘Yes, here it is in this box.’ or ‘No, where do you think we should add it?’</p><p>The first sketch of this diagram might be very simple, e.g.:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*t6ALbVcfIsBaAyKzPBU6Bw.png" /></figure><p>By the time you get to step 5 below (design review), it might have some more details, e.g.:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HnoQa3dPNO5EUIvs2AcKMg.png" /></figure><p>Where any steps are repeated (or parts of them are common), plan to use templates. If the platform’s templating facilities are inadequate for the task, use what UML would call ‘a class implemented through copy-paste’. Even if the real pipeline is WET, the design should be DRY.</p><p>It’s important to avoid unnecessary detail or noise in the diagram, because that will obscure important points like ‘there are no tests being run in the pipeline!’</p><h4>Step 3: Find implementations for each step</h4><p>For each step in the diagram from step 2, write down how it will be implemented. Recall from the logical architecture earlier in this article that, once you get through all the pipeline orchestration, you’re just running programs on the agent.</p><p>Your ‘pipelines’ platform may come with built-in or off-the-shelf ‘task definitions’ or ‘plugins’ to perform specific tasks such as run an Ant build, build a docker image, etc. These should be used in preference to writing your own implementation, since custom code is a liability. They should also take care of installing the required programs and dependencies, and guide you through their configuration. (However, if the off-the-shelf components are not suitable then refer to step 4 below.)</p><p>Where third-party components are used (e.g. plugins from a ‘marketplace’), flag them for architectural review.</p><h4>Step 4: Design custom code</h4><p>For any of the steps that don’t already have off-the-shelf implementations, you need to write custom code. Before writing this code (except for spikes and proofs-of-concept), write the following down on the pipeline diagram:</p><ul><li>What technology will be used, e.g. Bash, Python, Java, Haskell?</li><li>How will it be monitored, maintained, etc, as would any other software used in production?</li><li>How will runtime dependencies be provisioned on the agent?</li></ul><p>If the custom code seems ‘straightforward’, question what detail is being hidden. For example ‘one line of bash’ might actually invoke some third-party tool that needs to be provisioned, configured, and kept up-to-date.</p><h4>Step 5: Design review</h4><p>Steps 1–4 should be timeboxed to say 1 day to avoid waste. It is better to review a draft and iterate. Furthermore, steps 1–4 should not involve any actual implementation, apart from spikes and proofs-of-concept (which should be explicitly managed as such).</p><p>The design review is where the engineer says to themselves, ‘this is a good design’, or gets a peer or senior to perform the review, depending on what you want to do. This is also the step where the selection of technologies (e.g. Haskell!) and any third-party components are scrutinised by the appropriate authorities within the organisation.</p><h4>Step 6: Implement the pipeline</h4><p>Write a pipeline YAML (or clicky-click, depending on the platform) to reflect the design in your pipeline diagram. For any steps that require custom code, develop it.</p><p>Note that while implementing the pipeline, it is best to avoid repeatedly running the pipeline to troubleshoot issues, particularly the behaviour of custom code. You should understand your agent’s configuration and environment well enough to simply run each step outside of the pipeline until it works. If for example, you have a bash script that ‘works on my machine’ but mysteriously does not work in the pipeline, go back to the first part of this article and resolve the mystery.</p><p>Test-driven development can be cumbersome at the ‘pipeline’ level due to the ‘low-code’ and ‘cloud-hosted’ nature of the tool. However, any custom code can and should be subjected to the same testing as any other software you write.</p><h4>Step 7: Put the pipeline into production</h4><p>Putting a CI/CD pipeline ‘into production’ is always a strange thing to talk about because development tools are usually considered separately from the organisation’s ‘production’ environment and systems. But in terms of the pipeline as a product in its own right, if it is being used by developers then it is in production.</p><p>When replacing existing pipelines (or even when replacing manual processes), run the pipeline in parallel, i.e. trigger both versions to run. Take care not to have conflicting outputs e.g. one pipeline overwrites the other pipeline’s build artifact. This allows you to take your time to validate the behaviour of the new pipeline before using its outputs and switching off the old one.</p><h4>Step 8: Iterate</h4><p>If there are big problems, go back to step 1.</p><p>If not, go back to step 6 and implement the next round of improvements, optimisations, etc.</p><p>Some things to watch out for include:</p><ul><li>disk usage on agents;</li><li>CPU and memory usage on agents (saturation or under-utilisation);</li><li>time taken for pipeline to run — e.g. impact on Developer Experience and lead time from code to release;</li><li>logic/waiting happening on agents — whether this can be shifted from the agent to the server to reduce contention, costs, etc;</li><li>the balance between pre-provisioning tools and data (e.g. base images) onto agents, versus installing them during each pipeline run.</li></ul><p>Note that I list these things here under step 8, not earlier, so that the design process is not derailed by premature optimisation. However, once these things do bite, there is no reason to delay addressing them.</p><h3>Conclusion</h3><p>The careful reader will observe that I have not said anything about how to design CI/CD pipelines well, only how to design them. You can design a bad pipeline with this process, but it will be obvious to others when you do so. On the other hand, this process will help you and your colleagues to collaborate, get a shared understanding of requirements, and efficiently get on with implementing something that will help developers get their code into production more quickly, safely, and reliably. Hooray for DevOps! :-)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8b12188d775" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/how-to-design-ci-cd-pipelines-8b12188d775">How to design CI/CD pipelines</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ingredients of a Data Warehouse]]></title>
            <link>https://medium.com/weareservian/ingredients-of-a-data-warehouse-cd68b48f5306?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/cd68b48f5306</guid>
            <category><![CDATA[data-modeling]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[database]]></category>
            <dc:creator><![CDATA[Kovid Rathee]]></dc:creator>
            <pubDate>Tue, 08 Nov 2022 05:35:25 GMT</pubDate>
            <atom:updated>2022-11-08T05:35:25.351Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_p22T-28cRnX7sIRJxc3sA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@andersjilden?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Anders Jildén</a> on <a href="https://unsplash.com/s/photos/architecture?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><h4>Cutting through the noise around data warehousing</h4><h3>Signal vs. Noise</h3><p>With the appropriation of the term <em>data warehousing</em> to mean a whole lot of things it shouldn’t, the general understanding of what a data warehouse is has become <strong>a nomenclature problem</strong> more than anything else. Many people understand that the distinction between a data warehouse and a database is solely that of the underlying infrastructure.</p><p>Although infrastructure plays a significant role in building a data warehouse, data warehousing has one more aspect, which, I think, supersedes in importance —<strong> data modeling</strong>. Because of the failure to acknowledge data modeling as one of the core ideas behind data warehousing, the common understanding of data warehouses is flawed.</p><p>This article will take you through the three core ideas behind data warehousing and also discuss how data modeling is central to creating a data warehouse:</p><ul><li>Data modeling</li><li>Storage architecture</li><li>Processing architecture</li></ul><p>The article will also discuss how data warehouse platforms are pre-packaged products with a combination of storage and processing and how the data warehouse platforms are not themselves data warehouses. For instance, contrary to popular belief, dumping data into a data warehouse platform like Redshift or Snowflake doesn’t make it a data warehouse. There’s more to it.</p><p>Let’s dive straight in.</p><h3>Three Core Ideas Behind Data Warehouses</h3><p><em>TL;DR — data models, storage architecture, and processing methodology.</em></p><h4>Data Models</h4><p><strong>First</strong>, the <em>database data model</em> fed by applications, third-party integrations, IoT devices, etc., is meant to optimize the application&#39;s performance. You set yourself up for failure when you start overloading those databases with analytical workloads. That is not to say that these databases can’t partially support analytical workloads because they’re modeled a certain way. Still, they should only be used sparingly for such workloads, directed mainly by the application layer.</p><p>How a database is modeled depends on how the application wants to access the data. With relational databases, for instance, applications want to get all the data for an application entity like customers, products, brands, etc. Each entity has extensions based on its actions, such as customers having transactions, brands having products, products having prices, etc. The database model is created in such a way that the application is easily able to access any of these given entities efficiently.</p><p>Let’s look at a simple relational database model that uses an application that allows customers to purchase products belonging to various brands. The different entities in the following diagram have been created to cater to specific features of the application, such as <em>customer signup, customer ordering a product, and customer adding a new address</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QlGFGqYGsXiKaY-hLnuf-g.png" /></figure><p>The design is based on the actions that can be performed on the application. When you start querying the database with this data model (and remember that my example shows an ultra-simplistic data model — in real life, you’ll find much more complicated data models), not to serve the application but data analysts, ML engineers, and data scientists, you’ll start facing two significant problems really quickly:</p><ul><li><strong>Slow queries</strong> — this shouldn’t surprise you as you will have to join many tables to reach the desired output. You’ll need to take care of indexes, partitions, data types, disk-intensive operations, etc. Remember that <a href="https://towardsdatascience.com/explaining-sql-queries-for-better-performance-6be64905eaad">slow queries have a genuine cost attached</a> — they cost a lot more in resource time and block other analysts from doing their work.</li><li><strong>SQL verbosity</strong> — not just the joins but overall unpreparedness for handling such workloads will make your SQL queries much more verbose than they need to be. You’ll have data types that are great for the consumption of the application but not for data analysis (at least not in their native form) — array, JSON, etc.</li></ul><p>To understand more about this, say you want to calculate a month-wise summary of successful transactions for every product in the catalog. You can use the following query to do that — just notice how you have to navigate through different tables to get different pieces of information necessary for your query. And this works completely fine for an application because they are built to serve application <em>features,</em> not <em>aggregates.</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5ef62291566610644fec74efcc1b3250/href">https://medium.com/media/5ef62291566610644fec74efcc1b3250/href</a></iframe><p>Now, suppose you have hundreds and hundreds of such tables to navigate and want to simplify the process of answering business questions. In that case, you must create another data model that serves the purpose. We’ll talk about many data models later, but here’s the simplest one that broadly categorizes all your source tables into facts and dimensions.</p><p><em>Facts</em> are the things you want to measure, such as sales, response time, etc., and dimensions are the things you want to measure across, such as sales by <em>store</em> or sales by <em>country. </em>The following diagram isn’t an accurate description of a data warehouse model. Still, it loosely demonstrates how you will reorganize your data into these two different types of tables in a data warehouse:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kNiRWjGmB674Ba01ibjMPw.png" /></figure><p>When you want to deal with hundreds of facts and dimensions, you want to see the metrics measured. A dimensional model allows you to do that. If you want to just look at <em>transactions by product</em>, you don’t really have to know which brand the products belong to. If you have to measure the sales by the<em> customer&#39;s region, </em>you don’t even have to know<em> </em>who the <em>customer </em>is.</p><p>Remodeling a relational database into a data warehouse data model allows you to connect the measures directly with the dimensions instead of a complex route that you have to take, making a lot of joins. Here’s a simple example of measuring a month-wise summary of transactions by product and by brand separately:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2761a2d13a4d392a84a66410a69a9096/href">https://medium.com/media/2761a2d13a4d392a84a66410a69a9096/href</a></iframe><p>Remember that the above query will structurally remain almost the same, and it would, more or less, be the same number of lines irrespective of the dimension you want to see a metric across. The story will be slightly different when you want to see a metric across multiple dimensions, but you’ll still be far better off than querying a relational data model.</p><p>To summarize, you can use several data modeling techniques when creating a data warehouse. I’ll briefly touch upon these different data warehousing data models:</p><ul><li><a href="https://en.wikipedia.org/wiki/Third_normal_form"><strong>3NF (third normal form) modeling</strong></a> — owing its origins to the entity-relationship modeling methodology, 3NF is also widely used in data warehousing to serve as a normalized layer to the further layers. It provides tremendous flexibility but can end up having really verbose queries.</li><li><a href="https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/"><strong>Dimensional modeling</strong></a> — a modeling technique that restructures the data into denormalized fact and dimension tables to make analytic workloads easier to run. The most popular exponents of this method are the star schema and snowflake schema.</li><li><a href="https://en.wikipedia.org/wiki/Data_vault_modeling"><strong>Data Vault modeling</strong> </a>— a hybrid between 3NF and dimensional modeling, the <a href="https://towardsdatascience.com/the-definitive-intro-to-data-vault-8d43eaad1c38">Data Vault model</a> is much closer to 3NF than to the dimensional model. It tries to keep the best features of 3NF, such as ease of querying highly granular, historical data, and still restructures the data into new types of tables, such as satellites, links, hubs, bridges, and PITs.</li></ul><p>The choice of the data model should be impacted by the type of workload you expect, the scale and speed at which you want the data warehouse to operate, the agility with which you want to adapt to changes in the source systems, and the cost you’re willing to pay for all these things. But the model alone doesn’t seem so critical. It’s just one piece (but a very important piece) of the puzzle. Once you choose the model, you’ll have to store it on memory or disk. Let’s talk about the different storage architectures and their impact on your data warehousing endeavor.</p><h4>Storage Architecture</h4><p><strong>Second</strong>, the application databases&#39;<em> storage architecture (both on disk and memory) </em>is built to serve a specific purpose. Usually, applications use several databases to account for ACID compliance, schema flexibility, in-memory storage, etc. They all have a particular workload they are best designed to support. For instance, as mentioned in this first point, MySQL is designed to support applications that need to read, write, or update a record or a set of records at a time, which means that it makes sense to keep whole records physically close on the disk in a contiguous manner.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JGgZ7K6W_CDxpFgUMjp_gQ.png" /></figure><p>In contrast, analytical workloads usually need the ability to look through specific columns all at once for calculating aggregates, peeking into values of the same column for the next record or several records in a defined window for calculating moving averages, cumulative sums, and so on. Row-based storage won’t make much sense to run those queries. The following image loosely represents the access pattern on disk if you want to access a single column for calculating an aggregate in a row-based storage structure (as in MySQL or PostgreSQL):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sGMo5DasAfmu1fPnO_TDAg.png" /></figure><p>Relational databases work in pages (<a href="https://dev.mysql.com/doc/refman/5.6/en/innodb-file-space.html">MySQL</a>, <a href="https://www.postgresql.org/docs/current/storage-page-layout.html">PostgreSQL</a>). These pages continuously move in and out of the memory based on the workload. You can think of the above block as a page in a database. Even if you need a single record, the whole page gets accessed and moved to the memory. Imagine analytical workloads requiring a single column stored across many database pages. That can’t be efficient! It isn’t.</p><p>To cater to analytical workloads, it makes much more sense to store the data to be aggregated at the exact physical location, the most granular representation of which is a database page. And that page, for column-based storage, will conceptually look something like the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8_xiaA1h2ztgJZji4x5TwQ.png" /></figure><p>The storage arrangement shown above should make it clear how by accessing a small block of disk or memory, you can calculate aggregates, peek into specific columns of leading or lagging rows, etc., for your analytical workloads. The benefit of storing columns contiguously doesn’t end with a smaller search area for specific queries; it also helps compress the column data more efficiently as you are now applying compression to a block of storage that contains data with the same data type. Compression algorithms <a href="https://docs.aws.amazon.com/redshift/latest/dg/c_Compression_encodings.html">save more space for specific data types than others</a>.</p><h4>Processing Methodology</h4><p><strong>Third</strong>, the processing methodology and the processing infrastructure significantly differ in handling your workloads. Traditionally, relational databases have served mid-sized applications using a single-node deployment with appropriate provisions for read-intensive workloads, point-in-time backups, and failovers.</p><p>The philosophy of single-node databases is based on symmetric multiprocessing. With most processors being multi-core, operating systems can split the load between those cores while sharing all other resources, such as IO bandwidth and memory of the system.</p><p>This obviously <a href="https://towardsdatascience.com/throwing-more-compute-at-the-problem-1ceec0cb178a">doesn’t work at a scale</a> where you have to process enormous amounts of data in a very short time. Enter massively-multiprocessing systems. With MPP systems, you can use the age-old computer science method of divide-and-conquer to break down a processing task into many different nodes, which have their processors and do the work in parallel, consequently saving a lot of time for businesses. Here’s what a typical massively parallel processing system looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WdNSG6tu13TBpm6D4SFwJg.png" /></figure><p>Most modern cloud data warehouses are architected as massively parallel processing systems. Popular examples of MPP systems are Snowflake, Databricks (Spark), Redshift, and so on. When choosing between SMPs and MPPs, you need to understand the kind of read-and-write workloads you’re going to have, how you’ll store the data, and the money you’re willing to spend to get the results of your queries faster.</p><h3>Epilogue</h3><p>Having gone through the core ideas — data modeling, storage, and processing, it is clear that the identifying feature of a data warehouse is its <strong>data model</strong>. The <strong>storage</strong> and <strong>processing</strong> architecture depend on the scale and, hence, come later. For a business with low volumes of data, you can start your data warehousing journey by modeling one and exposing it using a traditional relational database, such as MySQL or PostgreSQL. Nothing says you can’t do that.</p><p>Besides the volume of data, at the heart of the data warehousing question also lie the variety of access patterns you expect. Both data volume and access patterns help you navigate the data warehouse storage and processing space much better. In contrast, the choice of data models is usually driven by how fast you want to deliver and how agile you want to be when the systems feeding the data warehouse change.</p><p>How you understand data modeling, storage, and architecture will decide how you understand data warehouses. Are data warehouses just about data platforms, i.e., a pre-packaged infrastructure for data processing, or are they more than that? Data modeling is the key to answering this question.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cd68b48f5306" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/ingredients-of-a-data-warehouse-cd68b48f5306">Ingredients of a Data Warehouse</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Revisiting Databricks Schema Validation and Evolution over Coffee.]]></title>
            <link>https://medium.com/weareservian/revisiting-databricks-schema-validation-and-evolution-over-coffee-1752c69f09b?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/1752c69f09b</guid>
            <category><![CDATA[etl]]></category>
            <category><![CDATA[databricks]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[data-engineering]]></category>
            <category><![CDATA[schema]]></category>
            <dc:creator><![CDATA[Subhasree Mohapatra]]></dc:creator>
            <pubDate>Mon, 07 Nov 2022 00:06:07 GMT</pubDate>
            <atom:updated>2022-11-07T00:06:07.414Z</atom:updated>
            <content:encoded><![CDATA[<h3>Revisiting Databricks Delta Lake: Schema Validation and Evolution over Coffee.</h3><p>Recently as a part of my interest in Databricks, I am going over the fundamental approaches of Delta Lake. The article can be a revisit to many and for anyone new, let’s learn.</p><p>For a quick overview, we know with the enormous increase in data for engineering, we need to ensure that it remains intact and valid from source to target. The open-source storage layer called Delta Lake ensures ACID properties during any ETL process in Databricks. It needs much extra work to bypass the implemented ACID properties of Delta Lake if someone wants to. The data are processed and stored at different data layers(tables) as mentioned below:<br>i) Bronze: Stores the raw data.<br>ii) Silver: Stores the cleaned and refined data.<br>iii) Gold: Stores the data that had taken the shape of information to be used by other data-analytics platform</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Mwlr8LXi2Nl7P5wd_uLVg.png" /><figcaption>Image from <a href="https://www.databricks.com/product/data-ingestion#:~:text=With%20Databricks%2C%20you%20can%20ingest,machine%20learning%20and%20business%20analytics.">Databricks.com</a></figcaption></figure><p>One of the features of Delta Lake is Schema Enforcement and Evolution to handle the vast amount of data consistency. The files are stored in parquet files. As we go further, we will see how schema evolution and validation are considered over the “coffee” data.</p><p><strong><em>Pre-work done</em>:</strong></p><p>The below work has been done behind the scenes :)</p><p>i) Azure platform is being used to store the data(CSV files in ADLS Gen 2 storage account) and launch the Databricks workspace for processing.</p><p>ii) An “all-purpose” cluster had been created. All work is done using the ‘default’ schema of Databricks workspace and all operations are performed using notebooks.</p><h4><strong>Schema Enforcement</strong></h4><p>To begin with, Schema Enforcement implies enforcing the fact that the schema of incoming data cannot have any additional columns or change of data types (i.e, int → string type) from the existing schema of the table. However, having fewer columns is allowed.</p><p>We are trying to construct a delta table named “<strong><em>coffeedetails</em></strong>” table containing the incoming coffee data. Below displays the first set of data that has been entered into the delta table.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e_og4hK_rkzXcpIyyCBIsw.png" /><figcaption>Reading the data from the storage account</figcaption></figure><p>The below shows the existing tables in the datastore of the workspace. There are two pre-existing tables (constructed earlier) ‘c<em>offeelist</em>’ and ‘<em>coffeemenu</em>’.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0GtEEaRLqSDp78pgvLfK-w.png" /><figcaption>Listing out the tables in the ‘default’ schema</figcaption></figure><p>The timestamp and filename of the respective data are added during the runtime for the creation of the delta table as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Yh7R0ueFO3kZdAhh34RLMg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*frCOqwde0cevaMdLUjOKeg.png" /></figure><p>For the second set of data, we have data without the “Price” column as compared to the previous set as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jfub0N5jLyVWO8txpIDIRg.png" /></figure><p>The data is being entered and the final table is shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZF6UQlLXllf5GiYt-qYLHA.png" /></figure><p>The later stage shows how an additional column invokes schema enforcement. This ensures that no change to the delta lake schema occurs. At the same time, the new set of data has an additional column as “Quantity”. An error is thrown as a schema mismatch. This ensures that the data can remains structure remains constant which can be used in various platforms like BI Analytics, Machine Learning, etc. Also, the column names that vary with the case are not being entertained unless the parquet files are overwritten, for example, ‘item_no’ replacing ‘Item_No’ does not reflect. This also ensures the prevention of data dilution.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YMjgef5Zj27kujqwfYOFbg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*30tW4WDe3MNHSzej4cDtzA.png" /></figure><h4><strong>Schema Evolution</strong></h4><p>With changing times, data maturity is evolving, so it&#39;s the business choice if they want to add up more columns, here is where schema evolution takes place. Along with schema enforcement, delta lake also offers schema evolution that implies adding new columns or changing the datatypes of a column. Here for some business reason, we need to add the “Quantity” column hence we perform the below operations and we can clearly see that the column “Quantity” was added to the table.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HMj3p6RrQ1mau1THifkEcg.png" /><figcaption>Final delta table</figcaption></figure><p>Below shows the metadata obtained for the final delta table</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sqrmbnR6IloZtH6Fp7PXNw.png" /><figcaption>Metadata Information</figcaption></figure><p>If we want to change the column names, drop a column, or change the data type of an existing column, then we need to overwrite both schema and data in all parquet files.</p><p>In any case, if the same column (field) with data of a different datatype comes in, the below error pops up.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VTElIhjORYtBXlk9bwybIQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vqed1TAthcB0T9dwzGF1Fg.png" /></figure><p>At the next level, we are trying to fetch the history of actions taken over the tables. This gives an overview for restoration (time travel) of tables in case of the occurrence of any error or failure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CcrfgM5bFaE7eVkj4FdQug.png" /><figcaption>Details for the historical data for the delta table</figcaption></figure><h4>Recovering a version of the delta table</h4><p>This action is also called “Time travel” through data. Sometimes, in any case of failure or error, we can extract a particular version of the delta data either by version number or timestamp to investigate and restore the latest correct data. Here we get back to version 0 of the delta table.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*abTYxGdEELhFyCECp_T9YA.png" /><figcaption>Restoring table using Timestamp</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dZt_EnjN6CtHst8tvKWKkQ.png" /><figcaption>Restoring table using Version</figcaption></figure><p>After restoring the delta table to its version 0 (the initial version of the table without any additional transformation).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wkJowQAUnK6fcg0TpEmEYA.png" /><figcaption>Restored version of delta table (Time travel)</figcaption></figure><p>The above steps demonstrate one of the various key features of Delta Lake in Databricks: Schema Understanding (Enforcement and Evolution). Hope it is a helpful crisp recap /learning. Moreover, a big thanks to Servian for providing the cloud platform to learn and practice.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1752c69f09b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/revisiting-databricks-schema-validation-and-evolution-over-coffee-1752c69f09b">Revisiting Databricks Schema Validation and Evolution over Coffee.</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Are you getting started with Power Apps?]]></title>
            <link>https://medium.com/weareservian/are-you-getting-started-with-power-apps-a83b5486defd?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/a83b5486defd</guid>
            <category><![CDATA[microsoft-dataverse]]></category>
            <category><![CDATA[powerapps]]></category>
            <category><![CDATA[datasource]]></category>
            <category><![CDATA[low-code-development]]></category>
            <category><![CDATA[power-platform-developers]]></category>
            <dc:creator><![CDATA[Deepali Vinay]]></dc:creator>
            <pubDate>Thu, 20 Oct 2022 06:02:01 GMT</pubDate>
            <atom:updated>2022-10-20T06:02:01.199Z</atom:updated>
            <content:encoded><![CDATA[<h4>Know your data sources first</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*76PvbuqKlIYLbmtD5FpUXg.jpeg" /></figure><p>Any application is primarily built on top of data. This data can reside in various types of storage options such as spreadsheets, databases, on-premise or cloud storages. Therefore, a data source becomes a foundation for building a robust, reliable, and scalable digital solution. Knowing various aspects of a data source in the initial phase of the development process, including its benefits, drawbacks, volume of data it can hold, and connectivity to development platforms like Power Apps can save developers and other stakeholders a huge amount of their effort, time, and money.</p><p>This article gives a quick overview of <strong>Power Apps, </strong>one of the core products of Microsoft Power Platform, and briefly touches upon the reasons for its popularity as an application development platform. It delves into some of the <strong>popular data sources</strong> used with Power Apps, the steps to establish a connection, and the limitations of each data source with the aim that the readers would make an informed choice of an appropriate data source before starting actual app development.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/481/1*zHUFr1bLxvBMrTmnE6vxog.jpeg" /></figure><h3><strong>Intro to Power Apps</strong></h3><p>Power Apps is a platform that provides an environment for the rapid development of custom applications and automation of business processes/workflows. It is a l<em>ow-code/no-code</em> solution to quickly build and deploy a logical or digital process on an interface, having a responsive design that can run on both mobile devices and web browsers. The intention of this platform is to empower the team and accelerate yet simplify the app development process.</p><h3><strong>What makes Power Apps great?</strong></h3><p>Power Apps provides a suite of data sources, connectors, UI elements, and various services that can enable an app to interact with different cloud services and ecosystems such as <em>Azure cloud components,</em> <em>Microsoft Dataverse, Microsoft 365, SharePoint, OneDrive, SQL Server, Amazon Redshift, Teradata,</em> etc.</p><blockquote>Gartner has recognized Microsoft as a Leader in the 2021 Magic Quadrant for Enterprise Low Code Application Platforms report.</blockquote><h3><strong>Data Sources</strong></h3><p>Some of the popular data sources used with Power Apps are Microsoft Excel, SharePoint List, SQL Server, and Microsoft Dataverse (formerly known as Common Data Service).</p><blockquote>When starting with a Power Apps project, it is essential to consider and understand where the data will be stored and the number of rows or columns that will be required by the app before jumping on the user interface design. This would help avoiding data source limitations and issues with data filtering and <a href="https://learn.microsoft.com/en-us/power-apps/maker/canvas-apps/delegation-overview"><strong>delegation</strong></a> in the future.</blockquote><p>Power Apps can retrieve up to <strong>2000 rows</strong> from its data source connections where delegation is not supported. Therefore, it becomes essential for developers to judiciously and effectively use filtering functions that are delegable, to be able to bring in relevant data into the app.</p><h4><strong>1. Microsoft Excel</strong></h4><p>Excel can be a viable option to choose as a data source for either personal projects or a quick proof of concept on a small tabular dataset with a few thousand rows or if external data is stored in spreadsheets.</p><p><strong><em>Steps to connect :</em></strong></p><p>a) Open a blank canvas app on the Power Apps web portal <a href="https://make.powerapps.com/">https://make.powerapps.com/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*80Y1Dy8b2OeG6AC_Gn-3bg.png" /></figure><p>b) In the Data pane, add Excel Online as a data source.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gAnp8lRMe_6h0tdZgOs5PQ.png" /></figure><p>c) Select a location of the excel file ➜ Select the excel file ➜ Select the excel table within the file</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ve0V1WWHlQBsrSR5B-ODIw.png" /></figure><p>d) Select an identifier from the excel table or insert an auto-generated id into the table and click on connect to view the excel table in the Data pane. Once the selected excel table is visible in the Data pane, it is ready to be consumed within the app UI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tjm3fGoFgU2hNOCbf2k1-w.png" /></figure><p><strong><em>Limitations of Excel Online (Business) connector :</em></strong></p><ul><li>Excel file data should be formatted as a table for Power Apps to parse the information.</li><li>Excel Online (Business) connector supports Excel files of a maximum of 25 MB.</li><li>After the use of this connector, an Excel file may be locked for any updates or deletes for up to 6 minutes.</li><li>Concurrent data writes to a single Excel file by multiple connectors or users is not supported.</li><li>Excel as a data source does not support delegation.</li></ul><p>Read more about Excel Online (Business) connector <a href="https://learn.microsoft.com/en-us/connectors/excelonlinebusiness/">here</a>.</p><h4><strong>2. SharePoint List</strong></h4><p>SharePoint list is a collection of data that can be made available to selected team members by granting suitable permissions. It is tabular and can be used to store attachments, files and images as well.</p><p>Access to SharePoint is included in the majority of Microsoft 365 subscription plans. This makes SharePoint a viable option as a data source for a ‘no cost implementation’ of a full-fledged solution on Power Apps, without the need to purchase a premium license for Power Apps, although with some limitations on the number of delegable functions and access to only standard free connectors.</p><p><strong><em>Steps to connect :</em></strong></p><p>a) In the Data pane, add SharePoint as a data source.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zyg2bJjcyLct2VYT5-zwqw.png" /></figure><p>b) Connect to a SharePoint cloud service or an on-premises data gateway and follow the steps to connect to any SharePoint list within a SharePoint site.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5h36N0ocONUh8-iwQ6qEQw.png" /></figure><p>c) Once the selected SharePoint list is visible in the Data pane, it is ready to be consumed within the app UI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0q298hfM5F3mntu0ri4amA.png" /></figure><p><strong><em>Limitations of SharePoint connector :</em></strong></p><ul><li>SharePoint lists have limited support for delegation which means filtering/lookup/searching of data is restricted.</li><li>Users must also have access to the underlying lists if the Power App built using SharePoint is to be accessed by them, which means the users will be able to edit/delete the data directly from SharePoint portal if they want to.</li><li>Each SharePoint list is independent and cannot be used as a relational database.</li><li>Data from SharePoint on-premises cannot be accessed directly. To send/receive data to SharePoint on-premises lists while using PowerApps with SharePoint On-premises, a server-side on-premises data gateway configuration is required.</li></ul><p>Read more about SharePoint (online) connector <a href="https://learn.microsoft.com/en-us/connectors/sharepointonline/">here</a>.</p><h4><strong>3. SQL Server</strong></h4><p>Microsoft SQL Server is a relational database management system. It allows users to perform CRUD operations on the rows in a table at the source. It supports Active Directory authentication which means the data used by Power Apps does not have to be explicitly shared with the user unlike SharePoint. The data access level can be managed at AD level.</p><p>SQL Server connector is a <strong><em>premium connector</em></strong> in Power Apps. Therefore, the end users must have a premium license, such as Power Apps per app or per user plan, in order to connect to the source and use the app.</p><p><strong><em>Steps to connect :</em></strong></p><p>a) In the Data pane, add SQL Server as a data source.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X8G3PPGpPJ0sGhF8jFWN2A.png" /></figure><p>b) Select the appropriate <a href="https://learn.microsoft.com/en-us/power-apps/maker/canvas-apps/connections-list#security-and-types-of-authentication">authentication type</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Hr0ndJMMQdfC1q3FysDLSw.png" /></figure><p>c) Provide SQL server and database name to select and connect to the required table.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pjR90APu0oFi-XbU5NLWwg.png" /></figure><p>d) Once the selected SQL table is visible in the Data pane, it is ready to be consumed within the app UI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z8UE73HxPBUtP2RfZWd-aw.png" /></figure><p><strong><em>Limitations of SQL Server connector :</em></strong></p><ul><li>Insert and update to a table does not work if a SQL server-side trigger is defined on the table.</li><li>Power Apps cannot invoke stored procedures.</li><li>The following data types cannot be used as query option predicates — date, datetime, datetime2 and smalldatetime.</li><li>Actions time out if a SQL query takes more than 110 seconds to execute.</li></ul><p>Read more about the SQL Server connector <a href="https://learn.microsoft.com/en-us/connectors/sql/">here</a>.</p><h4><strong>4. Microsoft Dataverse</strong></h4><p>Microsoft Dataverse (formerly Common Data Service) is a managed and secure data store with data stored within a set of tables, each used for a specific business need. It provides both row and column-level security along with sharing and auditing features.</p><p>Dataverse comes with a basic set of default tables that address common business scenarios. Custom tables can be created specific to an organisation or a business requirement and populated with data using Power Query which then can be used by developers to build rich applications using Power Apps. It provides <strong>better delegation support</strong> compared to any other data source</p><p>The access to the Dataverse tables depends on the environment in which the Power App is developed. No additional connectors are required since the app is by default connected to Microsoft Dataverse when a new Canvas Power App is created within an environment. Another feature of Dataverse is that it can house an organisation’s data models and is the only data source that supports Model-Driven Power Apps.</p><p>The below images illustrate another key benefit of Dataverse which is <strong>performance</strong>. Unlike in the case of any other online data source, Power Apps connect with Dataverse more directly without going through multiple networking layers. This makes the Dataverse connector the <strong>fastest connector</strong> to access data in the context of Power Apps.</p><p><strong>Other Data Sources</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/949/0*nSm66jAwIrwT92pK.png" /><figcaption>Data call flow with online data sources (Source: <a href="https://learn.microsoft.com/en-gb/power-apps/maker/canvas-apps/execution-phases-data-flow">Microsoft</a>)</figcaption></figure><p><strong>Microsoft Dataverse</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/564/0*NrT85TiTG6-bw99n.png" /><figcaption>Data call flow with Microsoft Dataverse (Source: <a href="https://learn.microsoft.com/en-gb/power-apps/maker/canvas-apps/execution-phases-data-flow">Microsoft</a>)</figcaption></figure><p>Dataverse connector is also a <strong><em>premium connector</em></strong> in Power Apps, thus it requires premium licenses such as Power Apps per app or per user plan, in order to connect this source and use the app.</p><p><strong><em>Steps to connect :</em></strong></p><p>a) Click on Add data to view all the default Microsoft Dataverse tables available in the current environment of Power Apps under the Tables section. Select any Dataverse table to consume it within the app UI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1_YzzwLpr_VK4GsEIRwsTw.png" /></figure><p>b) The complete list of default/standard and any custom Dataverse tables can be viewed on the Power Apps home screen under the Tables section within Dataverse as shown in the below image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QT0YY8GbHiEKOacKb6V4lA.png" /></figure><p>c) To create custom tables, the user must have either a System Administrator or System Customizer security role within Microsoft Dataverse. Click on New table to create a custom Dataverse table and follow the steps. This custom table can then be used as a data source by selecting it in the Data pane within an app, similar to other sources.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OuA95G7ym-lDAsJxZ5zj_w.png" /></figure><p><strong><em>Limitation of Dataverse connector :</em></strong></p><ul><li>Performing complex table queries, for example, join multiple tables, union/combine multiple tables, or aggregations can be challenging to execute with Dataverse. SQL Server provides better support in this regard to perform such operations efficiently.</li></ul><p>Read more about Microsoft Dataverse connector <a href="https://learn.microsoft.com/en-us/connectors/commondataserviceforapps/">here</a>.</p><h3>Summary</h3><p>Selecting an appropriate data source for any Power Apps use case is crucial prior to Power Apps design and development. Some of the factors that should be considered before making a choice are business requirement, data volume, budget constraints, existing infrastructure &amp; services, performance overhead, and security. Also note that each storage has a different capability or limitation to perform CRUD operations.</p><p>Being aware of possible data source bottlenecks and making an informed choice of data sources will help in building a robust and scalable application. It will also make the application development process easier and more efficient without facing hurdles midway.</p><p><strong><em>Additional sources :</em></strong></p><ul><li><a href="https://learn.microsoft.com/en-us/power-apps/powerapps-overview">What is Power Apps? - Power Apps</a></li><li><a href="https://learn.microsoft.com/en-us/power-apps/maker/data-platform/data-platform-intro">What is Microsoft Dataverse? - Power Apps</a></li><li><a href="https://learn.microsoft.com/en-gb/power-apps/maker/canvas-apps/slow-performance-sources">Common sources of slow performance for a canvas app - Power Apps</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a83b5486defd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/are-you-getting-started-with-power-apps-a83b5486defd">Are you getting started with Power Apps?</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating Cyclical Dependencies in DBT]]></title>
            <link>https://medium.com/weareservian/creating-cyclical-dependencies-in-dbt-92fdb739a3fb?source=rss----1f080c3ceb95---4</link>
            <guid isPermaLink="false">https://medium.com/p/92fdb739a3fb</guid>
            <category><![CDATA[data]]></category>
            <category><![CDATA[data-warehouse]]></category>
            <category><![CDATA[dbt]]></category>
            <dc:creator><![CDATA[Jordan Sands]]></dc:creator>
            <pubDate>Tue, 18 Oct 2022 22:25:00 GMT</pubDate>
            <atom:updated>2022-10-18T22:25:00.331Z</atom:updated>
            <content:encoded><![CDATA[<h3>Creating Cyclical Dependencies in dbt</h3><h3>Introduction</h3><p>dbt is a handy tool, it accelerates data warehouse transformations, writes its own documentation, and provides simplicity in its approach to testing. But with these benefits, come some restrictions; I have at times, been frustrated by the limitations and guard rails imposed by dbt. One such limitation is not allowing a cyclical dependency between dbt models.</p><p>This article covers a workaround I’ve built to address this restriction. It assumes the reader has some basic dbt knowledge and experience.</p><h3>The Challenge</h3><p>A dbt project is a collection of models, macros, tests, snapshots, seeds, and some configs. I’d like to draw your attention to the models today, the meat of dbt.</p><p>dbt relates models to each other using a Directed Acyclic Graph (DAG). This defines dependencies between each dbt model.</p><p>Here is a screenshot of the dbt docs generated from a sample project, built for this article. It can be seen that model_b is built using data in model_a . It can be said thatmodel_b is <strong>dependant</strong> on model_a</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4xKLrTpOvVeBgxEfbKs43Q.png" /></figure><p>Imagine a case where we want model_a to be dependent on the <strong>current state</strong> of model_b . This is not allowed in dbt, unsurprising as this graph would no longer be acyclic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*c-rshSs6f8qZuPnikyPGJg.png" /></figure><p>If possible, this would allow the state of the data maintained in dbt to evolve over time like so:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u569-GeDW1ImjpSf69HrxQ.png" /></figure><p>However, when attempted, dbt throws an error:</p><pre>RuntimeError: Found a cycle: model.dbt_cyclical_project.model_a --&gt; model.dbt_cyclical_project.model_b</pre><p>This guide will walk through how such a cyclical dependency, if desired, can be created in dbt.</p><h3>Solution</h3><p>The solution involves four parts</p><ol><li>Creating a macro to clone model_bto a new Snowflake table.</li><li>Creating a new dbt model to reference the result of the clone</li><li>Calling the macro in the pre-hook of model_a</li><li>Refer to the new dbt model in model_a</li></ol><p>Here is a schematic of the solution:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g0pic35rlNtkveRdJffCNw.png" /></figure><h4>But First, Reconsider Your Need To Do This!</h4><p>This is not a normal thing to do with dbt and your issue could perhaps be addressed with other clever ideas applied to dbt. This guide should be used carefully.</p><p>I found this technique useful for a client when we were using dbt to establish a hierarchy of records in model_a to be maintained in model_b, with the latter to be published to an external system. The issue arose when the current state of the hierarchy in model_b was needed to influence how dbt should compute model_a on the next run.</p><p><strong>Note: </strong>In normal circumstances, dbt is <strong>idempotent</strong>; running it once creates the same output as running it 1,000 times. But, by using data that has already been built by dbt, that behaviour is likely to change.</p><h4>Clone Macro</h4><p>The first and most complex step is to create a macro to clone model_b .</p><p>Before doing this, it is important to note that dbt points its output to locations inferred from the selected <a href="https://docs.getdbt.com/reference/dbt-jinja-functions/target">target</a>. The schema and databases to be used are inferred from the value of the dbt target’s schema and database parameter respectively.</p><p>The code developed needs to dynamically adjust at runtime by reading the user profile, without hardcoding the database or schema name. This is done in dbt code by instead using jinja like so:</p><pre>{{target.database}}.{{target.schema}}</pre><p>At runtime dbt transforms this expression according to the <strong>target </strong>database and schema.</p><p><strong>Creating a Base Case</strong></p><p>In most circumstances,model_bwill have been built by dbt and be available to clone, but on occasion, it will not yet exist, this could occur when dbt is running for the first time. If this happens, dbt will throw an error, this is because:</p><p>1) The table can’t be cloned in the macro and</p><p>2) The cloned table won’t exist when dbt attempts to read from it.</p><p>The workaround for this is to create a base case. Logic is included in the macro to check if model_b exists. If it does not exist, then an empty table will be created with the same structure as model_b, thus throwing no error.</p><p><strong>Pseudo Code</strong></p><ol><li>Create the required database schema if none exists</li><li>Check if model_bexists.</li><li>If model_bexists, clone it to a new table</li><li>If model_bdoes not exist, make a base case for it by creating an empty table.</li></ol><p><strong>Example</strong></p><p>Here is an example macro (below). This script implements the pseudo code above. It creates a schema if none exists, and either clones model_bor creates an empty table with the same columns names and data types.</p><p>Note that lines 1–30 define queries that are executed in later lines. Lines 31 onwards execute the queries defined in lines 1–30.</p><p>Note: In my case, using Snowflake, it was necessary to set +transient: false in the dbt_project.yml file, click <a href="https://docs.getdbt.com/reference/resource-configs/snowflake-configs#configuring-transient-tables-in-dbt_projectyml">here</a> for more information.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/224545ef442ba7f0fc61582105579708/href">https://medium.com/media/224545ef442ba7f0fc61582105579708/href</a></iframe><p>Note that the execute flag is used, to only check the result of the query during dbt’s seconds pass over the script. For more information on how dbt processes macros, check out <a href="https://docs.getdbt.com/reference/dbt-jinja-functions/execute">the dbt documentation here</a>.</p><h4>New dbt Model</h4><p>The above macro creates a table called model_b_clone. This can be referenced directly in our dbt code with {{target.database}}.{{target.schema}}_DBT_CLONES.model_b_clone. But this is hardcoded, will be invisible to dbt and won’t appear in the DAG in our project documentation.</p><p>To fix this, let’s create another dbt model, let’s call it model_b_clone:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d5aa96c22e0ca24905d11cfc4eb4b408/href">https://medium.com/media/d5aa96c22e0ca24905d11cfc4eb4b408/href</a></iframe><p>Note that this table is <a href="https://docs.getdbt.com/docs/building-a-dbt-project/building-models/materializations"><strong>ephemeral</strong></a>, it won’t be created in the data warehouse, it is instead a component only to be used by dbt for referencing in other tables and documentation.</p><p>We can now reference the clone with dbt&#39;s standard jinja syntax{{ref(&#39;model_b_clone&#39;)}}.</p><h4>Pre-Hook Change</h4><p>The clone_model_b_macro macro needs to be run immediately before model_a is run so that the data from model_bis available when model_a is run.</p><p>To achieve this, the macro is called as a pre_hook for the model_a model, <a href="https://docs.getdbt.com/reference/resource-configs/pre-hook-post-hook">more on dbt hooks can be found here</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1eb4413217bf0b7f6beeba9c4bc68d44/href">https://medium.com/media/1eb4413217bf0b7f6beeba9c4bc68d44/href</a></iframe><p>Calling the macro as a pre_hook for model_a ensures that before model_a runs, the model_b_clone will be an exact replica of model_b. This can then be used to build model_a .</p><h4>Reference New Table</h4><p>After the above steps are complete, the new dbt model can be referenced like any other using Jinja:</p><pre>{{ref(&#39;model_b_clone&#39;)}}</pre><p>The clone will even appear in dbt’s documentation.</p><h3>Summary</h3><p>This process can be repeated were necessary. It must be noted however, as it is not a supported feature of dbt, that it could cause unexpected consequences if not properly tested. One such consequence is the sacrifice of idempotence, dbt will likely <strong>not </strong>output the same result each time it is run because it is referring to its own output.</p><p>Here is a representation from dbt’s own docs after the change, the red line is superimposed to show what the dbt macro is doing behind the scenes. The new ephemeral model model_b_cloneis referenced by model_a. As a result, each time model_ais computed it takes input from the current state of model_b.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1003/1*u9Xc8TMVwUQETQkAra3YIQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92fdb739a3fb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/weareservian/creating-cyclical-dependencies-in-dbt-92fdb739a3fb">Creating Cyclical Dependencies in DBT</a> was originally published in <a href="https://medium.com/weareservian">Cognizant Servian</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>