<?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: Matteo Joliveau</title>
    <description>The latest articles on DEV Community by Matteo Joliveau (@matteojoliveau).</description>
    <link>https://dev.to/matteojoliveau</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%2F35649%2F3145b391-8831-45a6-884d-1d6d8c225854.jpg</url>
      <title>DEV Community: Matteo Joliveau</title>
      <link>https://dev.to/matteojoliveau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matteojoliveau"/>
    <language>en</language>
    <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>I don't like remote working</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Tue, 09 Oct 2018 07:49:36 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/i-dont-like-remote-working-2clk</link>
      <guid>https://dev.to/matteojoliveau/i-dont-like-remote-working-2clk</guid>
      <description>&lt;p&gt;I feel like I'm the only developer in the world that truly enjoy going to the office every morning.&lt;/p&gt;

&lt;p&gt;I like my colleagues, sometimes we have sushi for lunch, we play boardgames once a week after work and is generally a fun experience to work at the same desk. Being able to share knowledge and discuss with other colleagues face-to-face is really important to me, and the light chitchat at the coffee machine is invaluable.&lt;/p&gt;

&lt;p&gt;So while I do understand the benefits of remote working (to be fair, we can do remote at will, and I did a couple of times) I really don't see the value in terms of productivity and social engagement over working physically all together. &lt;/p&gt;

&lt;p&gt;What are your thoughts on the matter? Do you work remotely or on site? Are you happy about your setup?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>remote</category>
    </item>
    <item>
      <title>I built a custom CMS because why not</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Mon, 13 Aug 2018 20:07:33 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/i-built-a-custom-cms-because-why-not-gdn</link>
      <guid>https://dev.to/matteojoliveau/i-built-a-custom-cms-because-why-not-gdn</guid>
      <description>&lt;p&gt;My personal website was a static site generated with &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, and it worked very well. It was fast to serve, lightweight and the &lt;a href="https://themes.gohugo.io/hugo-elate-theme/"&gt;Elate theme&lt;/a&gt; I used was simply gorgeous.&lt;br&gt;
However, I had to edit the config file manually every time I wanted to add or remove a project from my portfolio, or a job description from my resume. And then I had to recompile the website and push it back to GitHub, which would trigger a pipeline to build a Docker container to be deployed on my server and yadda yadda. Boring and unpractical.&lt;br&gt;
So I started looking for some cool and easy to maintain CMSs. WordPress was obviously the first one that came to mind but I can't really stand it after having worked for 4 years as an editor for various websites, plus it's the opposite of maintainable and I don't like PHP.&lt;br&gt;
&lt;strong&gt;October&lt;/strong&gt; seemed a cool alternative, even if it is written in PHP at least it ses Laravel which is a well-designed framework, but I had troubles deploying it with Docker. Same for &lt;strong&gt;Wagtail&lt;/strong&gt;, which was in Python, a language I like.&lt;/p&gt;

&lt;p&gt;So I gave up and started working on my own CMS, tailored around my personal needs.&lt;br&gt;
I figured that if a good looking, well animated and stylish front page is crucial for frontend developers to showcase their skills, a robust and well-built web application works the same way for a backend developer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Round of applause for &lt;a href="https://github.com/matteojoliveau/dev-cms"&gt;DevCMS&lt;/a&gt; and its very original name
&lt;/h1&gt;

&lt;p&gt;It's a very simple app, built with Ruby on Rails 5.2 and &lt;a href="https://bulma.io"&gt;Bulma&lt;/a&gt; for the CSS part (I'm a backend developer, I suck at styles).&lt;br&gt;
It uses &lt;a href="https://github.com/thoughtbot/administrate"&gt;Administrate&lt;/a&gt; as its back-office interface and ActiveStorage to upload and store images in S3 (actually, I host a private, S3-compatible &lt;a href="https://minio.io"&gt;Minio&lt;/a&gt; server, but it's the same). Bear in mind that this app was built in two days, so rough edges are still there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DevCMS&lt;/strong&gt; is built around three core concepts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Projects
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dj7N-7K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9k44kr6o8kqsd4konyb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dj7N-7K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9k44kr6o8kqsd4konyb1.png" alt="Projects"&gt;&lt;/a&gt;&lt;br&gt;
A portfolio is crucial for a software developer, it helps to show off what you can do to potential recruiters and peers. So projects are first class citizens here. They have a name, a short description, a longer description (formatted in HTML and written with a WYSIWYG editor in the admin panel), some tags and a cover image. They can be "starred" so that more significant projects appear on homepage, and they have a concept of draft/published, so they can be created and later compiled before being published.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jobs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xS5ReCUD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/egah0zdfaxkk70cznh7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xS5ReCUD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/egah0zdfaxkk70cznh7n.png" alt="Jobs"&gt;&lt;/a&gt;&lt;br&gt;
We are one of the most mobile and dynamic professional figures, so our career timeline is very important to demonstrate the positions we held in the past. Jobs are very similar to their LinkedIn counterparts, a position at a company during a set period of time. Like projects, they have short and long descriptions, a cover image and can be drafted and published. They are presented in a nice little timeline created with a &lt;a href="https://wikiki.github.io/components/timeline/"&gt;Bulma extension&lt;/a&gt;, from newest to oldest.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;### Copies&lt;/del&gt;&lt;br&gt;
&lt;del&gt;I wanted to have some static pages like &lt;a href="https://matteojoliveau/about"&gt;about me&lt;/a&gt; and &lt;a href="https://matteojoliveau/contacts"&gt;contacts&lt;/a&gt; but didn't want to hardcode them in HTML. So, while I work on implementing proper page generation, I added the concept of a &lt;strong&gt;Copy&lt;/strong&gt;, a piece of formatted text stored in Postgres that is served inside the HTML. Pages are still hardcoded for the moment, but at least I can edit their content directly from the admin panel.&lt;/del&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pages
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_iWe4659--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hqwoim2za0o6c399yg22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_iWe4659--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hqwoim2za0o6c399yg22.png" alt="Pages"&gt;&lt;/a&gt;&lt;br&gt;
UPDATE 18/08/2018&lt;br&gt;
I added basic support for dynamic pages so that they can be created and edited without having to access the source code and perform redeploy.&lt;br&gt;
Templates are written in &lt;a href="https://shopify.github.io/liquid/"&gt;Liquid language&lt;/a&gt;, so they are safe and controlled, and can access the published project and job lists. Pages can be automatically added to the navbar and their order controlled by a weight system.&lt;/p&gt;

&lt;p&gt;Also, some smaller things like copyright year and author for the footer can be customized via &lt;strong&gt;Config&lt;/strong&gt; objects, key-value pairs stored in the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Need for Speed
&lt;/h2&gt;

&lt;p&gt;Inspired by The Practical Dev and this very website, I wanted mine to be equally fast and performant. Beside standard Rails solutions like the provided &lt;a href="https://github.com/turbolinks/turbolinks"&gt;Turbolinks&lt;/a&gt; installation, I kept the JavaScript presence very small (only Turbolinks, ActiveStorage, and the mobile burger button handler are present). I also enabled AWS CloudFront as its CDN to cache static assets and enabled CloudFlare as an extra caching layer and DDoS protection (I had a couple in the past, no idea why). &lt;br&gt;
I have it monitored by &lt;a href="https://sentry.io"&gt;Sentry&lt;/a&gt; so that exceptions are automatically handled and reported. It's a very nice service, if I may.&lt;/p&gt;

&lt;p&gt;At the moment it is not a general purpose framework or application that anyone can install, but it is easily customizable if you want to try it on your own. It is open sourced at &lt;a href="https://github.com/matteojoliveau/dev-cms"&gt;GitHub&lt;/a&gt;.&lt;br&gt;
I'd like to make it more generic and tunable in the future, maybe by adding themes support and real admin-defined static pages. &lt;br&gt;
I also want to add the concept of &lt;strong&gt;skills&lt;/strong&gt;, to show how confident or expert I am with various technologies and languages, maybe with some fancy percentage bars or something along those lines.&lt;br&gt;
So, what do you think? How did you put together your personal developer website?&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>opensource</category>
      <category>showdev</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>PlugFace Reborn - the Java Plugin System</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Mon, 09 Apr 2018 08:53:44 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/plugface-reborn---the-java-plugin-system-18bm</link>
      <guid>https://dev.to/matteojoliveau/plugface-reborn---the-java-plugin-system-18bm</guid>
      <description>&lt;p&gt;&lt;em&gt;Visit &lt;a href="https://plugface.matteojoliveau.com" rel="noopener noreferrer"&gt;https://plugface.matteojoliveau.com&lt;/a&gt; for the full documentation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One year ago I came across the need to dynamically load bits of code into my Java applications without having to recompile or repackage my software every time. Basically, I was looking for a plugin system.&lt;/p&gt;

&lt;p&gt;There was only one open source plugin system worth noting at the time, &lt;a href="https://github.com/pf4j/pf4j" rel="noopener noreferrer"&gt;PF4J&lt;/a&gt;, but I felt it was a bit clunky and cumbersome. I wanted something dead simple, that I could use to be productive in minutes. So I decided to write my own.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://github.com/matteojoliveau/plugface" rel="noopener noreferrer"&gt;PlugFace&lt;/a&gt;. &lt;br&gt;
And the first iteration was sh*tty as hell, because at the time I was just an intern at my company, still learning real-world Java and didn't have the knowledge to write a good, usable framework.&lt;/p&gt;
&lt;h1&gt;
  
  
  The Ugly
&lt;/h1&gt;

&lt;p&gt;The first implementation was not so simple as I wanted it to be.&lt;br&gt;
There were interfaces to implement, reflection to use, configuration files to write, a sandboxed permission system, a half-working/half-broken attempt at dependency injection between plugins, and a lot of sweat and tears from me to both write it and use it.&lt;br&gt;
Not the greatest software in the world.&lt;br&gt;
Here is an example of an old PlugFace plugin:&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.plugins.greet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.Plugin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.PluginConfiguration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.PluginStatus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.app.sdk.Greeter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.impl.DefaultPluginConfiguration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Collections&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;GreeterPlugin&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Plugin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[],&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="nc"&gt;Greeter&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;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PluginConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;PluginStatus&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;enabled&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;GreeterPlugin&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"greeter"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;configuration&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;DefaultPluginConfiguration&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PluginStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;READY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This plugin operates in single mode only"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnsupportedOperationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This plugin operates in single mode only"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;parameters&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="nf"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PluginConfiguration&lt;/span&gt; &lt;span class="nf"&gt;getPluginConfiguration&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="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PluginConfiguration&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unmodifiableMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setPluginConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PluginConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&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;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getName&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="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PluginStatus&lt;/span&gt; &lt;span class="nf"&gt;getStatus&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="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PluginStatus&lt;/span&gt; &lt;span class="n"&gt;pluginStatus&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pluginStatus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enable&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;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;disable&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;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isEnabled&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="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&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="s"&gt;"Hello PlugFace!"&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;These things were &lt;strong&gt;monsters&lt;/strong&gt;, the interface was huge and full of debatably useful features (like status and name) and they were not practical to implement.&lt;br&gt;
If you wanted more complex behaviors than 'start', 'stop' and 'execute', you had to add your own interfaces and cast your plugin to that type in order to use it or access the methods via reflection.&lt;/p&gt;

&lt;p&gt;Then an idea stroke me. Why bother restricting the way a user interacts with a plugin when all the framework could deal with was the dynamic class loading?&lt;/p&gt;
&lt;h1&gt;
  
  
  The Good
&lt;/h1&gt;

&lt;p&gt;With version 0.6, the framework revived. It was an (almost) complete rewrite. I ditched the whole interface story for a much cleaner &lt;code&gt;@Plugin("name")&lt;/code&gt; annotation and ZERO opinions on how your plugin shall behave. Simply make it implement some interface your application is aware of and then access it through it.&lt;/p&gt;

&lt;p&gt;Here is the same plugin but with the new system:&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.plugins.greet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.core.annotations.Plugin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.app.sdk.Greeter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Plugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greeter"&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;GreeterPlugin&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;greet&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="s"&gt;"Hello PlugFace!"&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;It implements the &lt;code&gt;Greeter&lt;/code&gt; interface provided by my application. Now my code can simply retrieve the plugin an put it in a variable of type Greeter without ever have to be aware of the &lt;code&gt;GreeterPlugin&lt;/code&gt; class. Neat!&lt;/p&gt;

&lt;p&gt;Here is my application code.&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="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PluginManager&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PluginManagers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultPluginManager&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadPlugins&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PluginSources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jarSource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"path/to/my/plugin/jars"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPlugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;greet&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; "Hello PlugFace!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;PluginManager&lt;/code&gt; is a utility class to load plugins from various sources, another improvement over the old version which only featured hard-coded JAR loading, and accesses the &lt;code&gt;PluginContext&lt;/code&gt; to add/get/remove plugins both by name and by type.&lt;/p&gt;

&lt;p&gt;I also entirely ditched the Sandbox functionalities, which leveraged the Java SecurityContext features to restrict plugins in what they were allowed to do. As it was a huge pain to deal with, I preferred to remove it entirely to focus on the core features for this new version. I might reintroduce it in a future version if I find a way to implement it in a convenient fashion.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependency Injection done right
&lt;/h1&gt;

&lt;p&gt;A feature the old system tried to introduce was the possibility of having plugins injected into each other. It achieved this by putting plugins into the &lt;code&gt;PluginConfiguration&lt;/code&gt; object (which was basically a glorified &lt;code&gt;Map&amp;lt;String, Object&amp;gt;&lt;/code&gt;, it worked but was fairly unpractical to use.&lt;/p&gt;

&lt;p&gt;PlugFace 0.6 introduced a full-fledged dependency injection system via constructors, using the standard &lt;code&gt;@javax.inject.Inject&lt;/code&gt; annotation (which will be made optional in the future in case of a single constructor being present) so that plugin classes can be used with any standard DI framework such as &lt;a href="https://spring.io" rel="noopener noreferrer"&gt;Spring&lt;/a&gt; or &lt;a href="https://github.com/google/guice" rel="noopener noreferrer"&gt;Guice&lt;/a&gt;.&lt;br&gt;
It supports complicated dependency graphs using &lt;a href="https://en.wikipedia.org/wiki/Topological_sorting" rel="noopener noreferrer"&gt;topological sorting&lt;/a&gt;, with circular dependencies detection and all that good stuff.&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.plugins.math&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.core.annotations.Plugin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.app.sdk.Mathematics&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Plugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"math"&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;MathPlugin&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Mathematics&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;SumPlugin&lt;/span&gt; &lt;span class="n"&gt;sum&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;MultPlugin&lt;/span&gt; &lt;span class="n"&gt;mult&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MathPlugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SumPlugin&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MultPlugin&lt;/span&gt; &lt;span class="n"&gt;mult&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum&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;mult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mult&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&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="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;mult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&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="n"&gt;mult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;h1&gt;
  
  
  Spring Integration
&lt;/h1&gt;

&lt;p&gt;The Spring Framework is a tremendous toolkit in Java. It features pretty much anything, but its core feature is clearly the dependency injection system. Since I use Spring a lot in nearly all my projects, I wanted PlugFace to be well integrated with it.&lt;br&gt;
If you want to use plain vanilla PlugFace you can import the &lt;code&gt;plugface-core&lt;/code&gt; module, but if using Spring you may want to switch to the special &lt;code&gt;plugface-spring&lt;/code&gt; module.&lt;br&gt;
Not only it sports auto-configured beans for both the PluginManager and the PluginContext, but it also adds support for plugin retrieval from the &lt;code&gt;ApplicationContext&lt;/code&gt; (meaning if an object is not found as a plugin, it will be looked up amongst Spring beans) and, perhaps more importantly, it makes Spring beans viable targets for dependency injection in plugins.&lt;/p&gt;

&lt;p&gt;That's right, with &lt;code&gt;plugface-spring&lt;/code&gt; you can not only inject other plugins inside your plugins, but also any Spring bean you have registered in your application.&lt;/p&gt;

&lt;p&gt;Your plugins can access service classes, repositories, utility singletons, basically anything lives inside the Spring context.&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="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.plugins.user&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.core.annotations.Plugin&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.app.sdk.Greeter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.plugface.demo.app.sdk.TestService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.inject.Inject&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Plugin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"greeter"&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;UserPlugin&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;UserDetails&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="c1"&gt;//this is a Spring service&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;GreeterPlugin&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;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&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;getUserById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&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;h1&gt;
  
  
  From Now On
&lt;/h1&gt;

&lt;p&gt;In the future, I want to integrate with other DI frameworks as well, such as Guice, and expand upon the current feature set if any new use case for plugins in Java comes up. &lt;br&gt;
Until then, thanks for the attention, and happy coding!&lt;/p&gt;

</description>
      <category>java</category>
      <category>plugins</category>
      <category>spring</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Microservices communications. Why you should switch to message queues.</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Fri, 23 Feb 2018 16:59:52 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/microservices-communications-why-you-should-switch-to-message-queues--48ia</link>
      <guid>https://dev.to/matteojoliveau/microservices-communications-why-you-should-switch-to-message-queues--48ia</guid>
      <description>&lt;p&gt;&lt;em&gt;This is actually a more elaborate version of an old comment I wrote &lt;a href="https://dev.to/matteojoliveau/comment/1bk1"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When doing microservices, a fairly crucial design point is: how should my services communicate with each other?&lt;br&gt;
Many people usually choose to design some RESTful HTTP API that each service expose and then have the other services invoke it with a normal HTTP client.&lt;br&gt;
This has some advantages, primarily making it easy to discover services by using DNS resolution and API Gateways, but it has many drawbacks too.&lt;br&gt;
For example, what if the called service has crashed down and cannot respond? Your client service has to implement some kind of reconnection or failover logic, otherwise, you risk to lose requests and pieces of information. A cloud architecture should be resilient and recover gracefully from failures. Also, an HTTP request is a blocking API, making it asynchronous implies some tricky shenanigans on the client side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entering message queues
&lt;/h2&gt;

&lt;p&gt;Using message queues is actually a fairly old solution when dealing with multiple intercommunicating services. Think about old approaches like Enterprise Service Buses or the Java JMS specification.&lt;/p&gt;

&lt;p&gt;Let's start by introducing some terminology:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Message&lt;/em&gt;: a package for information, usually composed of two parts. Some &lt;strong&gt;headers&lt;/strong&gt;, key-value pairs containing metadata, and a &lt;strong&gt;body&lt;/strong&gt;, a binary package containing the actual message itself.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Producer&lt;/em&gt;: whoever creates and sends a message&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Consumer&lt;/em&gt;: whoever receives and reads a message&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Queue&lt;/em&gt;: a communication channel that enqueues messages for later retrieval by one or more consumers&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Exchange&lt;/em&gt;: a queue aggregator that abstract away message queues and routes messages to the appropriate queue based on some predefined logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A message queue architecture requires an additional service called a &lt;em&gt;message broker&lt;/em&gt; that is tasked with gathering, routing and distributing your messages from senders to the right receivers.&lt;br&gt;&lt;br&gt;
Think of it as a mail service. You (the producer) are sending a letter (your message) to someone (the consumer), and you do this by specifying the address (the routing logic for the message, such as the topic on which it is published) and by giving the letter to the local Post office (the message broker). After you deliver the letter, it's no longer your business to ensure that it actually arrives at your friend. The postal service will take care of that.&lt;/p&gt;

&lt;p&gt;In a microservice environment, it's actually a really solid solution because it adds a layer of abstraction (the message broker itself) between loosely coupled services and allows for fully asynchronous communications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Errors will occur. Let's deal with them instead of simply avoiding them
&lt;/h2&gt;

&lt;p&gt;Remember, a cloud environment should be error-resilient and services must fail gracefully and not take down the whole application if one of them dies. With message queues if a microservice dies unexpectedly the broker can still receive incoming messages, store them for later (so that the dead service can recover them when it comes back online) and optionally send back a &lt;em&gt;Last Will and Testament&lt;/em&gt; message to the other service saying that the receiver has died. Also, &lt;em&gt;Push/Pull&lt;/em&gt;, &lt;em&gt;Publish/Subscribe&lt;/em&gt; and &lt;em&gt;Topic&lt;/em&gt; queue mechanisms give more flexibility and efficiency when designing inter-service communications, and the ability to send binary payloads allow for easy use of formats like &lt;a href="https://github.com/google/protobuf" rel="noopener noreferrer"&gt;Google ProtoBuff&lt;/a&gt; or &lt;a href="https://msgpack.org/" rel="noopener noreferrer"&gt;MessagePack&lt;/a&gt; instead of JSON, which are much more efficient in terms of bandwidth usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security is key
&lt;/h2&gt;

&lt;p&gt;Advanced broker servers like &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt; support multiple message protocols (AMQP, MQTT, STOMP...), have &lt;a href="https://www.rabbitmq.com/access-control.html" rel="noopener noreferrer"&gt;flexible authorization mechanism&lt;/a&gt; (access control, virtual hosts and even third party/custom auth services via many different transports such as &lt;a href="https://github.com/rabbitmq/rabbitmq-auth-backend-http" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt; or &lt;a href="https://github.com/rabbitmq/rabbitmq-auth-backend-amqp" rel="noopener noreferrer"&gt;AMQP&lt;/a&gt;) and will basically remove the burden of orchestrating requests authorization from your service. Plug a custom microservice into Rabbit's auth backend and code your policies in there. The rest will be taken care of by the broker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure at scale
&lt;/h2&gt;

&lt;p&gt;Using message queues with brokers like Rabbit helps a lot with scalability too, which is another crucial aspect of microservices.&lt;br&gt;
If one of the services is struggling under load we want to be able to spin up more instances quickly and without having to reconfigure stuff around.  With HTTP as our communication method we would normally have a self-registering &lt;strong&gt;Service Discovery Server&lt;/strong&gt; (like &lt;a href="https://github.com/Netflix/eureka" rel="noopener noreferrer"&gt;Netflix Eureka&lt;/a&gt; or a container orchestration system like &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; or &lt;a href="http://rancher.com/" rel="noopener noreferrer"&gt;Rancher&lt;/a&gt;) and some kind of load balancer integrated with it so that our traffic is distributed and routed to the various instances. With message queues, our broker IS the load balancer. If multiple consumers are listening to a topic at the same time messages will be delivered following a configured strategy (more on RabbitMQ's QoS &lt;a href="https://insidethecpu.com/2014/11/11/rabbitmq-qos-vs-competing-consumers/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;br&gt;&lt;br&gt;
So, for example, we can have four instances of our service processing messages in a round robin fashion, but since the QoS parameter is customizable at runtime we could also switch to a &lt;a href="https://www.rabbitmq.com/tutorials/tutorial-two-java.html" rel="noopener noreferrer"&gt;fair dispatching strategy&lt;/a&gt; if one of the consumers is taking too long to complete its work and we need to balance the load out. Also, note that the client configuration is entirely done at runtime (and so is exchanges, queues and topics declarations by the way) so there is no need to tinker with the broker's configuration or restart anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async == Efficiency
&lt;/h2&gt;

&lt;p&gt;We said at the beginning that one of the key features of messages compared to HTTP requests is that they allow for fully async communications. If I need to make a request to another service I can send a message on it's topic and then move on with my work. I can deal with the response when it comes in on my own topic, without having to wait for it. &lt;a href="http://www.enterpriseintegrationpatterns.com/patterns/messaging/CorrelationIdentifier.html" rel="noopener noreferrer"&gt;Correlation IDs&lt;/a&gt; are used to keep track of which response message refers to which request. This works in concert with what we said about resiliency.&lt;br&gt;
In an HTTP scenario, if I make a request and the callee is down, the connection would be refused and I would have to try again and again until it comes back up.&lt;br&gt;
With message systems, I can send my request and forget about it. If the callee cannot receive it the broker will keep the message in the queue, and then deliver it when the consumer connects back. My response will come back when it can and I won't have to block or wait for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion, messages are great. Show them some love
&lt;/h2&gt;

&lt;p&gt;This is by no mean a rant against HTTP (which is still great, especially for public front facing APIs) but rather a try to guide you towards a more efficient and proficient strategy to coordinate microservice communications and all of this can be achieved with open source software, open protocols such as AMQP that prevent vendor lock-in and with a low (and scalable) infrastructure cost (see &lt;a href="https://www.rabbitmq.com/production-checklist.html" rel="noopener noreferrer"&gt;RabbitMQ's requirements&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I used RabbitMQ for all my microservices project and it has been a great experience. Let me know in the comments what are your thoughts! Have you used message queues before? What is your experience with it?&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>cloud</category>
      <category>amqp</category>
      <category>rest</category>
    </item>
    <item>
      <title>Moving to OpenShift!</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Tue, 29 Aug 2017 21:57:06 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/moving-to-openshift-apo</link>
      <guid>https://dev.to/matteojoliveau/moving-to-openshift-apo</guid>
      <description>&lt;h1&gt;
  
  
  I finally made it!
&lt;/h1&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%2Fmatteojoliveau.com%2Fcontent%2Fimages%2F2017%2F08%2Fopenshift.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%2Fmatteojoliveau.com%2Fcontent%2Fimages%2F2017%2F08%2Fopenshift.png" alt="Moving to OpenShift!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I dreamed of installing &lt;a href="https://www.openshift.org/" rel="noopener noreferrer"&gt;OpenShift Origin&lt;/a&gt; on my server since a collegue showed me our installation at work. The idea of having a way to automate builds, deploys, orchestration and scaling of the applications that I develop was just amazing for me.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;BUT&lt;/strong&gt; , big problems arise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old server
&lt;/h2&gt;

&lt;p&gt;A couple of friends and I one day rented a server together. Tired of having small, crappy VPSs we rented a massive &lt;strong&gt;dedicated server&lt;/strong&gt; from &lt;a href="https://www.hetzner.de/" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt;, something like a &lt;strong&gt;quadcore Xeon processor&lt;/strong&gt; and &lt;strong&gt;32 GB of RAM&lt;/strong&gt;. It was all good and wonderful, we ran a &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; engine to run our applications, databases and whatnot inside containers and an &lt;a href="https://nginx.org/en/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; reverse proxy in front of them to route the traffic coming from the outside world.&lt;br&gt;&lt;br&gt;
Since &lt;strong&gt;OpenShift&lt;/strong&gt; nearly cannibalize a server when it's installed, since it wants to handle all the traffic coming from ports 80 and 443 with it's own internal proxy, it was out of question to uninstall everything and migrate to the Origin platform. End of story.&lt;/p&gt;

&lt;p&gt;Then we realized we needed nearly half of this compute power and paying &lt;strong&gt;40€ a month&lt;/strong&gt; for the dedicated server seemed a bit too much for a few guys playing the sysadmin game.&lt;/p&gt;

&lt;p&gt;So we decided to migrate our server to a much cheaper VPS from &lt;a href="https://nginx.org/en/" rel="noopener noreferrer"&gt;Contabo&lt;/a&gt; (still a very resonable machine, with 6 cores, 24 GB of RAM and a whopping 600 GB of SSD storage) &lt;strong&gt;AAAAAAND&lt;/strong&gt; this allowed me to install my so long awaited OpenShift platform :D&lt;br&gt;&lt;br&gt;
It was an excruciating pain to set up, let me tell you. First the &lt;a href="https://github.com/openshift/openshift-ansible" rel="noopener noreferrer"&gt;Ansible installer&lt;/a&gt; didn't manage to complete its job, but since it seemed to be a bug in the installer itself using a newer patch seemed to fix it.&lt;br&gt;&lt;br&gt;
Then the integrated Docker registry and HAProxy router couldn't deploy because I didn't labeled the node (aka the master aka the only server in my cluster) as "infra", or "infrastructure".&lt;br&gt;&lt;br&gt;
Then the Docker registry couldn't write to its internal directory, mounted as a NFS share, because of some wrong POSIX permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  BUT NOW EVERYTHING IS COMPLETED
&lt;/h2&gt;

&lt;p&gt;If you are reading this post in the recent future, and we didn't already migrate yet another time, then &lt;strong&gt;this very blog is actually running as an OpenShift service&lt;/strong&gt; inside a docker container, using yet another service holding a MariaDB engine as the storage backend.&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%2Fmatteojoliveau.com%2Fcontent%2Fimages%2F2017%2F08%2Fghost-pod.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%2Fmatteojoliveau.com%2Fcontent%2Fimages%2F2017%2F08%2Fghost-pod.png" alt="Moving to OpenShift!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If needed (and it won't be needed) I can scale this container a &lt;strong&gt;hundred of times&lt;/strong&gt; and I will be able to handle the combined traffic of the Washington Post and Wikipedia during peak hours.&lt;br&gt;&lt;br&gt;
Or maybe not, I suppose the VPS would die way before the blog.&lt;br&gt;&lt;br&gt;
But still, you get the idea.&lt;/p&gt;

&lt;p&gt;Also I'm running a couple of useful services on the platform, such as a private &lt;a href="https://gogs.io" rel="noopener noreferrer"&gt;Gogs&lt;/a&gt; repository server and a &lt;a href="http://www.sonatype.org/nexus/" rel="noopener noreferrer"&gt;Sonatype Nexus&lt;/a&gt; repository manager for my &lt;a href="https://maven.apache.org/" rel="noopener noreferrer"&gt;Maven&lt;/a&gt; projects.&lt;/p&gt;

&lt;p&gt;My friend has developed some &lt;a href="https://telegram.org" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; bots in the past and OpenShift makes him able to simply push new code to Git to have the changes immediately deployed and live. (BTW go check his awsome &lt;a href="https://t.me/tagalertbot" rel="noopener noreferrer"&gt;TagAlertBot&lt;/a&gt; out, if you use Telegram it's a huge improvement)&lt;/p&gt;

&lt;h2&gt;
  
  
  Long Live OpenShift
&lt;/h2&gt;

&lt;p&gt;So I'm pretty happy with the deployment. 99% of the stuff we need runs without an issue, and the 1% that doesn't have some kind of workaround we can try to make it work. So yay, welcome to the PaaS world!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>development</category>
    </item>
    <item>
      <title>GNU Public License is all but free and you should never use it</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Wed, 31 May 2017 15:17:26 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/gnu-public-license-is-all-but-free-and-you-should-never-use-it-3fk</link>
      <guid>https://dev.to/matteojoliveau/gnu-public-license-is-all-but-free-and-you-should-never-use-it-3fk</guid>
      <description>&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%2Fwg9o20gzbmf6pylzk28l.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%2Fwg9o20gzbmf6pylzk28l.png" alt="GNU Public License is all but free and you should never use it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Free Software Foundation and its sprout the GNU Project are a core element of the free and open source software movement.  &lt;/p&gt;

&lt;p&gt;They led to a new era of software development where sharing and improving as a community is more valuable than selling proprietary software (maybe because we &lt;a href="https://matteojoliveau.com/from-product-makers-to-service-providers" rel="noopener noreferrer"&gt;stopped selling software altogether&lt;/a&gt; and started selling services).  &lt;/p&gt;

&lt;p&gt;But there is a key thing in the most popular free licence of the world, a key problem that let me question if this license is truly free, or if it brings a distorted concept of freedom.  &lt;/p&gt;

&lt;p&gt;And it's a problems affecting both version &lt;a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html" rel="noopener noreferrer"&gt;2.0&lt;/a&gt; and &lt;a href="https://www.gnu.org/licenses/gpl.html" rel="noopener noreferrer"&gt;3.0&lt;/a&gt; of the GNU Public License.  &lt;/p&gt;

&lt;p&gt;Is a license that sets limits to developers really "free"?  &lt;/p&gt;

&lt;p&gt;Software freedom as intended by Richard Stallman and the FSF is not real freedom, just like communism is not really about sharing and loving each other.  &lt;/p&gt;

&lt;p&gt;Communism is more like being at the bottom of the pit, and forcing everyone to stay down there just because you don't wanna be left behind by those who manage to climb.  &lt;/p&gt;

&lt;p&gt;Software freedom in the stallmanian way of thinking is not about being free, is about not doing anything on your own.  &lt;/p&gt;

&lt;p&gt;No commercial software, no code that you keep for yourself, no way to use it in a manner that makes you keep it private. Which is good, right?  &lt;/p&gt;

&lt;p&gt;Well, not really. Not at all.&lt;/p&gt;




&lt;h3&gt;
  
  
  Free not to be free
&lt;/h3&gt;

&lt;p&gt;A key point of this whole text is about the definition of freedom. What follows is &lt;strong&gt;&lt;em&gt;MY POINT OF VIEW&lt;/em&gt;&lt;/strong&gt; and does not reflect any "official" definition of &lt;em&gt;freedom&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;In my vision of software freedom, &lt;em&gt;free software&lt;/em&gt; means that I'm allowed to use it in my daily work, to make use of libraries and programs inside my projects. I mean, that is the whole reason I do open source in the first place. When I started the &lt;a href="https://plugface.org" rel="noopener noreferrer"&gt;PlugFace Framework&lt;/a&gt; I decided to release it under the MIT License because I thought that it could be useful to other people in need of using plugins inside their software. I thought of other developers in my same situation, in need of modularizing their monolitic application at work with a simple and robust solution. I don't care if you want to use it in proprietary software, on the contrary I would be flattered by this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;GPL wouldn't allow that to happen.&lt;/em&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;A PlugFace Framework released under GPL would have never been used in enterprise environment because it would require to the user to release their software under the same license. Even with LGPL, which allows software linking to proprietary software, would not have been ideal since any customization (i.e. proprietary security features to validate plugins?) could not have been kept private.  &lt;/p&gt;

&lt;p&gt;So if I'm developing a library, why should I want to use a GPL-like license?  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why should I choose a free license in order to limit other developers' freedom?&lt;/strong&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%2Fi.warosu.org%2Fdata%2Fg%2Fimg%2F0559%2F26%2F1470396293115.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%2Fi.warosu.org%2Fdata%2Fg%2Fimg%2F0559%2F26%2F1470396293115.jpg" alt="GNU Public License is all but free and you should never use it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;But Matt, without a strong copyleft license $InsertNefariousSoftwareCompanyHere could steal your work and sell it with their name on it, and you wouldn't see a dime of it&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I can hear you reply like that already.  &lt;/p&gt;

&lt;p&gt;And my answer would be: &lt;strong&gt;&lt;em&gt;THAT'S EXACTLY WHAT I WANT.&lt;/em&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;If you are reading this and you are a software company, please &lt;strong&gt;&lt;em&gt;TAKE MY CHILD SOFTWARE AND DO WHAT YOU WISH WITH IT.&lt;/em&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;If my goal was to make money I wouldn't be doing open source, I would try with something easier. Like forex trading, ice-cream making or underground drug dealing.  &lt;/p&gt;

&lt;p&gt;Instead, I'm doing open source software because I want people to use it, to solve problems with it. I imagine professional software developers like myself being stuck with a problem, finding out my &lt;a href="https://github.com/matteojoliveau" rel="noopener noreferrer"&gt;GitHub account&lt;/a&gt; and thinking "Well damn, this guy has made a library that exactly do what I need".  &lt;/p&gt;

&lt;p&gt;And it would download it, and link it into his software and proceding working, and I would send him a spiritual "You're welcome buddy" through the Force.  &lt;/p&gt;

&lt;p&gt;That's why, if you write software libraries, you should &lt;strong&gt;NEVER EVER USE GPL LICENSES&lt;/strong&gt;. The best enterprise software are released under weak copyleft licenses, like &lt;a href="https://kubernetes.io" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, &lt;a href="https://docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, &lt;a href="https://github.com/google/guava" rel="noopener noreferrer"&gt;Google Guava&lt;/a&gt;, &lt;a href="https://www.freebsd.org/" rel="noopener noreferrer"&gt;FreeBSD&lt;/a&gt; and many others.  &lt;/p&gt;

&lt;p&gt;cLinux doesn't count. Linux is a final product, not a middleware. But still, remember that without weak licensing and with Linux as the only open source OS, products like the &lt;a href="https://en.wikipedia.org/wiki/PlayStation_4_system_software" rel="noopener noreferrer"&gt;PlayStation 4&lt;/a&gt; and the &lt;a href="https://www.reddit.com/r/NintendoSwitch/comments/5xbe5a/the_switch_runs_freebsd_making_it_nintendos_first/" rel="noopener noreferrer"&gt;Nintendo Switch&lt;/a&gt; would be very very different.&lt;/p&gt;




&lt;h3&gt;
  
  
  Choose another license, please
&lt;/h3&gt;

&lt;p&gt;There are many many great licenses out there that are truly free. They will make Stallman angry (and that's probably something that I would truly enjoy), but they will also make many fellow developers happy and thankful.&lt;br&gt;&lt;br&gt;
My favourite ones are the the &lt;a href="https://opensource.org/licenses/Apache-2.0" rel="noopener noreferrer"&gt;Apache License 2.0&lt;/a&gt; and &lt;a href="https://opensource.org/licenses/MIT" rel="noopener noreferrer"&gt;MIT License&lt;/a&gt;. I release all of my works under those two licenses (and also the &lt;a href="https://opensource.org/licenses/MPL-2.0" rel="noopener noreferrer"&gt;MPL 2.0&lt;/a&gt; for complete products, aka not libraries). If you want a complete list, check out &lt;a href="https://choosealicense.com/licenses/" rel="noopener noreferrer"&gt;this awesome site&lt;/a&gt; from GitHub and look for licenses that does not feature the &lt;em&gt;Same license&lt;/em&gt; tag in the &lt;em&gt;Conditions&lt;/em&gt; column. They are the &lt;a href="https://en.wikipedia.org/wiki/Copyleft#Strong_and_weak_copyleft" rel="noopener noreferrer"&gt;weak-copyleft&lt;/a&gt; ones.&lt;/p&gt;




&lt;p&gt;That's all for now. Thank you all for your kind attention, and happy coding! &amp;lt;3&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>From product makers to service providers. Thoughts on the evolution of software development</title>
      <dc:creator>Matteo Joliveau</dc:creator>
      <pubDate>Fri, 31 Mar 2017 13:14:25 +0000</pubDate>
      <link>https://dev.to/matteojoliveau/from-product-makers-to-service-providers-thoughts-on-the-evolution-of-software-development-d01</link>
      <guid>https://dev.to/matteojoliveau/from-product-makers-to-service-providers-thoughts-on-the-evolution-of-software-development-d01</guid>
      <description>&lt;h3&gt;
  
  
  We used to ship products.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IFi3bew2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://matteojoliveau.com/content/images/2017/08/Data-Center.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IFi3bew2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://matteojoliveau.com/content/images/2017/08/Data-Center.jpg" alt="From product makers to service providers. Thoughts on the evolution of software development" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We were craftsmen, artisans as &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt; calls us.&lt;br&gt;&lt;br&gt;
We spent months planning a project, writing the code and polishing rough edges (well, not everyone always did this part, to be honest...) before releasing it, so that our users don't find any problem.&lt;br&gt;&lt;br&gt;
When users wanted to use our software, they had to buy it, and then we shipped it to them either as a download or on a physical media.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;They owned the software&lt;/strong&gt; , and even if they were not allowed to do everything they wanted with it, they didn't have to talk to us longer that needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1OROmjHX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://matteojoliveau.com/blog/content/images/2017/05/cloud_145.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1OROmjHX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://matteojoliveau.com/blog/content/images/2017/05/cloud_145.jpg" alt="From product makers to service providers. Thoughts on the evolution of software development" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;This is no longer the case&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Gone are the days of software as products, gone are the days of downloads and installations and updates and...&lt;br&gt;&lt;br&gt;
Well, ok not yet. But I can see it coming. The &lt;strong&gt;&lt;em&gt;Software as a Service&lt;/em&gt;&lt;/strong&gt; paradigm is starting to take root in Software Land and users are already accostumed to it. Take Google's cloud services like &lt;a href="https://mail.google.com"&gt;Gmail&lt;/a&gt; or &lt;a href="https://inbox.google.com"&gt;Inbox&lt;/a&gt;, &lt;a href="https://docs.google.com"&gt;Google Docs&lt;/a&gt; and &lt;a href="https://drive.google.com"&gt;Drive&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Take &lt;a href="https://www.youtube.com/"&gt;YouTube&lt;/a&gt;, or &lt;a href="https://web.skype.com/"&gt;Skype Web&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Even take the whole concept of &lt;em&gt;smartphones&lt;/em&gt;, the most common and diffused personal devices of the entire computer history.&lt;/p&gt;




&lt;p&gt;People are starting to see the &lt;strong&gt;&lt;em&gt;Cloud&lt;/em&gt;&lt;/strong&gt; as a growing and powerful computing platform, and I'm not only talking about students writing notes on Google Docs. I'm talking about big companies moving away their local infrastructure and start using &lt;em&gt;IaaS&lt;/em&gt; like &lt;a href="https://aws.amazon.com/"&gt;Amazon AWS&lt;/a&gt; or &lt;a href="https://azure.microsoft.com/"&gt;MS Azure&lt;/a&gt;, and developers like me who don't need to send their software to a sysadmin with a full deploying manual to see their applications running.&lt;/p&gt;

&lt;p&gt;For instance, at my current workplace we use a private instance of &lt;a href="https://www.openshift.org/"&gt;Red Hat OpenShift&lt;/a&gt; to deploy dev versions of our solutions. It's easy to use and does a great job at &lt;strong&gt;keeping the complexity away&lt;/strong&gt; from developers so that they can focus on coding full speed ahead.&lt;br&gt;&lt;br&gt;
We no longer have to buy machines to run our business&lt;sup&gt;&lt;a href="https://matteojoliveau.com/from-product-makers-to-service-providers/#fn1" id="fnref1"&gt;[1]&lt;/a&gt;&lt;/sup&gt;. We just use a web browser and deploy our software.&lt;/p&gt;

&lt;p&gt;You can hide all of the hardware-related issues and keep your dev team up and running &lt;strong&gt;working on new features&lt;/strong&gt; without sacrificing the user experience.&lt;/p&gt;




&lt;p&gt;And it's even better on the user side: hardware cost is going down.&lt;br&gt;&lt;br&gt;
There is no more need for powerful computers or portable devices, cheap, high energy efficient hardware can run all the modern computing tasks leveraging the power of a remote machine.&lt;br&gt;&lt;br&gt;
Some took this idea and brought it at an insane level, with &lt;strong&gt;&lt;em&gt;cloud IDEs&lt;/em&gt;&lt;/strong&gt; and developing tools like &lt;a href="https://eclipse.org/che/"&gt;Eclipse Che&lt;/a&gt;, &lt;a href="https://codenvy.com/"&gt;Codenvy&lt;/a&gt;(which uses the aforementioned Eclipse) and &lt;a href="https://c9.io/"&gt;Cloud9&lt;/a&gt;, which let you code and develop software as you were on your computer, but from a web browser.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.google.com/chromebook/"&gt;Chromebooks&lt;/a&gt; are a great example of this shift in mentality. Laptops that exist with the sole purpose of running the &lt;strong&gt;Chrome web browser&lt;/strong&gt; and entirely rely on the power of the cloud to provide &lt;strong&gt;mainstream users&lt;/strong&gt; with the light productivity and content consumption environment they need, sold at low cost and with very low specs.&lt;br&gt;&lt;br&gt;
They are the quintessence of the &lt;strong&gt;&lt;em&gt;as a Service&lt;/em&gt;&lt;/strong&gt; philosophy, of the distributed world we are building right now in the software industry.&lt;/p&gt;




&lt;h4&gt;
  
  
  It's easier and more secure
&lt;/h4&gt;

&lt;p&gt;When a new version or patch of a software came out, we had to inform our customers that they could update their apps. &lt;strong&gt;They didn't always listen&lt;/strong&gt;. Even with some forms of auto-update, security risks still existed and legacy versions maintenance still had to be done. LTS, Release Candidates, patch, hotfixes, too much complicated stuff to handle for a poor user that just wanted to write a spreadsheet.&lt;br&gt;&lt;br&gt;
With a &lt;strong&gt;cloud-based approach&lt;/strong&gt; , by distributing your application as a &lt;em&gt;Software as a Service&lt;/em&gt;, you move all of that burden &lt;strong&gt;away from the user's machine&lt;/strong&gt;. Security updates and new versions can be deployed directly on your infrastructure and be immediately available to your users. Forget about updater and download links, users will have the latest versions without even noticing it.&lt;/p&gt;




&lt;h4&gt;
  
  
  But there are drawbacks too
&lt;/h4&gt;

&lt;p&gt;Of course nothing is perfect in our world, and so it is in the software world too.&lt;br&gt;&lt;br&gt;
By moving all the computation to a cloud infrastructure you are &lt;strong&gt;increasing the computational needs&lt;/strong&gt; on your side. Higher needs means higher costs and a more complicated backends, possibly fault tolerant and redundant so that your customers don't have to experience any downtime or data loss.&lt;/p&gt;




&lt;h4&gt;
  
  
  There is still a lot to do
&lt;/h4&gt;

&lt;p&gt;We'll get there someday. A world of shared, distributed computing with close-to-zero complexity for the end user, high abstraction for the developers and easy, standard platform maintenance for sysadmins.&lt;br&gt;&lt;br&gt;
We're not quite there yet, but with the right effort &lt;strong&gt;&lt;em&gt;Service Land&lt;/em&gt;&lt;/strong&gt; can become a reality in no time.&lt;/p&gt;







&lt;ol&gt;
&lt;li id="fn1"&gt;
&lt;p&gt;Well, we still had to rent a server on which to run OpenShift Origin. But if we used the &lt;a href="https://www.openshift.com/"&gt;commercial version&lt;/a&gt;, it would run on Red Hat's infrastructure. &lt;a href="https://matteojoliveau.com/from-product-makers-to-service-providers/#fnref1"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>development</category>
    </item>
  </channel>
</rss>
