<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anton Goncharov</title>
    <description>The latest articles on DEV Community by Anton Goncharov (@antongoncharov).</description>
    <link>https://dev.to/antongoncharov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F567091%2F3fab6ee5-d1ef-4e05-8f0b-d0cb39ed7937.jpeg</url>
      <title>DEV Community: Anton Goncharov</title>
      <link>https://dev.to/antongoncharov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antongoncharov"/>
    <language>en</language>
    <item>
      <title>Sample Surveys Application (Kotlin + Spring + RSocket + Vue.js Demo)</title>
      <dc:creator>Anton Goncharov</dc:creator>
      <pubDate>Tue, 06 Jul 2021 11:30:49 +0000</pubDate>
      <link>https://dev.to/antongoncharov/writing-surveys-application-kotlin-spring-rsocket-vue-js-demo-59ba</link>
      <guid>https://dev.to/antongoncharov/writing-surveys-application-kotlin-spring-rsocket-vue-js-demo-59ba</guid>
      <description>&lt;p&gt;Recently I started building a repo with boilerplate code to facilitate creation of my future full-stack pet projects. Despite it's work in progress and always will be, as I'll continue to implement new features and tweak existing ones, I wanted to share it with the community.&lt;/p&gt;

&lt;p&gt;Check out the GitHub repo I'm covering in this post:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anton-goncharov" rel="noopener noreferrer"&gt;
        anton-goncharov
      &lt;/a&gt; / &lt;a href="https://github.com/anton-goncharov/kotlin-vue-surveys-demo" rel="noopener noreferrer"&gt;
        kotlin-vue-surveys-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Boilerplate Kotlin+Vue fullstack application made with Spring, JWT, WebFlux, H2, JPA, RSocket. Implements sample surveying functionality.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;It's a sample "surveys" application with the actors of two roles: coordinators and respondents. Coordinators are allowed to create &amp;amp; edit polls, then review response statistics. Respondents have read-only view with the only option to submit survey responses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79bhx6kxb26m79p38g8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79bhx6kxb26m79p38g8l.png" alt="surveys-list"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzgzsski4ugmjqdbzfep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzgzsski4ugmjqdbzfep.png" alt="editing-survey2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the key features is that the statistics data is refreshed in real time on a survey stats page 📊. It works by using Rsocket and Reactive Streams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyia80rltd5usxqpga0b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyia80rltd5usxqpga0b.gif" alt="surveys"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;p&gt;This demo application showcases the following list of concepts:&lt;/p&gt;

&lt;h4&gt;
  
  
  Kotlin and Spring backend API development
&lt;/h4&gt;

&lt;p&gt;I've started using Kotlin on new backend projects 2 years ago, and it's my first repository to have boilerplate code for full-stack apps with Kotlin. Here I'm using Kotlin in pretty much the same Spring setup as I would use Java.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rapid CRUD bootstrapping using Spring Data REST
&lt;/h4&gt;

&lt;p&gt;It's arguable whether Spring Data REST is a good fit for a production-ready project. On the other hand, it allows a rapid start having full-blown API implementation with sorting, paging and filtering for given entities 💁.&lt;/p&gt;

&lt;p&gt;Any given controller can be extended with additional handlers or reimplemented from scratch as a separate custom REST endpoint.&lt;/p&gt;

&lt;h4&gt;
  
  
  Database migrations with Liquibase
&lt;/h4&gt;

&lt;p&gt;Hibernate JPA auto schema creation was used during the development. After the first version of the schema had been finalized, I generated the Liquibase changelog from JPA entities and disabled ddl-auto by Hibernate.&lt;/p&gt;

&lt;p&gt;To populate schema with some initial data (predefined users), there's sql script on classpath.&lt;/p&gt;

&lt;h4&gt;
  
  
  Security
&lt;/h4&gt;

&lt;p&gt;JWT-based authentication with role-based access is showcased with tokens issued by the backend. ❗️ Such a setup must not be used in production, this functionality is only to demonstrate the flow. In a real solution, use IAM solution like Keycloak or 3rd party SaaS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reactive flow for live data streaming
&lt;/h4&gt;

&lt;p&gt;After reading the official guide on Spring Webflux + RSocket I got an idea to implement some real-time streaming functionality to try Reactive Streams in a demo application setup.&lt;/p&gt;

&lt;p&gt;The survey statistics page is implemented using rsocket.js, it reads the survey response stream data from a Kotlin Flow that is populated with data from R2DBC H2 reactive-ready driver. The charts are updated on a survey stats page in real time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building with Gradle
&lt;/h4&gt;

&lt;p&gt;As a sidenote, I've never used Gradle before, always preferring Maven as a classic tool that makes more sense to me 😃. This was an interesting challenge to create something new with Gradle, especially writing the build script with Kotlin DSL since there're not many ready-to-use examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🔸 Backend
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Kotlin 1.4&lt;/li&gt;
&lt;li&gt;Spring Boot 2.4.3 (JPA Data REST / Hibernate + Security + WebFlux)&lt;/li&gt;
&lt;li&gt;H2 Database with Liquibase database migrations&lt;/li&gt;
&lt;li&gt;Gradle&lt;/li&gt;
&lt;li&gt;JUnit 5&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🔹 Frontend
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Vue.js 2 (with Vuex, Vue-router, Vue-image-upload)&lt;/li&gt;
&lt;li&gt;Bootstrap 4&lt;/li&gt;
&lt;li&gt;RSocket&lt;/li&gt;
&lt;li&gt;Apexcharts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Launching
&lt;/h2&gt;

&lt;p&gt;🚀 To get it up and running follow the instructions from &lt;a href="https://github.com/anton-goncharov/kotlin-vue-surveys-demo#launch" rel="noopener noreferrer"&gt;the GitHub repo&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Please reach me out if you have any questions or feedback. But keep in mind it's a boilerplate code withstanding permanent work in progress 🛠. Cheers!&lt;/p&gt;

</description>
      <category>github</category>
      <category>kotlin</category>
      <category>reactive</category>
      <category>vue</category>
    </item>
    <item>
      <title>Distributed Logs and Tracing with Spring, Apache Camel, OpenTelemetry and Grafana: Example</title>
      <dc:creator>Anton Goncharov</dc:creator>
      <pubDate>Mon, 21 Jun 2021 12:02:46 +0000</pubDate>
      <link>https://dev.to/antongoncharov/distributed-logs-and-tracing-with-spring-apache-camel-opentelemetry-and-grafana-example-554e</link>
      <guid>https://dev.to/antongoncharov/distributed-logs-and-tracing-with-spring-apache-camel-opentelemetry-and-grafana-example-554e</guid>
      <description>&lt;p&gt;I've built an Apache Camel &amp;amp; OpenTelemetry demo project. It showcases how to achieve distributed tracing across Camel routes and other components using OpenTelemetry, which is the OpenCensus and OpenTracing projects merged into a new single specification under CNCF. The project uses Spring Boot as a base service framework, Loki to store logs, Tempo to store traces, Grafana as a visualization software.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anton-goncharov" rel="noopener noreferrer"&gt;
        anton-goncharov
      &lt;/a&gt; / &lt;a href="https://github.com/anton-goncharov/camel-opentelemetry-grafana-demo" rel="noopener noreferrer"&gt;
        camel-opentelemetry-grafana-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An Apache Camel &amp;amp; OpenTelemetry demo project. Uses Spring Boot as a base service framework, Loki as a log storage, Tempo as a trace storage, Grafana as a visualization software.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Apache Camel has added &lt;a href="(https://camel.apache.org/components/3.7.x/others/opentelemetry.html)"&gt;OpenTelemetry support&lt;/a&gt; in the 3.5 release. The official documentation doesn't focus on how to set everything up for logs and traces visibility, so the goal of this example is to fill this gap.       &lt;/p&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; is an open-source project resulted from merging of OpenCensus and OpenTracing. Its purpose is to enable an application's observability by providing a set of standardized data collection tools for capturing and exporting metrics, logs and traces. It's one of the most active CNCF projects these days.&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://camel.apache.org/" rel="noopener noreferrer"&gt;Camel&lt;/a&gt; in tandem with OpenTelemetry instrumentation allows us to have distributed tracing across different routes in one or more services, and to link application logs with these traces, which makes it a great alternative to ELK and similar solutions.&lt;/p&gt;

&lt;p&gt;This logs &amp;amp; traces view is what we're aiming to achieve in the end:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbenz8gj72ppfpsvdesi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbenz8gj72ppfpsvdesi.png" alt="image / grafana / dashboard" width="800" height="508"&gt;&lt;/a&gt;        &lt;/p&gt;

&lt;p&gt;Important note: this example uses Apache Camel 3.10 (the last available version as of June 2021), which depends on OpenTelemetry SDK for Java version 0.15.0. OpenTelemetry specification and its tools develop rapidly, now beyond 1.x release. In the Camel tracker I see the plans to upgrade dependency but today make sure 0.15.0 is used to run this example smoothly.     &lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The project is a Spring Boot web application named 'hello-service' serving 2 endpoints. &lt;code&gt;/hello&lt;/code&gt; responds with "Hello, ${name}" and &lt;code&gt;/dispatch&lt;/code&gt; passes the request to a downstream service. &lt;/p&gt;

&lt;p&gt;The docker-compose config spins up 5 container instances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hello-service (1)&lt;/strong&gt; (container "dispatch") accepts requests and dispatches them down to the &lt;strong&gt;hello-service (2)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hello-service (2)&lt;/strong&gt; (container "hello") handles dispatched requests &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;loki&lt;/strong&gt; is a logs storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tempo&lt;/strong&gt; is a traces storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;grafana&lt;/strong&gt; is a web dashboard with loki/tempo data visualizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interacting &lt;strong&gt;hello-service (1)&lt;/strong&gt; and &lt;strong&gt;hello-service (2)&lt;/strong&gt; are here to demonstrate how OpenTelemetry traces requests across different containers.   &lt;/p&gt;

&lt;p&gt;The architecture overview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuq2odpzk63pi5t9nt5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzuq2odpzk63pi5t9nt5e.png" alt="image / architecture" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both 'hello' services send logs to Loki via &lt;a href="https://grafana.com/docs/loki/latest/clients/docker-driver/" rel="noopener noreferrer"&gt;&lt;code&gt;loki-docker-driver&lt;/code&gt;&lt;/a&gt; and traces to Tempo via the OpenTelemetry exporter. Grafana uses Loki and Tempo as data sources. Collected logs are linked to the trace data by using traceId assigned by the OpenTelemetry instrumentation.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation" rel="noopener noreferrer"&gt;OpenTelemetry instrumentation&lt;/a&gt; dynamically captures telemetry from a number of popular Java frameworks. To plug it in, add &lt;code&gt;opentelemetry-javaagent-all.jar&lt;/code&gt; as a javaagent of the JAR application. This preparation is done in the Dockerfile.&lt;/p&gt;

&lt;p&gt;For the Camel integration it's important that we use &lt;code&gt;opentelemetry-javaagent-all.jar&lt;/code&gt; &lt;a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/v0.15.x" rel="noopener noreferrer"&gt;version 0.15.0&lt;/a&gt; as &lt;a href="https://camel.apache.org/components/3.7.x/others/opentelemetry.html" rel="noopener noreferrer"&gt;&lt;code&gt;camel-opentelemetry&lt;/code&gt;&lt;/a&gt; depends on this OTel Java SDK release.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; /agent/opentelemetry-javaagent-all.jar /etc/agent/opentelemetry-javaagent-all.jar&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java", "-javaagent:/etc/agent/opentelemetry-javaagent-all.jar" , "-jar", "observable-service.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Camel 3.5+ it's required to add the &lt;code&gt;camel-opentelemetry-starter&lt;/code&gt; dependency. Then, in a &lt;code&gt;RouteBuilder&lt;/code&gt; class, set up the tracer as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;OpenTelemetryTracer&lt;/span&gt; &lt;span class="n"&gt;ott&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenTelemetryTracer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;ott&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContext&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The docker-compose configuration has a few items to highlight.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt; is an endpoint where to send the opentelemetry data. In our case it's the Tempo's receiver.&lt;/li&gt;
&lt;li&gt;We don't send metrics in this demo, so it's disabled to hide all related warnings.&lt;/li&gt;
&lt;li&gt;The downstream endpoint point to the address of the second service to show how distributed tracing works.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;logging&lt;/code&gt; sections states that the container's stdout should be pipelined to the Loki storage by using the &lt;a href="https://grafana.com/docs/loki/latest/clients/docker-driver/" rel="noopener noreferrer"&gt;&lt;code&gt;loki-docker-driver&lt;/code&gt;&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dispatch-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello-service:1.0.0&lt;/span&gt;
  &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dispatch&lt;/span&gt;
  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tempo-net"&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:55680&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_EXPORTER_OTLP_INSECURE=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_METRICS_EXPORTER=none&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_RESOURCE_ATTRIBUTES=service.name=dispatcher&lt;/span&gt;
    &lt;span class="c1"&gt;# sends requests to the 'hello-service' container&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SRV_DOWNSTREAM_ENDPOINT=http://hello:8080/hello&lt;/span&gt;
  &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;loki&lt;/span&gt;
    &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;loki-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3100/loki/api/v1/push"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second service instance has the similar setup except for the fact that it has no downstream service.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;application.properties&lt;/code&gt;, the &lt;code&gt;logging.pattern&lt;/code&gt; formats log output in a way to include &lt;strong&gt;traceId&lt;/strong&gt; and &lt;strong&gt;spanId&lt;/strong&gt;. It's necessary for the system to be able to index logs and link them to traces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loki
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt; is a scalable log aggregation system to use with Grafana.&lt;/p&gt;

&lt;p&gt;The Loki config is pretty much default. It exposes port 3100 so all the other docker containers can send logs there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;loki&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;loki"&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/loki:2.2.0&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3100:3100"&lt;/span&gt;
  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tempo-net"&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-config.file=/etc/loki/local-config.yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tempo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://grafana.com/oss/tempo/" rel="noopener noreferrer"&gt;Tempo&lt;/a&gt; is a scalable trace storage. It has receivers for Jaeger, Zipkin and OpenTelemetry.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;tempo-config.yaml&lt;/code&gt; is mounted from the project. It disables auth and specifies that Tempo instance should expose an OpenTelemetry receiver. The default OTel port is 55680.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tempo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tempo"&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grafana/tempo:latest&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tempo-net"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./tempo-config.yaml:/etc/tempo-config.yaml&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-config.file=/etc/tempo-config.yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grafana
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; is a visualization and monitoring software that can connect to a wide variety of data sources and query them. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to launch
&lt;/h2&gt;

&lt;p&gt;I used Maven 3.8.1 + JDK 11 to create the demo, so it should work with all version from these onwards.&lt;/p&gt;

&lt;p&gt;Steps to launch and try:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Prepare Docker &lt;/p&gt;

&lt;p&gt;Install Loki driver to Docker (to stream logs from the standard output of a container)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker plugin &lt;span class="nb"&gt;install &lt;/span&gt;grafana/loki-docker-driver:latest &lt;span class="nt"&gt;--&lt;/span&gt; 
&lt;span class="nb"&gt;alias &lt;/span&gt;loki &lt;span class="nt"&gt;--grant-all-permissions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a network for the demo services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create tempo-net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Pack the service with Maven&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Build the container image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; hello-service:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; Run the docker-compose script to bring up the demo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Open a web browser and navigate to the Grafana dashboard: &lt;code&gt;http://localhost:3000&lt;/code&gt;. Go to the Configuration-&amp;gt;Data Sources menu item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6.&lt;/strong&gt; Add new Tempo data source (a storage for traces)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye7ir1ju2a0kh185q3l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye7ir1ju2a0kh185q3l3.png" alt="image / tempo" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.&lt;/strong&gt; Add new Loki data source (a storage for logs)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdvwtj3faph6gzikna43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdvwtj3faph6gzikna43.png" alt="image / loki" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure "Derived Field" in Loki Data Source to relate logs with traces&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl932wyru8vem14wkd2lz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl932wyru8vem14wkd2lz.png" alt="image / loki / derived field" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8.&lt;/strong&gt; Send a sample request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/dispatch?name&lt;span class="o"&gt;=&lt;/span&gt;Ada
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;9.&lt;/strong&gt; After all set and executed as above, browse to the Grafana UI at &lt;code&gt;http://localhost:3000&lt;/code&gt;. Open the "Explore" view and switch to the Loki view using to dropdown on the top.&lt;/p&gt;

&lt;p&gt;Searching for &lt;code&gt;{container_name="dispatch"}&lt;/code&gt; will output the recent logs for the &lt;strong&gt;hello-service (1)&lt;/strong&gt; running in the &lt;code&gt;dispatch&lt;/code&gt; container.&lt;/p&gt;

&lt;p&gt;Note that each log entry now has &lt;strong&gt;traceId&lt;/strong&gt;, a global identifier to track request across interacting services; and &lt;strong&gt;spanId&lt;/strong&gt; that identifies local unit of work (eg. an individual route or a handler within a service). &lt;/p&gt;

&lt;p&gt;Click on an entry that has a traceId. It would unfold a detailed info on the log entry. Next to the "traceId" field there's a button that would carry us to the corresponding tracing.   &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnnfgdy7dx6p6xiobycu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnnfgdy7dx6p6xiobycu.png" alt="image / grafana / log entry" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voilà, we've got to the distributed tracing for this request. Each span has the corresponding log entries grouped under the "Logs" box on this panel.    &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyxiprvodoqjpr8vhy43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyxiprvodoqjpr8vhy43.png" alt="image / grafana / trace" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The combined split view in Grafana allows browsing the logs and traces side by side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbenz8gj72ppfpsvdesi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbenz8gj72ppfpsvdesi.png" alt="image / grafana / dashboard" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;More references on the topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://camel.apache.org/components/3.7.x/others/opentelemetry.html" rel="noopener noreferrer"&gt;&lt;code&gt;camel-opentelemetry&lt;/code&gt; Component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation" rel="noopener noreferrer"&gt;OpenTelemetry Java Instrumentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>camel</category>
      <category>java</category>
      <category>opentelemetry</category>
      <category>grafana</category>
    </item>
    <item>
      <title>Low-Code Tradeoffs</title>
      <dc:creator>Anton Goncharov</dc:creator>
      <pubDate>Wed, 16 Jun 2021 22:01:27 +0000</pubDate>
      <link>https://dev.to/antongoncharov/low-code-tradeoffs-3nmo</link>
      <guid>https://dev.to/antongoncharov/low-code-tradeoffs-3nmo</guid>
      <description>&lt;p&gt;I’ve been a low-code developer and architect for few years consulting clients worldwide. Even though “low-code” is a buzzword these days, the concept and its applications have been around for many years. &lt;/p&gt;

&lt;p&gt;As it’s rather trendy today, I see that many companies great and small are tend to fit in low-code platforms for their needs. I have extensive experience working with such backend solutions in different environments and subjects areas. In addition, I participated in designing and building a new visual development platform. It all gave me an idea of sharing my best experience on this topic, and advise decision makers considering low-code could ultimately optimize software development processes in their organizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is low-code?
&lt;/h2&gt;

&lt;p&gt;Low-code, as the name states, is about building applications using abstractions over code to hide its complexity. This usually implies visual programming tools that make it possible to create something by combining ready blocks and configuring their interactions without traditional coding.&lt;/p&gt;

&lt;p&gt;Such a tool rely on code generation, there’s always a powerful translator under the hood. It maps visual “low-code” representation into actual executable code, then wraps it into an deployable framework. Some of the low-code platforms have cloud integrations so they provide an option to publish the built application into a public domain.&lt;/p&gt;

&lt;p&gt;Low-code embrace many use cases, in my post I’d like to focus on the most powerful tools that enable users to build APIs and microservices to automate complex processes from ground up.&lt;/p&gt;

&lt;p&gt;I don’t want to highlight particular vendor platforms. Out of my experience, different solutions in this area have many features in common. All I’ll note below could be applied to a generic low-code visual tool allowing users to build pipelines and services by chaining pre-built blocks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10iouks4mild8jaw6rv1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10iouks4mild8jaw6rv1.png" alt="Generic Low-Code Platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does it shine?
&lt;/h2&gt;

&lt;p&gt;Firstly, I’d want to highlight the low-code usages where it really makes difference without significant tradeoffs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s great for personal use, especially if one has a little or no experience in programming. Today we’ve got a great lot of services and smart devices. Even with a moderate interest in whole variety of applications, there’re scenarios that could make life easier: from IoT shortcuts to convenient data sync between web apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example: write a pipeline that parses commands from a telegram bot to append new entries to a budget spreadsheet.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For solo developers to automate routine in their pet-projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example: create a service handling orders from a single-page web shop, integrated with Mailgun API to send and track emails.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For startups to implement a throwaway MVP in order to test a hypothesis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Example: a travel agency has decided to start an affiliate program and now they need to implement a dashboard for affiliates to use. While requirements haven’t yet been gathered and a development team hasn’t been packed up, business analysts may scrap a simple solution using a low-code platform.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Low-code in the world of enterprise
&lt;/h2&gt;

&lt;p&gt;There’s always a lot of development going on in big companies. They’re constantly seeking for ways to optimize costs and speed up delivery of new features.&lt;/p&gt;

&lt;p&gt;Low-code may seem to be a silver bullet as it enables more people to write code and accelerates development by reusing ready-to—use blocks. This usually translates to top managers being fascinated by potential benefits of putting development on low-code track.&lt;/p&gt;

&lt;p&gt;My opinion that it’s a popular delusion, and I saw many companies chosen this way but eventually switched back to traditional coding. Below I’ll reason it by listing the frequent issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common challenges
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;As I noted above, what low-code provides us is a convenient level of abstraction above the code. It’s great for rapid prototyping or in case we’re building something that simple so we don’t need to bother about its internals. As long as we start thinking about how underlying code works, and try to adjust the visual design accordingly, we actually no longer need the low-code layer. It’s a red flag when low-code platform users explain how an application works by using terms of the underlying code. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It generates code from the graphical representation. A platform version upgrade may change implementation details which affect how the visual language is translated to code. It may have implications on your application behavior, and such bugs are very difficult to trace down since the platform internals are hidden.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Typically a low-code IDE lacks tooling for editing and teamwork because for vendors it’s hard to implement and maintain such logic when it comes to visual programming.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git support is at primitive level. It goes smoothly only when there’s fast-forward merging. Other cases are tedious to resolve as even when visual graphs are merged correctly, the conflicts in components’ properties make it a mess.&lt;/li&gt;
&lt;li&gt;Most of low-code IDEs don’t have “find and replace” for strings across blocks inputs. A developer should click through all the components and manually rename target value.&lt;/li&gt;
&lt;li&gt;Some tools may partially provide it, but often there’s no functionality to navigate throughout the project, e.g. “Find Usages”, “Find Duplicates” or “Browse Hierarchy”. And as a consequence, it’s difficult to decouple logic as one can’t quickly jump between dependencies.&lt;/li&gt;
&lt;li&gt;As opposed to no-code platforms, a low-code IDE usually provides a very rudimentary code editor to include snippets of custom code where it’s needed. The editor’s functionality is limited so traditionally developers use another IDE to write code and copy it from there. It increases effort and leads to nasty bugs caused by minor discrepancies between contents of the editors.&lt;/li&gt;
&lt;li&gt;Lack of CI/CD integration in such tools is a common issue, as low-code platforms are by and large designed to be self-reliant having no perspective to participate in broader infrastructure.
&lt;/li&gt;
&lt;li&gt;It’s possible to continue the list since there’re a lot of rough edges when it comes to low-code development tooling. I was occasionally upset not finding any automated testing features or hot reload of a running project. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I watched an interview with Anders Hejlsberg, a creator of Delphi, a visual development tool that was incredibly popular along with Visual Basic at the time when I was a student. He said that “when it comes to visual programming, a line of code is worth a thousand pictures because you just die a slow death in wires going from everywhere to everywhere”. &lt;a href="https://youtu.be/nCVNpwXijVQ" rel="noopener noreferrer"&gt;https://youtu.be/nCVNpwXijVQ&lt;/a&gt; (21:20)&lt;br&gt;&lt;br&gt;
His main point was that visual programming doesn’t scale. I can’t agree more as what I’ve seen in long-living enterprise low-code projects was utter “blocks’n’wires” chaos. The use of off-the-shelf components is designed to greatly template development. But when we need a lot of different blocks with small adjustments, and we can't change their internals, we create new custom blocks, therefore generating more duplicated code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Everything has its time and place
&lt;/h2&gt;

&lt;p&gt;I love no-code and low-code platforms as they enable lots of creative people to put new ideas into practice. They start new ventures and automate everyday routine by manipulating data in a smart way. &lt;/p&gt;

&lt;p&gt;The visual developments tools emerged a long time ago and will remain with us for a long time to come. New and more elegant products with better UX will appear. As many companies have tried to adapt low-code to their business, I consulted them along this way. After avoiding pitfalls on a few projects, I’ve gained enough experience and insight into the process.&lt;/p&gt;

&lt;p&gt;To summarize, a low-code platform isn’t a good fit for a company where software development is a teamwork and when it has to scale. As of today, none of the tools on the market is suitable for building a full-blown service layer. Most prominent challenges include lack of professional tooling, scalability and infrastructure limitations. There’re great examples of handy low-code tools for enterprises but their main feature is that they effectively address one particular challenge (e.g., monitoring scenarios) not being platforms for building any kind of software.&lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>architecture</category>
      <category>programming</category>
      <category>tooling</category>
    </item>
    <item>
      <title>It's Easy To Overengineer But Underwork</title>
      <dc:creator>Anton Goncharov</dc:creator>
      <pubDate>Sun, 02 May 2021 10:00:52 +0000</pubDate>
      <link>https://dev.to/antongoncharov/it-s-easy-to-overengineer-but-underwork-27ha</link>
      <guid>https://dev.to/antongoncharov/it-s-easy-to-overengineer-but-underwork-27ha</guid>
      <description>&lt;p&gt;Many developers have already learned how to write concise code, to build scalable software architecture; they turned infrastructure into a smart conveyor. They accustomed themselves to a high-tech toolset, which is suitable for dealing with foreseeable issues. A problem, that was a creative task just yesterday, today becomes a template. Engineering approach as it is. Script it, observe and enjoy.&lt;/p&gt;

&lt;p&gt;In the area of IT there're own fads and trends. Today we see microservices, microcontainers, blockchains, tomorrow's agenda will get us something new. A certain part of IT industry tries hard to ensure that we're in a stream of constant changes. They're capitalizing on our yearning for novelty. While I'm writing this text, it's likely that a yet another &lt;em&gt;whatever.js&lt;/em&gt; framework is published somewhere.&lt;/p&gt;

&lt;p&gt;An enlightened developer should be above this tech chaos. Experience in a technology measured in years has ceased to mean much since a long time ago. Knack can be developed fast and could be obtained from various sources. In the long run other skills make difference.&lt;/p&gt;

&lt;p&gt;Software development is harder than just figuring what API should be called today, and more complex than keeping in mind a checklist of actual practices and techniques. A viable software product can't be considered apart from the business it's serving to. Today software teams should give more consideration to product evolution. It's very easy to overengineer but underwork.&lt;/p&gt;

&lt;p&gt;After all, we create not just a piece of software, but a technological process around it. What's really difficult is to build a system of methods, communications and conditions allowing a product to stand firm within a frame of expectations. Yet we can't expect a marvellous tech that will do it for us.&lt;/p&gt;

</description>
      <category>career</category>
      <category>industry</category>
      <category>watercooler</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
