<?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: MIKAMAI</title>
    <description>The latest articles on DEV Community by MIKAMAI (@mikamai).</description>
    <link>https://dev.to/mikamai</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%2Forganization%2Fprofile_image%2F321%2F8140eec3-80a6-4521-923b-ea424efb3c9e.jpg</url>
      <title>DEV Community: MIKAMAI</title>
      <link>https://dev.to/mikamai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikamai"/>
    <language>en</language>
    <item>
      <title>A Serverless Architecture to handle image generation from bulk data</title>
      <dc:creator>valeriadibattista</dc:creator>
      <pubDate>Mon, 11 Jul 2022 07:30:44 +0000</pubDate>
      <link>https://dev.to/mikamai/a-serverless-architecture-to-handle-image-generation-from-bulk-data-ooc</link>
      <guid>https://dev.to/mikamai/a-serverless-architecture-to-handle-image-generation-from-bulk-data-ooc</guid>
      <description>&lt;h5&gt;
  
  
  A real case study on how AWS serverless ecosystem can give your product a lot of value with minimum effort
&lt;/h5&gt;

&lt;p&gt;Publications about serverless adoption often miss a practical approach that can make it affordable in real-life use case scenarios. In Neosperience Cloud Services (formerly Mikamai)  we challenge this pure theoretical adoption of serverless technologies, testing our skills in large scale projects that can leverage the full potential of serverless. One of the most interesting use cases is our BeatIdentity client. &lt;/p&gt;

&lt;p&gt;Their platform contains thousands of instrumental music tracks, offered on an ecommerce platform in different takes. A user can select them one by one, or as part of a playlist. &lt;br&gt;
The platform has to create a cover for each track and make clear when it belongs to a single or a playlist. Sometimes, due to marketing reasons, the client may need a cover image with the BeatIdentity logo as a watermark.&lt;br&gt;
Since doing  this task manually is extremely time consuming and stressful for content creators, we supported the company in building the BeatId Generator.&lt;/p&gt;

&lt;p&gt;Thanks to the work of the Neosperience design team, along with the customer, we created a tool, using &lt;a href="https://processing.org/" rel="noopener noreferrer"&gt;Processing&lt;/a&gt;, to procedurally generate the cover image from track details such as title, artist, instruments, whether it is part of a playlist or needs the logo.&lt;/p&gt;

&lt;p&gt;A sample of the resulting images  is as follows, either with a standalone song (the pink images) or a playlist (the purple images): &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%2Fjcr31pehvu71mmozqwqq.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%2Fjcr31pehvu71mmozqwqq.png" alt="Covers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This core logic needs to be packaged within a service capable of storing the images in a way they could be easily retrieved in the future by third party applications (e.g. the ecommerce platform) or by BeatIdentity employees. Infrequent and unpredictable access patterns as well as maintenance considerations suggest this could be built as a cloud native application, leveraging all the benefits coming from serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;The application should support the following use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A general user can get an already generated cover in high resolution or in a custom defined size;&lt;/li&gt;
&lt;li&gt;A third party application can upload a single track, letting the system generate the high resolution versions of the cover;&lt;/li&gt;
&lt;li&gt;A BeatIdentity Admin can import a single track or massively import multiple tracks uploading a CSV file. At the end of the CSV import process the user can download a zip archive containing all the generated files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html" rel="noopener noreferrer"&gt;AWS Cloud Development Kit (CDK)&lt;/a&gt; lets define the AWS cloud infrastructure in a general-purpose programming language. Among the several available ones, we chose Typescript to take advantage of the benefits this programming language serves. Instead of writing the resulting Cloud Formation Stacks using the native JSON or YAML format, Typescript makes infrastructure design, deployment and the overall coding experience more enjoyable, even allowing good practices such as code reviews, unit tests, and source control to make the infrastructure more robust.&lt;br&gt;
The overall architecture, implementing the beforehand use cases leverages the following AWS services: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda: it’s the core of our serverless application, since it allows us to run the code without caring about provisioning or managing servers (and only pay per use!);&lt;/li&gt;
&lt;li&gt;Amazon API Gateway: it sits in front of our lambdas exposing them as REST APIs and taking care of authentication;&lt;/li&gt;
&lt;li&gt;Amazon Cognito: this takes care of authenticating our users;&lt;/li&gt;
&lt;li&gt;Amazon S3: as a storage service, it helps us to manage data in every format we will need, storing them as objects in Buckets;&lt;/li&gt;
&lt;li&gt;AWS SQS: it’s a queue service and we use it as a decoupling mechanism, to avoid losing messages;&lt;/li&gt;
&lt;li&gt;Amazon DynamoDB: the fully managed NoSQL service offered by AWS. We use it to persist generation info and let users and third parties know the status of each of their imports;&lt;/li&gt;
&lt;li&gt;Amazon CloudFront: simply put, it’s a CDN fully integrated with the AWS ecosystem. We use it for caching and for generating resized covers on the fly;&lt;/li&gt;
&lt;li&gt;AWS Code Pipeline and AWS Code Build: to take advantage of the CI/CD approach in order to automatically build and deploy our code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to store on Amazon S3 different sets of data, thus we defined four buckets starting from the access patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSV Bucket: used for uploading the CSVs (via presigned URLs);&lt;/li&gt;
&lt;li&gt;Track Bucket: used for storing the track metadata. This bucket has no public access and is used only by the lambdas to write and read them;&lt;/li&gt;
&lt;li&gt;Image Bucket: this bucket is served by Cloudfront and contains the generated cover and the zip archives;&lt;/li&gt;
&lt;li&gt;Frontend Bucket: for storing the frontend web application, written in React. The bucket assets are then served by Cloudfront. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using multiple buckets (instead of just one bucket for everything) makes our life easier for handling permissions and reduces the chance of human error.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cover Generation Lambda
&lt;/h2&gt;

&lt;p&gt;The Lambda which translates the Processing algorithm must reproduce all the expected behaviors, such as receiving track details, generating some variables and colors, drawing shapes and applying stickers, if needed.&lt;br&gt;
All the Processing APIs used by the algorithm were available as part of the Canvas API. So we decided to convert the Processing code in Typescript and use the node-canvas package to reproduce the same behavior. This package needs some native libraries which can be easily provisioned on the Lambda function via an &lt;a href="https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:990551184979:applications~lambda-layer-canvas-nodejs" rel="noopener noreferrer"&gt;existing AWS Lambda Layer&lt;/a&gt;.&lt;br&gt;
Once we were able to replicate the algorithm result, making it work as a Lambda function was the easiest part: we just needed to slightly change our function definition to adhere to the lambda event specification.&lt;br&gt;
The function would need to access several static assets which would make the deploy artifact bigger. We could have used S3 for them, but this would result in a lot of unnecessary API requests, so we moved these assets in a Lambda Layer too.&lt;br&gt;
Having the cover generation lambda complete, the rest of the product was already appearing as an easy task. We divided the rest of this serverless architecture into three main parts, described in the following paragraphs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Track Creation
&lt;/h2&gt;

&lt;p&gt;The simplest flow is the Single Track Image Creation. The flow is thought to be used by a third party user and the BeatIdentity admin.&lt;br&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%2Fh1r0qvfu3i2heh2gklvg.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%2Fh1r0qvfu3i2heh2gklvg.png" alt="Single track creation flow"&gt;&lt;/a&gt;&lt;br&gt;
There are two APIs that need to be called by third party services. They are implemented as Lambda Functions and exposed via API Gateway and authenticated against an API Key.&lt;br&gt;
Calling the “Create Single Track” API will insert the corresponding record in DynamoDB, save the JSON details in the JSON Bucket and start the Step Function workflow, which is async. This way the HTTP request is not blocked by the cover generation, and the user can know if the generation is complete by calling the Status API, which fetches the status from the corresponding record on DynamoDB. The state machine provided by the AWS Step function allows us to perform all the tasks needed to call the “Cover Generation” Lambda, keep the corresponding record on DynamoDB updated, and handle errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSV Upload
&lt;/h2&gt;

&lt;p&gt;The aim of the second flow is to allow BeatIdentity admins to massively import hundreds of tracks at the same time uploading a CSV in which each row represents a track.&lt;br&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%2Fhzn14m10t7722d6xocl6.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%2Fhzn14m10t7722d6xocl6.png" alt="CSV Upload flow"&gt;&lt;/a&gt;&lt;br&gt;
At the very start of the flow, the frontend application calls the “Presigned URL” API to obtain a presigned URL which allows uploading the CSV on the S3. This technique guarantees a secure way of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeping the CSV bucket private;&lt;/li&gt;
&lt;li&gt;Offloading the file from our service to S3, reducing the overhead of receiving the file on the backend and then uploading it from the backend onto S3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More info on this topic can be found &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
When the upload on S3 is complete, a message is propagated to a SQS Queue, and consumed by a Lambda Function (Start State Machine) which is responsible for starting the Step Function responsible of processing the CSV (a Step Function cannot be started directly from an SQS queue). If any error occurs, a message will be requeued and, if the error persists, after some time it will be archived in a DLQ queue for further analysis.&lt;br&gt;
The Step Function of this flow is slightly different with respect to the previous one, since it needs to create images from each CSV row as fast as possible. Thus, the iterator operator was implemented to perform the actions in parallel and to process rows in groups of 5 elements for each iteration. At the end of the generation a zip archive is created containing all the generated Covers and stored in the Image Bucket to be later downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cover Request
&lt;/h2&gt;

&lt;p&gt;Until this point each generated image can be fetched in its high resolution size. But someone may also need scaled down versions. To allow this we implemented a common pattern through Lambda@Edge.&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%2Fqy0z52hjr95htymt6v8n.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%2Fqy0z52hjr95htymt6v8n.png" alt="Cover Request flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a cover image is requested to Cloudfront (its path starts with “/covers”), the request is sent to S3 to retrieve an object from there. The S3 response is then handled by a Lambda@Edge which is a special Lambda acting as a middleware.&lt;br&gt;
If the S3 response is a “Not Found Object” and the requested path is referring to a cover image, the Lambda@Edge will fetch the high resolution image from S3, size it down to the desired dimension, store it on S3 and return the image content. This way on the next request for the same object, S3 would return the resized version and the Lambda would just ignore the message.&lt;br&gt;
This pattern is explained in detail &lt;a href="https://aws.amazon.com/blogs/networking-and-content-delivery/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we got at the end of the day
&lt;/h2&gt;

&lt;p&gt;We could have delivered this product in a plain, classic way: a simple server configured with Java and Processing and a couple of PHP web pages. The user would have used the web pages to let PHP handle the Processing sketch and generated the images, maybe storing them on the EC2 EBS itself. This would have reduced (slightly) the development time, but at what cost?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaling is not obvious and needs some additional work;&lt;/li&gt;
&lt;li&gt;Security is not by-default. An EC2 server needs additional work on this point too;&lt;/li&gt;
&lt;li&gt;The instance needs periodic updates;&lt;/li&gt;
&lt;li&gt;The infrastructure has fixed costs, even if we don’t use the platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead we decided to aim for a fully serverless architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The cover generation lambda and the resize lambda@edge function complete their work in about 2 seconds, which means that generating covers for 1 MILLION tracks will cost 34$ which is slightly less than paying a t3a.large EC2 instance;&lt;/li&gt;
&lt;li&gt;We don’t have to take care of infrastructure security at the same level of classic infrastructures, we just need to ensure the correct permissions are set and that our code is not faulty;&lt;/li&gt;
&lt;li&gt;We have built-in decoupling between the different components, which means changing a peace of our design is pretty easy;&lt;/li&gt;
&lt;li&gt;Thanks to CDK we have a single repository, put in CI/CD, which contains both our infrastructure and application logic, in a homogeneous language, making it easy to understand how data is flowing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, the final result exceeded the client expectations, and the effort required to both translate the original generation algorithm to a different language and to develop the product with a serverless approach required the same time we would have needed to provision and properly configure a classic infrastructure.&lt;/p&gt;

&lt;p&gt;Looking at the repository, it’s easy to see which components do what in our architecture, because the stack code appears as an imperative function of code composing pieces together and adding behaviors. For example, we create a csvBucket, then we create a “CSVGenerationFSM” (which is a construct for our step function) then we do “fsm.bindToS3Bucket(csvBucket)” to imply that our step function will start when an event is triggered on the csv bucket.&lt;/p&gt;

&lt;p&gt;So, our advice is, don’t be afraid of the serverless world, and don’t play safe! Just start playing with it and look at some other architectural examples (like the one we talked about in this post) to get inspiration for improving your design more and more.&lt;/p&gt;

&lt;p&gt;Some advice for the beginners:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The AWS world aims for security over all. If you have a bucket and a lambda, you have to explicitly give permission to the lambda to write or read on that bucket, and you can also scope this permission to specific objects or prefixes. This applies to any AWS service and to any action you make on them. So, even if it may seem complicated when you start, once you’ll get used to it, you’ll discover your products have never been so robust and secure!&lt;/li&gt;
&lt;li&gt;It’s not you that are not good at googling for documentation! This is indeed one the few things on which AWS could improve. And they are doing it, because if you look at the CDK documentation, it’s awesome!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Co-Authored with: &lt;a href="https://github.com/AntonioR199" rel="noopener noreferrer"&gt;Antonio Riccio&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Why we went from Slack to Discord</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Thu, 09 Apr 2020 15:56:01 +0000</pubDate>
      <link>https://dev.to/mikamai/why-we-went-from-slack-to-discord-200</link>
      <guid>https://dev.to/mikamai/why-we-went-from-slack-to-discord-200</guid>
      <description>&lt;p&gt;The beginning of 2020 was one of the most difficult moments of the last decade. The rapid spread of SARS-COVID-2 and the consequent quarantine imposed by the various countries of the world has led many companies to discover and approach remote work for the first time, in order to protect their employees while still being able to work without attending the office. However, choosing the right tools to support remote collaboration is almost as difficult a challenge as adopting "smart" working methodologies that allow you to keep productivity high. The panorama of available choices is vast, from open-source tools such as Jitsi and Nextcloud to commercial services such as Slack and Google GSuite, each with its own strengths and peculiarities.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://mikamai.com"&gt;Mikamai&lt;/a&gt; we have always been used to working in a "smart" way, preferring asynchronous and written collaboration wherever possible to make our business more streamlined and agile. This allows us to expand our operational area to the entire world, both in terms of customers and collaborators. In fact, many colleagues do not work from our main office in Milan, Italy, but from more comfortable places for them, such as other Italian or European cities, even other continents. We have long been GSuite users for shared documents, GitHub for hosting our projects, Trello for managing activities and Slack for internal communication.&lt;/p&gt;

&lt;p&gt;However, we recently started to feel the limitations of Slack’s free plan. Mikamai has grown, the number of people and messages written every day has grown significantly with it, and we have found ourselves to frequently exceed the limit of 10,000 messages, thus losing potentially important conversations and messages. The lack of group video calls forces us to use Google Meet, an excellent video conferencing solution but which lacks the immediacy of starting a call directly from the text chat. However, paid plans, the price of which increases for each employee present in the workspace, are not very appealing to us. So we started scouting for a tool that would better meet our needs.&lt;/p&gt;

&lt;p&gt;In the past few months we have tried several online communication tools, in particular &lt;a href="https://mattermost.com"&gt;Mattermost&lt;/a&gt;, an open source alternative to Slack, &lt;a href="https://www.jetbrains.com/space/"&gt;JetBrains Space&lt;/a&gt;, a collaboration and management service that includes a chat very similar to Slack, and &lt;a href="https://discordapp.com/"&gt;Discord&lt;/a&gt;, a communication platform designed for gamers and online communities, but with very interesting features also for companies that work in a distributed way.&lt;/p&gt;

&lt;p&gt;The latter has caught our attention, and here are the reasons that led us to adopt it as our corporate communication tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice chat is only one click away
&lt;/h2&gt;

&lt;p&gt;Despite working mainly in an asynchronous way through email, Trello cards and comments on the code repositories, direct conversation is a very important tool especially for creative activities that benefit from a rapid and continuous exchange of ideas between the participants. The ability of immediately entering a group voice chat, with excellent audio quality and with the support of text chat and screen sharing is perhaps Discord's main strength, and what really convinced us in attempting the transition.&lt;/p&gt;

&lt;p&gt;Brainstorming and planning sessions can be started quickly without the overhead that changing tools entails when using services outside the chat, as was our case with Google Meet. Everything is much more natural and immediate, promoting communication and the exchange of ideas rather than discouraging them.&lt;/p&gt;

&lt;p&gt;It is also very convenient for organizing virtual coffee breaks, allowing you to maintain human contact with colleagues that you risk losing by working remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Granular control over roles and permissions
&lt;/h2&gt;

&lt;p&gt;Discord was created to host online communities, mainly in the gaming world but extending over time to all those groups of users who need a safe digital space in which to meet and chat. For this reason, the platform provides a wide range of permissions, which can be grouped into roles to be assigned to users, allowing you to granularly control which actions are granted to which users, and in which channels.&lt;br&gt;
In our particular case we do not manage a public space but a private server, however it is not used solely for business purposes. We have dedicated some channels to external activities, like video games or role-playing games, which involve the presence of users who are not part of the company staff, such as family members and playmates, former colleagues and partners of other companies. Thanks to Discord's powerful permission system, these users have access only to the channels for which they were authorized, while the company's internal chats are hidden and inaccessible.&lt;/p&gt;

&lt;p&gt;This also allows us to invite our customers to join the server to facilitate the exchange of information with them. For each project, a text channel and a corresponding voice room are created, along with a role that allows access to them. When the customer enters the server and is assigned the role, he can then access these channels and actively collaborate with us, without being able to see reserved areas and spaces dedicated to other active projects.&lt;/p&gt;

&lt;p&gt;We have also created a dedicated announcement channel, in which only Mikamai's administrative staff can write, to support the internal mailing list in quickly sharing official news and communications with colleagues.&lt;/p&gt;
&lt;h2&gt;
  
  
  External integrations
&lt;/h2&gt;

&lt;p&gt;Slack boasts a multitude of integrations with third-party systems, from ticketing and project management platforms to infrastructure alarms and monitoring systems. Discord does not have the same spread in the business and development world, but provides the possibility to configure the integrations in a Slack compatible mode, basically allowing to integrate any system that can interact with Slack.&lt;br&gt;
Discord also has a robust and diverse chatbot ecosystem, small applications that act like automatic users and increase native chat features. For example, a very successful bot in Mikamai’s server is &lt;a href="https://groovy.bot/"&gt;Groovy&lt;/a&gt;, a bot that allows you to play music to all users connected to a voice channel as a kind of virtual jukebox. Thanks to it, we can share our music with colleagues, allowing everyone to add songs to the playlist being played.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Obviously one aspect that we have not underestimated during our evaluation is the monetary cost compared to the competition. All of Discord’s core features are completely free, providing paid additions mainly aimed at the gaming world, especially streamers and youtubers, such as the ability to add custom emojis, customize the profile and improve audio and video quality. This, added to the points previously discussed, was one of the key points for Mikamai in making the decision to migrate to Discord.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testimonials
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Given that I’m not a very techy person, which often limits me in discovering the full potential of this type of tool, I must say that I find Discord very versatile. I really appreciate the possibility of enabling audio channels that allow an immediate switch between text communication and voice communication (especially group chats). Having an unlimited number of messages always available free of charge is, of course, another nice advantage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Debora, Office Manager&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Discord adds syntax highlighting for code snippets, unlimited message history, integrated calls, screenshare with up to 50 people (during the COVID-19 period), a really advanced role and permission system, and is very easy to integrate with external tools. I don't know what more you could ask for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Nicola Racco, Tech Lead&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__95140"&gt;
    &lt;a href="/nicolaracco" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XlMqOv_I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F95140%252F9a025a6f-d4ff-4d3e-8f31-dc6a878589cb.jpeg" alt="nicolaracco image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/nicolaracco"&gt;Nicola Racco&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/nicolaracco"&gt;&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;I have been using Discord for more than a year mainly for gaming but also to talk or see my friends. I immediately found it intuitive and with a youthful graphic feeling.&lt;br&gt;
Its strength is absolutely being free, I still remember when I had to communicate with other players simultaneously, we used TeamSpeak and it required us to spend a lot of money every month for a dedicated server, with an increasing cost based on the amount of users who could connect at once, a real nightmare.&lt;br&gt;
With Slack, I suffered (and still suffer) because of the limited chat history, 10,000 messages or a month of history and then that’s it. How many lost links, how many chats that have fallen by the wayside ("I wrote it to you on Slack", "When ???") ...&lt;br&gt;
Discord is, in my opinion, the tool par excellence of remote communication both for gaming, chatting and companies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Daniela, Frontend Developer&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__267544"&gt;
    &lt;a href="/moguriangel" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LCzr8lBS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://media.dev.to/cdn-cgi/image/width%3D150%2Cheight%3D150%2Cfit%3Dcover%2Cgravity%3Dauto%2Cformat%3Dauto/https%253A%252F%252Fdev-to-uploads.s3.amazonaws.com%252Fuploads%252Fuser%252Fprofile_image%252F267544%252F8bfbc909-3655-4cae-bf9f-8ee3470ce310.png" alt="moguriangel image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/moguriangel"&gt;Daniela&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/moguriangel"&gt;&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Discord has proved to be an excellent corporate communication platform despite being mainly geared towards the world of gaming and digital communities. The speed with which it is possible to start talking with colleagues and organize virtual meetings has allowed us to facilitate the transition even for those who were not previously used to working completely remotely, and has given us back a part of the warmth that sharing the day with our coworkers transmit, reducing the alienation due to the emergency situation in which we find ourselves. We will have the opportunity to test it thoroughly in the coming months, but we are sure that it will prove itself to be a valid and central tool for our daily work.&lt;/p&gt;

</description>
      <category>remote</category>
      <category>community</category>
      <category>communication</category>
    </item>
    <item>
      <title>DEV Milan has started, and it was awesome!</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Tue, 24 Sep 2019 13:12:34 +0000</pubDate>
      <link>https://dev.to/mikamai/dev-milan-has-started-and-it-was-awesome-2odf</link>
      <guid>https://dev.to/mikamai/dev-milan-has-started-and-it-was-awesome-2odf</guid>
      <description>&lt;p&gt;On Monday 23rd September we kicked off the first event of the DEV Community Milanese chapter, and it was a blast! 🇮🇹&lt;/p&gt;

&lt;p&gt;We as &lt;a href="https://mikamai.com" rel="noopener noreferrer"&gt;Mikamai&lt;/a&gt; have fostered and helped to gather many tech communities in Milan over the course of the years, and it with great pleasure that we organized this one ourselves to thank all these awesome people and their daily effort in bringing Italian developers together.&lt;/p&gt;

&lt;p&gt;We hosted two talks (actually one big talk divided into two sections) exploring the magical world of &lt;a href="https://graphql.org" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; APIs first on the backend side, and then on the frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mighty Backend
&lt;/h2&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Falqzafa1x8npxzwf4sff.jpeg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Falqzafa1x8npxzwf4sff.jpeg" alt="Matteo Joliveau presenting the first half of the talk"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started the evening with the backend talk, introducing new people to what GraphQL is and isn't and quickly explaining the inner working of the language, then moved on to more practical advices and strategies for implementing clean and effective GraphQL APIs.&lt;/p&gt;

&lt;p&gt;We touched topics like &lt;a href="https://graphql.org/learn/schema/" rel="noopener noreferrer"&gt;types&lt;/a&gt; and &lt;a href="https://graphql.org/learn/schema/#scalar-types" rel="noopener noreferrer"&gt;scalars&lt;/a&gt;, datasources, &lt;a href="https://www.graphql-java.com/documentation/v12/batching/" rel="noopener noreferrer"&gt;batch loading&lt;/a&gt; and evolving schemas, and tried to give actionable suggestions on how to cleanly and efficiently tackle all these issues. &lt;/p&gt;

&lt;p&gt;Participants were very active and asked clever questions that made the whole experience much more inclusive and enjoyable!&lt;/p&gt;

&lt;h2&gt;
  
  
  When in Italy, just pizza 🍕
&lt;/h2&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbcx2k1nc8mpdqaex82wx.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbcx2k1nc8mpdqaex82wx.jpg" alt="Participants networking over a hot slice of pizza"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the first talk, it's time for a break! We offered pizzas, chips and beverage to all attendees and had a fun time networking, discussing and generally have a good time. It was really fun and I'm very proud of how the evening turned out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Glorious Frontend
&lt;/h2&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F29tg8i76i0cd040vqjvy.jpeg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F29tg8i76i0cd040vqjvy.jpeg" alt="Mattia Panzeri explaining how GraphQL can help frontend developers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then it was time for the second half of the event. My colleague Mattia Panzeri, one of our finest frontend engineers, talked about the challenges of modern frontend development, from multiple devices and screen resolutions to finicky mobile networks and voice assistants, and how GraphQL help clients tailor API requests exactly to their needs. He provided examples of similar and related technologies like &lt;a href="https://netflix.github.io/falcor/" rel="noopener noreferrer"&gt;Netflix Falcor&lt;/a&gt; and why they failed to achieve what GraphQL does.&lt;/p&gt;

&lt;p&gt;All of this explained with his witty and funny style that made the whole speech very lighthearted and enjoyable.&lt;/p&gt;

&lt;p&gt;We close the evening with a live demonstration using GitLab's &lt;a href="http://gitlab.com/-/graphql-explorer" rel="noopener noreferrer"&gt;GraphQL Explorer&lt;/a&gt; to showcase how queries work in the wild, and of course, this being a live demo it went horribly wrong with authentication problems and the window manager of my laptop ultimately deciding that it didn't like our projector so much, but all in all we had good fun.&lt;/p&gt;

&lt;p&gt;We gave out stickers to everyone and announced a followup of this event, that we absolutely want to make again and possibly on a regular basis. We are thinking one per month or every two months, depending on speakers' availability. &lt;/p&gt;

&lt;p&gt;I really want to thank the DEV Team for launching &lt;a href="https://irl.dev" rel="noopener noreferrer"&gt;IRL&lt;/a&gt; and supporting this kind of initiatives. There is still work to be done on the logistic side of things, but in the end, the event was a success and everyone enjoyed it.&lt;/p&gt;

&lt;p&gt;Thank you for reading and I hope to see you next time!&lt;/p&gt;

&lt;p&gt;You can find the slides &lt;a href="https://docs.google.com/presentation/d/1kl1jhjQJIHDIvTJfUL_GcPrBN7wGdqxiJiqegKZb9q0/edit?usp=sharing" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1176193547768389633-453" src="https://platform.twitter.com/embed/Tweet.html?id=1176193547768389633"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1176193547768389633-453');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1176193547768389633&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>irl</category>
      <category>news</category>
      <category>webdev</category>
      <category>meetup</category>
    </item>
    <item>
      <title>Effective Service Objects in Ruby</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Mon, 04 Jun 2018 19:47:48 +0000</pubDate>
      <link>https://dev.to/mikamai/effective-service-objects-in-ruby-2ga0</link>
      <guid>https://dev.to/mikamai/effective-service-objects-in-ruby-2ga0</guid>
      <description>&lt;p&gt;As a Java developer that recently transitioned to a Ruby on Rails company, I felt kinda lost when I discovered that the use of models directly inside of controllers was a common practice.&lt;/p&gt;

&lt;p&gt;I have always followed the good practices of &lt;strong&gt;Domain Driven Design&lt;/strong&gt; and encapsulated my business logic inside special classes called &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Service_layer_pattern" rel="noopener noreferrer"&gt;service objects&lt;/a&gt;&lt;/strong&gt;, so in Java (with &lt;a href="https://spring.io/guides/gs/serving-web-content/" rel="noopener noreferrer"&gt;Spring&lt;/a&gt;) a controller would look like this:&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="nd"&gt;@Controller&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;)&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;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllUsers&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsers&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verbosity aside, this is nice and clean with good separation of concerns. The actual business logic that retrieves the user list is delegated to the &lt;code&gt;UserService&lt;/code&gt; implementation and can be swapped out at any time.&lt;/p&gt;

&lt;p&gt;However, in Rails we would write this controller as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Api::UserController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
        &lt;span class="vi"&gt;@users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, this is indeed shorter and even cleaner than the Java example, but it has a major flaw. &lt;code&gt;User&lt;/code&gt; is an ActiveRecord model, and by doing this we are tightly coupling our controller to our persistence layer, breaking one of the key aspects of DDD. Moreover, if we wanted to add authorization checks to our requests, maybe only returning a subgroup of users based on the current user's role, we would have to refactor our controller and putting it in charge of something that is not part of the presentation logic. By using a service object, we can add more logic to it while being transparent to the rest of the world.&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's build a service object
&lt;/h1&gt;

&lt;p&gt;In Java this is simple. It's a singleton class that is injected into other classes by our IoC container (Spring DI in our example).&lt;br&gt;
In Ruby, and Rails especially, this is not quite the same, since we can't really inject anything in our controller constructor. What we can do, however, is taking inspiration by another programming language: &lt;a href="http://elixir-lang.org" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt;.&lt;br&gt;
In Elixir, a functional language, there are no classes nor objects, only functions and structs. Functions are grouped into modules and have no side effects, a great feature to ensure immutability and stability in our code.&lt;br&gt;
Since Ruby too has modules, we can use them to implement our service object as stateless collections of methods.&lt;/p&gt;

&lt;p&gt;Our UserService can look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;UserService&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_users&lt;/span&gt;
            &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then will be used like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Api::UserController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
        &lt;span class="vi"&gt;@users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_users&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn't sound like a smart move, does it? We just moved the &lt;code&gt;User.all&lt;/code&gt; call in another class. And that's true, but now, as our application grow we can add more logic to it without breaking other code or refactoring, as long as we keep our API stable.&lt;br&gt;
One small change I'll make before proceding. Since we may want to inject some data into our service on every call, we'll define our methods with a first parameter named &lt;code&gt;ctx&lt;/code&gt;, which will contain the current execution context. Stuff like the current user and such will be contained there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;UserService&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_users&lt;/span&gt; &lt;span class="n"&gt;_ctx&lt;/span&gt; &lt;span class="c1"&gt;# we'll ignore it for now&lt;/span&gt;
            &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Api::UserController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
        &lt;span class="vi"&gt;@users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_users&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@users&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Applying business logic
&lt;/h1&gt;

&lt;p&gt;Now let's build a more complex case, and let's use a user story to describe it first. Let's imagine we're building a ToDo app (Wow, how revolutionary!).&lt;br&gt;
The story would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a normal user I want to be able to see all my todos for the next month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The RESTful HTTP call will be something like: &lt;br&gt;
&lt;code&gt;GET /api/todos?from=${today}&amp;amp;to=${today + 1 month}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our controller will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Api::TodoController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
        &lt;span class="vi"&gt;@ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="vi"&gt;@todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TodoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_todos_by_interval&lt;/span&gt; &lt;span class="vi"&gt;@ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permitted_params&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@todos&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;permitted_params&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:todo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;TodoService&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_todos_by_interval&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
            &lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:current_user&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;by_interval&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we are still delegating the heavy database lifting to the model (throught the scope &lt;code&gt;by_interval&lt;/code&gt;) but the service is actually in control of filtering only for the current user. Our controller stays skinny, our model is used only for persistence access, and our business logic doesn't leak in every corner of our source code. Yay!&lt;/p&gt;

&lt;h1&gt;
  
  
  Service Composition
&lt;/h1&gt;

&lt;p&gt;Another very useful OOP pattern we can use to enhance our business layer is the &lt;a href="https://en.wikipedia.org/wiki/Composite_pattern" rel="noopener noreferrer"&gt;composite pattern&lt;/a&gt;. With it, we can segregate common logic into dedicated, opaque services and call them from other services. For example we might want to send a notification to the user when a todo is updated (for instance because it expired). We can put the notification logic into another service and call it from the previous one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;TodoService&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_todo&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
            &lt;span class="n"&gt;updated_todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:todo_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;updated_todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="c1"&gt;# raise exception if unable to update&lt;/span&gt;
            &lt;span class="n"&gt;notify_expiration&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:current_user&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;updated_todo&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expired?&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="kp"&gt;private&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_expiration&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="c1"&gt;# put in a private method for convenience&lt;/span&gt;
            &lt;span class="no"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify_of_expiration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Commands for repetitive tasks
&lt;/h1&gt;

&lt;p&gt;As the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;Gang of Four&lt;/a&gt; gave us a huge amount of great OOP patterns, I'm going to borrow one last concepts from them and greatly increase our code segregation. You see, our services could act as coordinators instead of executors, delegating the actual work to other classes and only caring about calling the right ones. Those smaller, "worker-style" classes can be implemented as commands. This has the biggest advantage of enhancing composition by using smaller execution units (single commands instead of complex services) and separating concerns even more. Now services act as action coordinators, orchestrating how logic is executed, while the actual execution is run inside simple, testable and reusable components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Side Note: I'm going to use the gem &lt;a href="https://github.com/nebulab/simple_command" rel="noopener noreferrer"&gt;simple_command&lt;/a&gt; to implement the command pattern, but you are free to use anything you want&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's refactor the update logic to use the command pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UpdateTodo&lt;/span&gt;
    &lt;span class="n"&gt;prepend&lt;/span&gt; &lt;span class="no"&gt;SimpleCommand&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt; &lt;span class="n"&gt;todo_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
        &lt;span class="vi"&gt;@todo_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todo_id&lt;/span&gt;
        &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
        &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="vi"&gt;@todo_id&lt;/span&gt;

        &lt;span class="c1"&gt;# gather errors instead of throwing exception&lt;/span&gt;
        &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_multiple_errors&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;
        &lt;span class="n"&gt;todo&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;TodoService&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_todo&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
            &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UpdateTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:todo_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
                &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&lt;/span&gt;
                &lt;span class="n"&gt;notify_expiration&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:current_user&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expired?&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;

            &lt;span class="c1"&gt;# let's return the command result so that the controller can&lt;/span&gt;
            &lt;span class="c1"&gt;# access the errors if any&lt;/span&gt;
            &lt;span class="n"&gt;cmd&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="kp"&gt;private&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_expiration&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="c1"&gt;# put in a private method for convenience&lt;/span&gt;
            &lt;span class="no"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify_of_expiration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expired?&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beautiful. Now every class has one job (Controllers receive requests and return responses, Commands execute small tasks and Services wire everything together), our business logic is easily testable without needing any supporting infrastructure (just mock everything. Mocks are nice.) and we have smaller and more reusable methods. We just have a slightly bigger codebase, but it's still nothing compared to a Java project and it's worth the effort on the long run.&lt;br&gt;
Also, our services are no longer coupled to any Rails (or other frameworks) specific class. If for instance we wanted to change the persistence library, or migrate one business domain to an external microservice, we just have to refactor the related commands without having to touch our services.&lt;/p&gt;

&lt;p&gt;Are you using service objects in your Ruby projects? How did you implement the pattern and what challenges did you solved that my approach does not?&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>service</category>
      <category>patterns</category>
    </item>
    <item>
      <title>Technical Debt: Definition and Practical Approach</title>
      <dc:creator>Nicola Racco</dc:creator>
      <pubDate>Thu, 15 Jun 2017 14:14:38 +0000</pubDate>
      <link>https://dev.to/mikamai/technical-debt-definition-and-practical-approach-1444</link>
      <guid>https://dev.to/mikamai/technical-debt-definition-and-practical-approach-1444</guid>
      <description>&lt;p&gt;I know this post doesn’t invent anything new and you may have read about technical debt other hundred of times. This post is just another take on the Technical Debt matter, with the description of the practical approach we follow in Mikamai.&lt;/p&gt;

&lt;p&gt;The process of software development is traditionally composed by three phases: development, testing, release. These phases can then be further detailed or splitted: the development phase may comprehend frequent deploys on an &lt;em&gt;alpha&lt;/em&gt; environment which will contain incomplete features but will allow to receive feedback easily; testing might then happen on different environments, sequentially (i.e. the first one is an isolated environment with an empty data set, the second one is an isolated environment with a realistic data set, the third one is accessible from the internet and can be used for stress testing, and so on)&lt;/p&gt;

&lt;p&gt;The one thing happening at the end of the traditional development life-cycle is the release, where the term “release” is much more like a “furniture shipment” than a digital good delivery. In this traditional lifecycle the product is indeed considered stable, without any issues, and we can rapidly forget it and move on to the next &lt;em&gt;product&lt;/em&gt;. There can be a period of controlled operativity where we’re admitting that the app may be affected by some bugs, that will be fixed. But anything weird happening after this period is considered &lt;em&gt;expected&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Problem is: a software feature is not a desk, or a seat.&lt;/p&gt;

&lt;p&gt;After the release, even after a reasonable amount of time, we could discover that the developers didn’t fully understand the specs, with the needing now of rewriting parts of code in a hurry, without considering too much themes like code readability.&lt;/p&gt;

&lt;p&gt;It may also happen that the delivered feature is good, it’s delivering the business value we had requested, be performant and without bugs. And even in this case, even with this excellent development, a change in the company strategy may require changes to the product some months or years from now.&lt;/p&gt;

&lt;p&gt;Even in the most lucky cases, just the passing of time increases day after day the chance that the code need to be changed again, to accommodate a technological upgrade for example.&lt;/p&gt;

&lt;p&gt;Whatever way it will happen, suddenly we’re handling this horrific code, written by developers that left the team years ago, written with an ancient technology, and even a small tiny little change, which normally would require just a day, is now requiring weeks.&lt;/p&gt;

&lt;p&gt;For example we may found ourselves to have written an e-commerce in a month two years ago, but to need now two months to change a single feature, arguing on whose fault is it and if it’s still reasonable to keep maintaining a so pricey tool.&lt;/p&gt;

&lt;p&gt;We’re exaggerating, but not that much.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is technical debt?
&lt;/h2&gt;

&lt;p&gt;The concept of &lt;em&gt;technical debt&lt;/em&gt; is a metaphor created by &lt;a href="https://it.wikipedia.org/wiki/Ward_Cunningham"&gt;Ward Cunningham&lt;/a&gt; to describe the complexity in software projects. His idea is that releasing a first-time code is like going into debt, which can be paid back with a refactoring. Every minute spent on this not-quite-right code increases the interest on the debt.&lt;/p&gt;

&lt;p&gt;Cunningham didn’t just find a good metaphor to describe complexity, but this same metaphor also works quite well to describe the worst case scenario, &lt;strong&gt;if development doesn’t follow the correct methodology, the interest on the debt may go up so much to paralyze the project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Obviously there are developers and Developers, consultants and Consultants. Experience helps a lot in writing &lt;em&gt;better&lt;/em&gt; code, in understanding the specifications and write the best implementation on the first try. But this is not enough: &lt;strong&gt;sometimes even the best code is anyway difficult to understand and change, thus increasing the technical debt.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually we tend to consider technical debt like something that can affect only the “old code”. But it’s not so obvious that a code written in the ‘70s will be more complicated of another one written in the ‘90s.&lt;/p&gt;

&lt;p&gt;Another definition of Technical Debt, more commonly accepted, is the one provided by &lt;a href="https://michaelfeathers.silvrback.com/"&gt;Michael Feathers&lt;/a&gt; in &lt;a href="https://www.amazon.it/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052"&gt;Working Effectively with Legacy Code&lt;/a&gt;: &lt;strong&gt;it’s code without test coverage&lt;/strong&gt;. It’s a good definition, which can helps us to avoid the mistake of associating the term technical debt with the term &lt;em&gt;old code&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The reason why writing tests is such a good precaution against technical debt is that &lt;strong&gt;tests provide an implicit documentation on the application functioning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So instead than talking of just “untested code”, we’re talking of:&lt;br&gt;&lt;br&gt;
– Code not easily readable;&lt;br&gt;&lt;br&gt;
– Code that doesn’t contain explanations of the logic;&lt;br&gt;&lt;br&gt;
– Not having explanations of the ideas and the decision process that lead to writing the code.&lt;/p&gt;

&lt;p&gt;Which offers a completely different point of view on this matter. Because at this point &lt;strong&gt;technical debt is not only a technical problem, but it’s also a communication problem&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How is technical debt generated?
&lt;/h2&gt;

&lt;p&gt;Let’s use the e-commerce example described at the beginning.&lt;/p&gt;

&lt;p&gt;After the first 100 lines of code this technical debt could be paid back showing the code to a colleague. This simple operation would mean sharing the knowledge, having a feedback on the logic correctness, and a confirmation that the code is readable by others.&lt;/p&gt;

&lt;p&gt;After a month, when the e-commerce was released, we had the minimum required to have a functioning platform. In this moment the technical debt could be paid back showing the buying process to our colleagues, checking again the code so we can be sure there are no dark spots too complex to read, and writing some automatic tests that can grant the purchase process is functioning. This technical debt is much higher than before, but still acceptable.&lt;/p&gt;

&lt;p&gt;Two months after the release we’re asked of adding an asiatic country: everything need to change, from taxes to customer fields. Given that any change can break the purchase process developers have started testing their changes on the staging environment after each push. This is slowing down the development, and the technical debt is now so high that we’re starting to feel the first problems. To pay back this debt we should now completely change our strategy, starting to dedicate some time to write tests and clean the more problematic points of the code.&lt;/p&gt;

&lt;p&gt;Six months have passed. On each new release we’re spotting new bugs, and for this reason it has been hired a QA specialist, whose duty is to visiting the staging environment before each production release to help spot and fix bugs. In this moment the interest on the technical debt is so high that we’re effectively paying a new employee, which would not be needed otherwise.&lt;/p&gt;

&lt;p&gt;After an year: Company grew up, and now we need to add the brand concept to the e-commerce. This requires a complete refactoring to the app. The team is doing their best, but development is going slowly. I like to think that at this point the technical debt has gained a physical form: it’s a snake swallowing its own tail. Technical debt is not so high that any development is slower, that the team is tired to work on the project but at the same time is so busy to not have time for refactoring.&lt;/p&gt;

&lt;p&gt;We’re not so close from the worst case scenario I mentioned before: rewriting the app costs too much (and rewriting from scratch is never a good choice), changing the app is instead too risky.&lt;/p&gt;

&lt;p&gt;Summarizing, every time we’re talking of:&lt;br&gt;&lt;br&gt;
– Code difficult to change;&lt;br&gt;&lt;br&gt;
– Code difficult to read;&lt;br&gt;&lt;br&gt;
– Unstable app;&lt;br&gt;&lt;br&gt;
– Slow development cycle;&lt;br&gt;&lt;br&gt;
– Team hard to expand;&lt;br&gt;&lt;br&gt;
– Application hard to upgrade;&lt;br&gt;&lt;br&gt;
– Application hard to maintain;&lt;br&gt;&lt;br&gt;
– Low performances.&lt;/p&gt;

&lt;p&gt;We’re talking of technical debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we reduce the technical debt?
&lt;/h2&gt;

&lt;p&gt;Technical debt is a communication problem, and this inevitably brings to mind the &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_law"&gt;Conway Law&lt;/a&gt;: &lt;strong&gt;organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even before solving the technical debt into detail, changing the code, we need to solve the communication problem. We need to determine which communication protocols we’re going to use to document the project itself, the functional specifications, the ideas behind the code, and so on. Only after having decided which protocols to use we can delve into the code.&lt;/p&gt;

&lt;p&gt;What are this communication protocols, which can help so much into reducing the technical deb?&lt;br&gt;&lt;br&gt;
– Behavioural tests: automatic tests which test features at a high level (i.e. Using the browser in a web product). More than their value as tests, they’re also usually easy to understand and can reveal a lot about the intentions of the developers;&lt;br&gt;&lt;br&gt;
– The code itself:&lt;br&gt;&lt;br&gt;
 – Comments and code formatting. Even a simple blank line between to code blocks can communicate a lot (for example two blocks that deal with two distinct phases of the process);&lt;br&gt;&lt;br&gt;
 – Naming of variables, objects, methods, functions. Naming a variable “value” doesn’t say that much on what it may contain, and naming a method “calc” doesn’t say that much on what it’s calculating;&lt;br&gt;&lt;br&gt;
 – Errors: raising errors with a detailed description of what is happening may save your day in a year from now, when that error will pop up from nowhere during a process that is considered ultra-stable;&lt;br&gt;&lt;br&gt;
 – Again on the errors: there is nothing worse than not raising errors. The worst case is when you’re not receiving any error, still you don’t get any result (e.g. You see the “purchase successful” page but no order has been generated). Errors are useful, always.&lt;br&gt;&lt;br&gt;
– Version control system: A well written commit on Git may be the most precious tool to solve an incomprehensible bug, or when you’re reading an obscure line of code.&lt;br&gt;&lt;br&gt;
– Typical “project documentation”: setup procedures, deploy procedures, how to create a staging/production environment, how to execute a system task, and so on;&lt;br&gt;&lt;br&gt;
– Company chatroom, slack, forums, mailing lists. These tools have a persistent history and we can use them to keep track of discussions on the decision process;&lt;br&gt;&lt;br&gt;
– And there are a lot more than these, some of them more obvious than others.&lt;/p&gt;

&lt;p&gt;Using the right communication protocols can help us to build something new, something that can allow knowledge sharing between developers (present and future ones), something that acts as a communication bridge between the owner of the platform and the developers of the platform.&lt;/p&gt;

&lt;p&gt;Once we’ve set the communication protocols, we can start analyzing the project as it’s an ancient tomb, documenting each finding and trying to give an explanation to each object.&lt;/p&gt;

&lt;p&gt;But the real cleaning should be done gradually, while we’re also delivering new features maybe. But we should avoid changing everything at once. &lt;strong&gt;Rewriting a product is almost never a good idea&lt;/strong&gt; , because rewriting causes the loss of “implicit” specifications, of those hidden features that were contributing to give the product the experience we knew.&lt;/p&gt;

&lt;p&gt;There are some other side effects when doing a refactoring on large scale:&lt;br&gt;&lt;br&gt;
– It requires a substantial budget;&lt;br&gt;&lt;br&gt;
– It requires to stop developing new features while cleaning the code;&lt;br&gt;&lt;br&gt;
– It increases the chance to generate bugs because we could clean features whose effects are not fully understood, or because the testing process cannot test all their edge cases.&lt;/p&gt;

&lt;p&gt;Let’s imagine that our house is messy and some guests are coming (buying a new house and sell the old one is not an option). If we try to clean all the rooms together we’re risking to go out of time (and guests would see our house in a messy state). We could try to do just a rough cleaning of all the rooms, but our house would be still messy, only less messier than before. We could instead ignore the rooms when guests will not see (our restroom and the kitchen), and concentrate on the ones they’ll visit for sure (the living room and the bathroom).&lt;/p&gt;

&lt;p&gt;We could proceed with the same approach when refactoring. We create new features using the new communication protocols, and every time our feature deals or need to change an old feature, we also clean that feature upgrading it to the new standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical approach
&lt;/h2&gt;

&lt;p&gt;Experience has taught us that we need to follow a method when a client contact us for refactoring, upgrading or maintaining legacy applications.&lt;/p&gt;

&lt;p&gt;In these cases, the first step is a &lt;strong&gt;Code Inspection&lt;/strong&gt; , to evaluate the situation. We do a code analysis (with the help of some tools), so we can get an idea of what points of the code are more harder to read or to change, of what security vulnerabilities are present, of the status of the documentation. As a result &lt;strong&gt;we deliver to the customer a documentation which describes what we have found and what steps the customer could take to improve the situation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At this point it’s up to the customer to decide if this code inspection should result in starting a process of improvement. If the process starts, it’s time to &lt;strong&gt;define a team&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
– If there’s already a senior technical team our developers usually joins the existing team;&lt;br&gt;&lt;br&gt;
– If there’s a technical team but it’s composed mainly by junior developers, we usually try to leave the new developments to the existing team (followed by a mentor). At the same time another team composed by specialists works on the maintenance;&lt;br&gt;&lt;br&gt;
– If there’s no technical team, we can provide one.&lt;/p&gt;

&lt;p&gt;Then there’s the &lt;strong&gt;definition of a release life-cycle&lt;/strong&gt; :&lt;br&gt;&lt;br&gt;
– In the worst cases we cannot do this without also creating an operations team;&lt;br&gt;&lt;br&gt;
– If there are no counter issues we usually try to put in place a continuous release process;&lt;br&gt;&lt;br&gt;
– In special cases (for example when each release requires to produce specific documentation for users of the platform) we advise to work with milestones and scheduled releases;&lt;/p&gt;

&lt;p&gt;And finally we can &lt;strong&gt;define the ceremonies and the communication protocols&lt;/strong&gt; : this step changes a lot from customer to customer, because some of them have enough time to participate to each communication protocol, some others may only join us for a review/planning meeting each week, some others don’t like video conferencing tools, and so on. The following is a typical setup:&lt;br&gt;&lt;br&gt;
– 15 minutes standup every morning at 10:00 (except Wed);&lt;br&gt;&lt;br&gt;
– 30 minutes review meeting every Wednesday at 15:00;&lt;br&gt;&lt;br&gt;
– 30 minutes planning meeting every Wednesday at 15:30;&lt;br&gt;&lt;br&gt;
– Production release every Thursday at 02:00;&lt;br&gt;&lt;br&gt;
– Retrospective and progress report every first friday of the month at 17:00;&lt;br&gt;&lt;br&gt;
– Definitions of &lt;em&gt;Done&lt;/em&gt;. Example:&lt;br&gt;&lt;br&gt;
 – For a feature to be released in staging is needed:&lt;br&gt;&lt;br&gt;
 – Automatic unit tests;&lt;br&gt;&lt;br&gt;
 – &lt;em&gt;Code Review&lt;/em&gt; from a colleague;&lt;br&gt;&lt;br&gt;
 – Being documented in the &lt;em&gt;Changelog&lt;/em&gt;;&lt;br&gt;&lt;br&gt;
 – To have at least one integration test.&lt;br&gt;&lt;br&gt;
 – For a feature to be released in production is needed:&lt;br&gt;&lt;br&gt;
 – To be approved at the Review meeting by the &lt;em&gt;Product Owner&lt;/em&gt;;&lt;br&gt;&lt;br&gt;
 – Be translated in each supported language.&lt;br&gt;&lt;br&gt;
 – For a bugfix to be released is needed:&lt;br&gt;&lt;br&gt;
 – To have at least one test that is testing the absence of the bug.&lt;/p&gt;

&lt;p&gt;Now the team can start working on the project. &lt;strong&gt;The objective is to create stability, to reach that point of equilibrium between growth and stability in which developments at par while keeping the technical debt low.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually during time we also find ourselves reducing the team size because:&lt;br&gt;&lt;br&gt;
– The amount of automatic tests reduce the regressions caused by any new feature;&lt;br&gt;&lt;br&gt;
– The code becomes more readable and more manageable;&lt;br&gt;&lt;br&gt;
– Junior developers learn how to write code with a low (or absent) level of technical debt.&lt;/p&gt;

&lt;p&gt;The wealth we’re creating at the end of this process allow us to deliver new features easily. At the same time this creates a new class of developers, more &lt;em&gt;virtuous&lt;/em&gt; and careful about certain themes. &lt;strong&gt;In the end we can say that this process is becoming part of the company culture, changing the result of the Conway Law&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>softwaredesign</category>
      <category>productivity</category>
      <category>architecture</category>
      <category>methodology</category>
    </item>
  </channel>
</rss>
