<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by AlessandroMinoccheri on Medium]]></title>
        <description><![CDATA[Stories by AlessandroMinoccheri on Medium]]></description>
        <link>https://medium.com/@minompi?source=rss-21b9bb08545c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*PS-3NKyobTYhe4M7cIV9-w.jpeg</url>
            <title>Stories by AlessandroMinoccheri on Medium</title>
            <link>https://medium.com/@minompi?source=rss-21b9bb08545c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 28 May 2026 04:54:58 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@minompi/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Apache Kafka with Node.js]]></title>
            <link>https://minompi.medium.com/apache-kafka-with-node-js-310d26e6bc14?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/310d26e6bc14</guid>
            <category><![CDATA[message-queue]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[events]]></category>
            <category><![CDATA[kafka]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Thu, 16 Feb 2023 15:17:52 GMT</pubDate>
            <atom:updated>2023-02-16T16:27:20.737Z</atom:updated>
            <content:encoded><![CDATA[<p>Apache Kafka it’s a real-time data streaming technology created and open-sourced in 2011.<br>Kafka is a broker-based solution that operates by maintaining streams of data as records within a cluster of servers and it can handle billions of event streams per minute.</p><p>Before the arrival of event streaming systems like Apache Kafka and other Pub/Sub architecture, data processing was typically handled with periodic batch jobs that couldn’t be handled in real-time.<br>Instead,<strong> Apache Kafka has streams of events</strong>: they are created to capture the time value of data and create push-based applications that kick in whenever an interesting event occurs in real time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*svsP-KFUSLKbMz0jcgnMEg.jpeg" /></figure><p>Being purpose-built for real-time log streaming, Apache Kafka is ideal for applications that need to:<br>- Native support for data/message playback<br>- Ability to partition messaging workloads as application requirements change<br>- Real-time streaming for data processing<br>- Reliable data exchanges between different components</p><p>Nowadays there are a lot of applications that can take a lot of advantages using Apache Kafka, and now we can understand the basic concepts of this technology.<br><strong>Broker:</strong> It’s a single Kafka server that runs on the Java Virtual Machine.</p><p><strong>Cluster: </strong>It’s a group of brokers that work together, it can contain one or more brokers. Every broker in a cluster has a unique ID.</p><p><strong>Topics:</strong> They are the categories used to organize messages and each of them has a unique name across the entire Kafka cluster.<br>Topics are partitioned and replicated across brokers, using the partitions approach, which enables the parallelization of topics, enabling high message throughput.<br>Each partition has a specific offset and they are sliced into different segments<br>Every topic can have zero, one, or multiple consumers subscribing to that topic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/703/1*gmOeUvPj5jAmxIplr0131w.png" /></figure><p>(image from: <a href="https://www.javatpoint.com/kafka-topics">https://www.javatpoint.com/kafka-topics</a>)</p><p><strong>Producer:</strong> It’s an application that sends messages to a topic, those messages are distributed to partitions according to a mechanism such as key hashing.<br>A Kafka message consists of different elements:</p><ul><li><strong>Key:</strong> It is optional in the Kafka message and it can be null. A key may be a string, number, or any object and then the key is serialized into binary format.</li><li><strong>Value: </strong>represents the content of the message and can also be null. The value format is arbitrary and is then also serialized into binary format.</li><li><strong>Compression Type:</strong> The compression type can be specified as part of the message. Options are none, gzip, lz4, snappy, and zstd</li><li><strong>Headers:</strong> There can be a list of optional Kafka message headers in the form of key-value pairs. It is common to add headers to specify metadata about the message, especially for tracing.</li><li><strong>Partition + Offset:</strong> Once a message is sent into a Kafka topic, it receives a partition number and an offset id. The combination of topic+partition+offset uniquely identifies the message</li><li><strong>Timestamp:</strong> It is added by the user or the system in the message.</li></ul><p><strong>Consumer:</strong> It’s an application that reads data from the Kafka cluster via a topic, It reads the data within each partition in a specific order starting from 0 and increasing the offset number.</p><p><strong>Zookeeper:</strong> It’s a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.<br>It’s used to track cluster state, membership, and leadership</p><p>Now, these are the main concepts (there are a lot more) but now it’s time to see a little bit of code, creating topics, sending messages, and reading them.</p><h3>Create a basic application</h3><p>The first thing to do is to create a local environment with Docker, obviously that you can use <a href="https://www.confluent.io/confluent-cloud/?utm_medium=sem&amp;utm_source=google&amp;utm_campaign=ch.sem_br.nonbrand_tp.prs_tgt.kafka_mt.xct_rgn.emea_lng.eng_dv.all_con.kafka-cloud&amp;utm_term=apache%20kafka%20cloud&amp;creative=&amp;device=c&amp;placement=&amp;gclid=Cj0KCQiAxbefBhDfARIsAL4XLRr0lxhKaGKCcOVyachZWf6npk7-MkxcAYdSruFBnmN3Bj6cCldeRsEaAmG5EALw_wcB">Confluent Cloud</a> which is perfect for most of your use cases. But for this example, I preferred to use a local docker.</p><p><em>docker-compose.yml</em></p><pre>version: ‘3’<br>services:<br>  zookeeper:<br>    image: wurstmeister/zookeeper<br>    container_name: zookeeper<br>    ports:<br>      - &quot;2181:2181&quot;<br>  kafka:<br>    image: wurstmeister/kafka<br>    container_name: kafka<br>    ports:<br>      - &quot;9092:9092&quot;<br>    environment:<br>      KAFKA_ADVERTISED_HOST_NAME: localhost<br>      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 </pre><p>To run the application you can launch this command:</p><pre>docker-compose up -d</pre><p>I have used the standard port for each service, now we can try to create our NodeJS app by installing a useful library: <a href="https://kafka.js.org/">kafkajs</a></p><pre>npm install kafkajs</pre><p>After that, you can create a file called topic.js to create your topics</p><pre>import {Kafka} from ‘kafkajs’</pre><pre>run();<br>async function run() {<br>  try {<br>    const kafka = new Kafka({<br>      “clientId”: “myapp”,<br>      “brokers”: [“localhost:9092”]<br>    })</pre><pre>    const admin = kafka.admin();<br>    await admin.connect();</pre><pre>    await admin.createTopics({<br>      “topics”: [{<br>        “topic”: “Users”,<br>        “numPartitions”: 2<br>      }]<br>     })<br>     console.log(“Created succesfully”);</pre><pre>     admin.disconnect();<br>     } catch(ex) {<br>       console.error(`Something bad happended ${ex}`)<br>     } finally{<br>       process.exit(0);<br>    }<br> }</pre><p>In this file, you are connecting to the local Kafka creating a topic &quot;Users&quot; with two partitions, one from the first letter starting with a-m, and the second from n-z.<br>To create a topic you can launch:</p><pre>node topic.js</pre><p>Now we can send a message into the topic created previously, to do it, you can create a file called producer.js like this:</p><pre>import {Kafka} from ‘kafkajs’<br>const msg = process.argv[2];<br>run();<br>async function run() {<br>  try {<br>    const kafka = new Kafka({<br>      “clientId”: “myapp”,<br>      “brokers”: [“localhost:9092”]<br>     })<br>     const producer = kafka.producer();<br>     await producer.connect();<br>     const partition = msg[0] &lt; “N” ? 0 : 1;<br>     const result = await producer.send({<br>       “topic”: “Users”,<br>       “messages”: [<br>        { <br>          “value”: msg,<br>          “partition”: partition<br>        }<br>        ]<br>     })<br>     console.log(`Send succesfully! ${JSON.stringify(result)}`);<br>     producer.disconnect();<br>   } catch(ex) {<br>      console.error(`Something bad happended ${ex}`)<br>   } finally{<br>     process.exit(0);<br>   }<br> }</pre><p>In this file, we are connecting again to Kafka and we take from the CLI command the message argument passed. With that argument, we try to understand in which partition we can send the message and after that, we can send it passing the name of the topic and the message with the value and the partition.</p><p>You can send a message from your CLI in this way:</p><pre>node producer.js test-message</pre><p>Now we can consume the message with a consumer.<br>You can create a file called consumer.js with the following code:</p><pre>import {Kafka} from ‘kafkajs’<br>run();<br>async function run() {<br>  try {<br>    const kafka = new Kafka({<br>      “clientId”: “myapp”,<br>      “brokers”: [“localhost:9092”]<br>    })<br>    const consumer = kafka.consumer({“groupId”: “test”});<br>    await consumer.connect();<br>    await consumer.subscribe({<br>      “topic”: “Users”,<br>      “fromBeginning”: true<br>    })<br>    await consumer.run({<br>       “eachMessage”: async result =&gt; {<br>          console.log(`Received message ${result.message.value} on partition ${result.partition}`)<br>       }<br>    })<br>  } catch(ex) {<br>     console.error(`Something bad happended ${ex}`)<br>  } finally{<br> }<br>}</pre><p>In this file, we are connecting to Kafka and we are reading from the beginning the topic &quot;Users&quot; from each partition.<br>To read messages you can launch this command:</p><pre>node consumer.js</pre><p>Here is an example of a message created and read!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Td6RrdGJlI2Xl9o5wvYKgg.jpeg" /></figure><p>Now you can add another consumer attached to the same topic, if you do it, you are parallelizing the way you are reading messages because a consumer read from one partition and the other one from the other partition.<br>A consumer can consume from multiple partitions, but a partition can be consumed by only one consumer, this is a concept of the <strong>Consumer group</strong>!</p><p>So, this can be your first application using Apache Kafka locally, it’s very simple and basic.<br>There are a lot of concepts about Kafka and more and more things to know and understand but with this simple example, you are seeing the basic concept of Kafka!</p><h3>Pros and Cons</h3><p>But what are the pros and cons of this architecture?<br><strong>Pros:</strong><br>- High performance<br>- Distributed system<br>- Event Driven, Kafka can be a Pub Sub system and a queue system<br>- Scalability<br>- Parallel Processing</p><p><strong>Cons:</strong><br>- The producer needs to explicit the correct partition to write and it can be a problem<br>- It’s complex to install configure and manage</p><p><strong>There are a lot of advantages and use cases where you can apply Kafka, it&#39;s an outstanding architecture with a lot of useful components to solve your problems!</strong></p><p>You can find the code of this article example in this repository: <a href="https://github.com/AlessandroMinoccheri/apache-kafka-basic">https://github.com/AlessandroMinoccheri/apache-kafka-basic</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=310d26e6bc14" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[8 Code reviews tips and tricks]]></title>
            <link>https://minompi.medium.com/8-code-reviews-tips-and-tricks-d5791fd4fefe?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/d5791fd4fefe</guid>
            <category><![CDATA[empathy]]></category>
            <category><![CDATA[collaboration]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[team]]></category>
            <category><![CDATA[code-review]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Tue, 30 Aug 2022 06:19:29 GMT</pubDate>
            <atom:updated>2022-08-30T06:33:35.973Z</atom:updated>
            <content:encoded><![CDATA[<p>Code reviews are a largely accepted best practice for software development teams. There are a lot of benefits to using them and there is always something to learn as a reviewer. But adopting from zero code reviews isn’t so easy and immediate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1013/1*fTjEhhV3IQH0vMEvrai71A.jpeg" /><figcaption>Image from iStock</figcaption></figure><p>It’s important to share why they are so important for a team and what are their <strong>goals</strong>:</p><ul><li><strong>Quality control:</strong> code reviews can increase the quality because we can find new solutions and improvements</li><li><strong>Sharing knowledge:</strong> It’s easy to end up in a situation where one developer deals with a certain part of the codebase because they’re most familiar with it. in short-period seems a win but it’s not for the future. When ownership is shared, teams become more motivated and autonomous.</li><li><strong>Increasing developer&#39;s knowledge:</strong> we can learn through code reviews, by asking questions about a piece of code that we don’t understand, or by sharing a different method to solve the problem</li></ul><p>So after sharing why code reviews are so important it’s time to understand what are some tips and tricks for using them correctly and take advantage of them.</p><h3>1 Keep Pull requests small</h3><p>Keeping the Pull requests <strong>smaller as possible</strong> allows for the easiest review and, usually, more contribution and focus on it. <br>If you create a bug pull request with 120 files changed, 12000 lines added and 3500 lines removed it’s very difficult to find problems or better solutions. It’s totally a waste of time reviewing such a big pull request and it takes too many hours for doing it. <br>For that reason, it’s better to split the pull request into different pull requests with a specific code review.</p><p>A <a href="http://smartbear.com/resources/case-studies/cisco-systems-collaborator/">SmartBear study of a Cisco Systems programming team</a> revealed that <strong>developers should review no more than 200 to 400 lines of code</strong> (LOC) at a time because the brain can only effectively process so much information at a time; beyond 400 LOC, the ability to find bugs, defects diminishes.</p><p>In practice, a review of 200–400 LOC over 60 to 90 minutes should yield 70–<strong>90% defect discovery.</strong> So, if 10 defects existed in the code, a properly conducted review would find between 7 and 9 of them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/658/1*hVvPK3s5lahatLY5DRUaiw.jpeg" /></figure><h3>2 Don’t review for more than 1 hour</h3><p>Usually, it’s not a best practice to review code too quickly, on the other side you shouldn’t review for too long because performance starts to decrease after about 1 hour. <br>Our brain needs a break to refresh to have good performance and to review well the code. <br>It’s important to keep the focus on the review to discover and understand every single part of the pull request. <br><strong>Doing a superficial review it’s not a good practice and decreases the credibility of the process for the whole team</strong>.</p><h3>3 Add a clear description</h3><p>To help reviewers to do their job it’s important to add a description to the pull request to share:</p><ul><li>which problem are you trying to solve</li><li>why did you choose that solution</li><li>doubts about something</li><li>question about the implementation</li><li>…</li></ul><p>It’s also important to <strong>add a clear description</strong> for the future, for example, after some months you would like to understand why that piece of code was added. There are a lot of benefits to adding a clear description!</p><h3>4 Use Pull Request template</h3><p>Many tools, like <strong>GitHub</strong>, provide a template to create Pull Requests, in this way you have a standard and it’s easier to create a new one and review it. If you want to add the template. <br>GitHub you need to create a new file .github/pull_request_template.md</p><p><strong>Github Documentation</strong>: <a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository">https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository</a></p><p>Using a template allows the team to create a standard pull request to help each member of the team.</p><h3>5 Number of reviewers</h3><p>What is the correct number of accepted reviews to merge a pull request? There isn’t a specific rule again but it’s important to decide it in the team and try to understand what is the correct number. <br>Usually, you don’t need that every member of the team accepts the pull request, except for some critical features. <br>Sometimes one or two accepted reviews are good enough to merge the pull request. <br>Why not everyone? <br>Because you can create a bottleneck and your deployment can be blocked by some reviewer that didn’t see it already for other reasons.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*7m2DQhgndMyZPPbdS0Vu-w.jpeg" /></figure><h3>6 Empathy</h3><p>Empathy is an important skill during the review. <br>As a reviewer, you need to understand what the author is trying to solve, what was his thought, and why it’s implemented in this way. <br>You need to<strong> be kind</strong> when you comment on the pull request without being rude. <br>Don’t try to give a new solution, instead ask questions about the implementation like: “Is this the only way to solve the problem?” “It seems a little bit coupled with this code, what do you think? Is there a better way?”</p><p>If you liked a piece of code or you learn a new thing write a comment like: “this is perfect, I never thought about it” or “I didn’t know about this function! Amazing, it seems very useful!” <br>Try to <strong>foster a positive code review culture!</strong></p><h3>7 Delegate static analysis</h3><p>Using a tool to automate static analysis checks it’s important because during reviews you need to focus on behaviors, business logic, and patterns you don’t have to focus on spaces, missing commas, or things that the static analysis tool can check. <br><strong>All the automatable static analysis checks should be delegated</strong> to these tools during a CD/CI process. <br>This delegation can save you a lot of time and allows the team to focus on the business logic and the high-level approach to the implementation.</p><h3>8 Run a retrospective</h3><p>After a month or two of reviews it’s important to understand if the process is good or not and how can you improve it. <br>To do it I can suggest running a retrospective to understand it. <br>It’s important to find an external facilitator so all the team can discuss together what was good and what was not. <br>There is a lot of different type of retrospectives and the facilitator can use one of them. <br>Every month or two it’s important to run the retrospective, especially in the early stage of the adoption process, to improve it and create a feedback process for all the team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U1VSpPxRPzb9OhukhR0FYQ.png" /></figure><h3>Conclusion</h3><p>Code reviews are a fantastic tool but you need to know how to manage them to get all the benefits.<br>There is always something to learn and improve in this process to discover with your team and discuss it.<br>I enjoy creating pull requests and reviewing the code of others, I always learn something and understand other points of view.<br>Never stop learning.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d5791fd4fefe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Add images to a React project with Typescript]]></title>
            <link>https://minompi.medium.com/add-images-to-a-react-project-with-typescript-2338c28bf5d9?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/2338c28bf5d9</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[webpack]]></category>
            <category><![CDATA[modules]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Fri, 22 Jul 2022 09:16:10 GMT</pubDate>
            <atom:updated>2022-07-22T09:18:44.771Z</atom:updated>
            <content:encoded><![CDATA[<p>In every single project, usually, you need to add an image to your React project to show something or to represent a graph and create a beautiful page for your audience.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Gh4eaAQU432ZQH7qsVbJ_A.png" /></figure><p>Adding an image with React is very simple and fast, this is an example:</p><pre>import React from &quot;react&quot;;<br>import imageToAdd from &quot;./../assets/images/logo.png&quot;;<br>function YourComponent() {<br>   return &lt;img src={imageToAdd} alt=&quot;Image&quot; /&gt;;<br>}<br>export default YourComponent;</pre><p>This works like a charm in a React project built using <a href="https://create-react-app.dev/">CRA</a> or <a href="https://vitejs.dev/">Vite</a>.<br> but if your project has a custom bundler, created using <strong>Typescript</strong> + <strong>Webpack</strong>, with the code above you will receive this error:</p><pre>Cannot find module  &#39;./../assets/images/logo.png&#39;</pre><p>The first time I saw that error, I thought “It’s a bug!”, but after searching and understanding typescript well, I discovered that receiving an error is the correct behavior.</p><p>By default in typescript, the <a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html"><strong><em>module resolution</em></strong></a> resolves the import using only the files with extension: <em>.ts</em> <em>.tsx</em> or <em>.d.ts</em> and this is the reason why in the previous case the module couldn&#39;t be found.</p><p>So, how can we fix the problem?<br>To solve the problem, usually, you have to:</p><p><em>1. add a directory called </em><em>types on your project&#39;s root</em></p><p><em>2. create inside of that folder a file called </em><em>index.d.ts with the following content</em></p><pre>declare module &quot;*.jpg&quot;;<br>declare module &quot;*.png&quot;;</pre><p><em>N.B. the extension depends on the file type you are adding.</em></p><p><em>3. install the </em><em>file-loader dependence using </em><em>npm, </em><em>yarn or </em><em>pnpm</em></p><pre>npm install --save-dev file-loader</pre><p><em>4. update your webpack config file to use the </em><em>file-loader module like this</em></p><pre>...<br>{ test: /\\.(png|jp(e*)g|svg|gif)$/, use: [&#39;file-loader&#39;], }<br>...</pre><p>Then, you can run your application, your build will succeed and your image will appear! 🎩</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*fERuNYOYofhptxfy3AAeSA.jpeg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2338c28bf5d9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Server-Sent events with PHP and Symfony]]></title>
            <link>https://minompi.medium.com/server-sent-events-with-php-and-symfony-5d6596cc84c8?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/5d6596cc84c8</guid>
            <category><![CDATA[symfony]]></category>
            <category><![CDATA[events]]></category>
            <category><![CDATA[server-sent-events]]></category>
            <category><![CDATA[mercure]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Wed, 25 May 2022 09:20:19 GMT</pubDate>
            <atom:updated>2022-06-17T11:12:46.587Z</atom:updated>
            <content:encoded><![CDATA[<p>In the magic world of <strong>PHP</strong>, there is a library for many things that you don’t know, every day new libraries are born and it’s impossible to know each of them.<br>For this reason, I try always to follow on <strong>Twitter</strong>, <strong>LinkedIn</strong>, and <strong>GitHub</strong> good developers that are sharing new approaches and libraries.<br>For one of our customers, we needed an application where the server can send data to all clients.<br>So we need to build the software with a <strong>Server-Sent events approach</strong> in a short time to release the product as soon as possible to validate the customer idea.</p><p>If you would like more about Server-Sent events, what it means, advantages and limits, you can read my previous article <a href="https://dev.to/minompi/websocket-vs-server-sent-events-2b77">here</a>.</p><p>To realize a Server-Sent Events in PHP we found a Symfony library <a href="https://github.com/symfony/mercure">symfony/mercure</a>, I saw this library in some article on LinkedIn and it’s the proof that following the right people can be very important.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E7Sz8Szuj-KJTpo08C_ErQ.png" /></figure><h3>How to install it</h3><p>We can use Flex to install it so, you can write into your CLI::</p><pre>composer require mercure</pre><p>After that, you can configure Mercure environment variables into the file: config/packages/mercure.yaml</p><pre>mercure:<br>  hubs:<br>    default:<br>      url: <a href="https://mercure-hub.example.com/.well-known/mercure">https://mercure-hub.example.com/.well-known/mercure</a><br>      jwt:<br>        secret: &#39;!ChangeMe!&#39;<br>        publish: [&#39;foo&#39;, &#39;<a href="https://example.com/foo&#39;">https://example.com/foo</a>&#39;]<br>        subscribe: [&#39;bar&#39;, &#39;<a href="https://example.com/bar&#39;">https://example.com/bar</a>&#39;]<br>        algorithm: &#39;hmac.sha256&#39;<br>        provider: &#39;My\Provider&#39;<br>        factory: &#39;My\Factory&#39;<br>        value: &#39;my.jwt&#39;</pre><p>Let me explain what are the values to set into the configuration file:</p><p><strong>secret</strong>: the key to use to sign the JWT (all other options, besides algorithm, subscribe, and publish will be ignored)<br><strong>publish</strong>: a list of topics to allow publishing when generating the JWT (only usable when secret or factory are provided)<br><strong>subscribe</strong>: a list of topics to allow subscribing to when generating the JWT (only usable when secret, or factory are provided)<br><strong>algorithm</strong>: The algorithm to use to sign the JWT (only usable when the secret is provided)<br><strong>provider</strong>: The ID of service to call to provide the JWT (all other options will be ignored)<br><strong>factory</strong>: The ID of service to call to create the JWT (all other options, besides subscribe, and publish will be ignored)<br><strong>value</strong>: the raw JWT to use (all other options will be ignored)</p><p>Automatically inside your .env will be updated with environment variables.</p><p>If you are using a Symfony version less than 6, the YAML file doesn’t exist and you need only to configure your environment variables into the .env file like this:</p><pre>MERCURE_URL=<a href="http://localhost:9090/.well-known/mercure">http://localhost:9090/.well-known/mercure</a><br>MERCURE_PUBLIC_URL=<a href="http://localhost:9090/.well-known/mercure">http://localhost:9090/.well-known/mercure</a><br>MERCURE_JWT_SECRET=”JWT-AuctionEngine”</pre><h3>Using a specific Docker container</h3><p>You can use an official docker for your local environment, with a simple configuration like this:</p><pre>version: &quot;3.5&quot;</pre><pre>services:<br>  mercure:<br>    container_name: mercure_sse_poc<br>    image: dunglas/mercure<br>    environment:<br>      SERVER_NAME: &#39;:80&#39;<br>      MERCURE_PUBLISHER_JWT_KEY: &#39;JWT-AuctionEngine&#39;<br>      MERCURE_SUBSCRIBER_JWT_KEY: &#39;JWT-AuctionEngine&#39;<br>      MERCURE_CORS_ALLOWED_ORIGINS: &#39;*&#39;<br>      MERCURE_EXTRA_DIRECTIVES: |-<br>      cors_origins &quot;*&quot;<br>      anonymous 1<br>    ports:<br>      — &quot;9090:80&quot;<br>      — &quot;4433:443&quot;</pre><p><strong>JWT_KEY</strong> must be the same as your environment variables, in this little example, I declare that it’s not necessary to be authenticated and you can use Mercure from all domains.<br><em>In production, I recommend restricting those parameters to avoid undesired problems.</em></p><h3>How to use Symfony/Mercure</h3><p>To send data to your client you need to instantiate a Mercure object called <strong>Update</strong> with 2 arguments: the topic name where you want to send your data, and the data encoded.<br>After that, you can publish your event using an object that implements HubInterface (for this example).<br>But symfony/mercure has already its implementation so you can use it without writing your implementation.<br>Here is a little example:</p><pre>public function send(Request $request, HubInterface $hub): void<br>{<br>    $update = new Update(<br>       &#39;channelname&#39;,<br>       json_encode([<br>           &#39;foo&#39; =&gt; &#39;bar&#39;<br>       ], JSON_THROW_ON_ERROR)<br>    );<br>    $hub-&gt;publish($update);<br>}</pre><p>The object Update has different arguments (directly from <a href="https://mercure.rocks/spec">https://mercure.rocks/spec</a>):</p><p><strong>topic</strong>: The identifiers of the updated topic. It is RECOMMENDED to use an IRI as an identifier. If this name is present several times, the first occurrence is considered to be the canonical IRI of the topic, and other ones are considered to be alternate IRIs. The hub MUST dispatch this update to subscribers that are subscribed to both canonical or alternate IRIs.<br><strong>data (optional)</strong>: the content of the new version of this topic.<br><strong>private (optional):</strong> if this name is set, the update MUST NOT be dispatched to subscribers not authorized to receive it. See authorization. It is recommended to set the value to on but it CAN contain any value including an empty string.<br><strong>id (optional):</strong> the topic’s revision identifier: it will be used as the SSE’s id property. The provided id MUST NOT start with the # character. The provided id SHOULD be a valid IRI. If omitted, the hub MUST generate a valid IRI (RFC3987). A UUID (RFC4122) or a DID MAY be used. Alternatively, the hub MAY generate a relative URI composed of a fragment (starting with #). This is convenient to return an offset or a sequence that is unique for this hub. Even if provided, the hub MAY ignore the id provided by the client and generate its id.<br><strong>type (optional): </strong>the SSE’s event property (a specific event type).<br><strong>retry (optional):</strong> the SSE’s retry property (the reconnection time).</p><h3>Frontend</h3><p>The frontend client needs to subscribe to the topic, the following example is a piece of a React component:</p><pre>const url = &#39;<a href="http://127.0.0.1:9090/.well-known/mercure?topic=auctions-1`">http://127.0.0.1:9090/.well-known/mercure?topic=auctions-1</a>&#39;;<br>const eventSource = new EventSource(url);</pre><pre>eventSource.onmessage = event =&gt; {<br>  const results = JSON.parse(event.data);<br>  console.log(results);<br>}</pre><p>You can use this code for example in a <strong>UseEffect</strong> function of <strong>React</strong> and you are telling that you want to subscribe to the topic auctions-1 and every event sent to that channel you will print it into the console to see what you have received and you can use those data for whatever you want.</p><h3>What happens?</h3><p>I have written a little example here to understand well what happens: <a href="https://github.com/AlessandroMinoccheri/sse-poc">https://github.com/AlessandroMinoccheri/sse-poc</a><br>Now if you clone the repository and follow the instructions to install the backend and frontend you can visit the page: <a href="http://localhost:8080/">http://localhost:8080/</a><br>You can see a simple form to submit a bid offer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/521/1*EjhRNwVbA7xURsQv3eSy-A.png" /></figure><p>Now, if you open the browser network, select Fetch/XHR (for Chrome), and reload the page you can see a subscription request to a specific topic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SCr03xPU8M1P9sr8KLSq5A.png" /></figure><p>Then, if you insert a number into the text field and click the button to make a bid, you can see in the network tab a new POST request for the bid, but inside the previous request in the tab Events, you can see a new event sent by the server with new information!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/567/1*9IQWIX9vqnOutq_aoDuncw.png" /></figure><p>So in the same subscription request, we can receive events for the server, for this reason, the Server-Sent events approach is considered a monodirectional communication because is the server that sends data to the client, and the client decides only to subscribe to topics.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u4A0xUxn7RXwKUqRtqTLIw.png" /></figure><p>If you make other bids you can see in the tab events all data sent from the server in the same HTPP connection.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*AfTT8Nc0niKjR5FEE5tehw.png" /></figure><h3>Subscribe to multiple topics</h3><p>Is it possible for the client to subscribe to multiple topics? Yes, absolutely, but how? <br>Well, you can easily do this thing into your frontend app (in this example using React):</p><pre>const url = &#39;<a href="http://127.0.0.1:9090/.well-known/mercure?topic=auctions-1`">http://127.0.0.1:9090/.well-known/mercure?topic=auctions-1</a>&#39;;<br>const eventSource = new EventSource(url);</pre><pre>eventSource.onmessage = event =&gt; {<br>  const results = JSON.parse(event.data);<br>  console.log(results);<br>}</pre><pre>const anotherUrl = &#39;<a href="http://127.0.0.1:9090/.well-known/mercure?topic=anotherTopic`">http://127.0.0.1:9090/.well-known/mercure?topic=anotherTopic</a>&#39;;<br>const anotherEventSource = new EventSource(anotherUrl);</pre><pre>anotherEventSource.onmessage = event =&gt; {<br>  const results = JSON.parse(event.data);<br>  console.log(results);<br>}</pre><p>You can subscribe to many topics in this way because the server will send data to a specific topic.<br>You can use this approach to create a private topic for a single user, or group of users to send events only to them.</p><h3>Asynchronous dispatching</h3><p>You can write your implementation to dispatch asynchronous events, but this is not recommended because <strong>Mercure</strong> already sends them asynchronously.<br>But if you want, you can use <strong>Symfony Messenger</strong> to dispatch it by yourself.<br>Let’s see how the previous example could be with your own implementation:</p><pre>public function send(Request $request, MessageBusInterface $customBus): void<br>{<br>   $update = new Update(<br>      &#39;channelname&#39;,<br>      json_encode([<br>          &#39;foo&#39; =&gt; &#39;bar&#39;<br>      ], JSON_THROW_ON_ERROR)<br>   );<br>   $customBus-&gt;publish($update);<br>}</pre><p>As you can see the code doesn’t change, you can use a different implementation.<br>But remember that <strong>Mercure already sends events asynchronously</strong> so it depends on you if you want to maintain by yourself the dispatching system.</p><h3>Use Case Examples</h3><p>There are many examples of using the Server-Sent events approach.<br>Imagine that you need to build a stock option client, the frontend application can subscribe to topics to receive data from the server only when a stock quote changes its value.<br>Or if you need to build a Twitter feed update, the server will send data when to every user (with a custom topic each) with new tweets.<br>Recently I built a push notification system where clients receive information and updates from the server like the common push notifications app on your phone.</p><h3>Conclusions</h3><p>There are a lot of useful resources and examples, in my opinion using symfony/mercure library has simplified my life because in some minutes you can create a system ready to send events to the client without a lot of configurations and code to do.<br>Using the right tool can be important to the success of the project, but to know it you don’t have to start from the implementation.</p><p>Start understanding what is the real problem to solve, I usually do an <strong>EventStorming </strong>before coding because we need to know the domain and business logic.</p><p>After that, you can understand better if Server-Sent Events is the right approach or not.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5d6596cc84c8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[WebSocket vs Server-Sent events]]></title>
            <link>https://minompi.medium.com/websocket-vs-server-sent-events-67c73d07b90f?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/67c73d07b90f</guid>
            <category><![CDATA[decision-making]]></category>
            <category><![CDATA[cognitive-bias]]></category>
            <category><![CDATA[server-sent-events]]></category>
            <category><![CDATA[websocket]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Fri, 29 Apr 2022 08:07:26 GMT</pubDate>
            <atom:updated>2022-04-30T05:37:57.731Z</atom:updated>
            <content:encoded><![CDATA[<p>Usually, I have heard more times the term <strong>WebSocket</strong> than <strong>server-sent events.</strong></p><p>The reason could be that <strong>WebSocket is used more</strong>, but not always is the ideal approach.<br>Sometimes Server-sent events approach is better to solve problems and create good applications.</p><p>It’s very important to understand differences, limits, and ideal cases for both to solve your problem with the right solution.<br>Sometimes we have a cognitive bias that doesn’t allow us to take the right decision.<br><strong>Cognitive bias</strong> is a systematic error in thinking that occurs when people are processing and interpreting information in the world around them and affects the decisions and judgments that they make.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Agap4Upvp4UoSb6ODSU9Og.png" /></figure><p><em>(Image from </em><a href="https://uxdesign.cc/how-to-improve-experience-design-by-managing-cognitive-biases-d7b360d35b0a"><em>https://uxdesign.cc/how-to-improve-experience-design-by-managing-cognitive-biases-d7b360d35b0a</em></a><em>)</em></p><p>So, for example, if we have solved a problem using WebSocket, next time with a similar problem we could think that, again, it’s the right approach without considering the big picture, all information about the problem to solve.<br>For that reason, understanding deeply bot approaches can help us to reduce the cognitive bias and make the best decision.</p><p>Let’s try to explain both approaches and their characteristics.</p><h3>Websocket</h3><p>It’s a computer communications protocol, that provides full-duplex communication channels over a single TCP connection (Wikipedia). The protocol was standardized in 2011.</p><p>The WebSocket approach is used in many contexts and projects because has many benefits and pros in its favor.</p><h4>Bidirectional communication</h4><p>The client and server can both send data to the other part.<br>The client creates a TCP connection to the server and keeps it open as long as needed. <br>Both server and client can close the connection easily whenever they want.<br>To exchange data there is a <strong>handshake process</strong> that verifies the communication, and if it’s all ok, they can exchange data using the custom WebSocket protocol.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/847/1*d_oB1Vst-wjJ6snOrUvuaQ.jpeg" /></figure><p><em>(Image from: </em><a href="https://www.onlyfullstack.com/polling-vs-server-sent-events-vs-websocket/"><em>https://www.onlyfullstack.com/polling-vs-server-sent-events-vs-websocket/</em></a><em>)</em></p><h4>Advantages</h4><p>- Bidirectional communication in real-time, connections can both send and receive data from the browser(example: chat).<br>- Generally don’t use XmlHttpRequest and headers are not sent every time, so it reduces the expensive data loads being sent to the server.<br>- Can transmit both binary data and UTF-8 format.</p><h4>Limits</h4><p>- When connections are terminated, WebSocket doesn’t automatically recover them, you need to implement a reconnection system by yourself.<br>- Browsers older than 2011 don’t support WebSocket connections.<br>- Some enterprise firewalls with packet inspection have trouble dealing with WebSocket.<br>- It cannot be placed behind container-based authentication methods with header-based security, it has to be query parameters (or hopefully, a token-based authentication where the token is established outside the WebSocket path).</p><h4>Ideal cases</h4><p>- Chat: both client and server exchange data to send and receive messages<br>- Multiplayer games<br>- Collaborative editing/coding<br>- Social feeds<br>- Sport updates<br>- … a lot more …</p><h3>Server-Sent Events</h3><p>It’s a server push technology enabling a client to receive automatic updates from a server via an HTTP connection. <br>It was born on September 1, 2006, so it’s been a while since it’s available.<br>It provides a memory-efficient implementation of XHR streaming. <br>Unlike a raw XHR connection, which buffers the full received response until the connection is dropped, an SSE connection can discard processed messages without accumulating all of them in memory.</p><h4>Monodirectional communication</h4><p>The client sends a request to subscribe to a specific channel and the server will send event/data into that request, so only the server can send data and the client receive automatically those events in the same HTTP connection.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/777/1*Ug-BosrJefTOOEBmtA2H4Q.jpeg" /></figure><p><em>(Image from: </em><a href="https://www.onlyfullstack.com/polling-vs-server-sent-events-vs-websocket/"><em>https://www.onlyfullstack.com/polling-vs-server-sent-events-vs-websocket/</em></a><em>)</em></p><h4>Advantages</h4><p>- Transported over simple HTTP instead of a custom protocol<br>- Simpler protocol<br>- Built-in support for re-connection and event-id<br>- No troubles with corporate firewalls doing packet inspection</p><h4>Limits</h4><p>- It’s limited to UTF-8 and does not support binary data.<br>- When not used over HTTP/2, Server-Sent events approach is subject to limitations with regard to the maximum number of open connections. This can be especially painful when opening various tabs as the limit is per browser and set to a very low number (6).<br>- It’s mono-directional<br>- It doesn’t have native browser support. However, there are available workaround with poly-fill (replicate an API) in Javascript that simulates the SSE functionality to solve this issue. All modern browsers support server-sent events: Firefox 6+, Google Chrome 6+, Opera 11.5+, Safari 5+, Microsoft Edge 79+.</p><h4>Ideal cases</h4><p>- Stock client updates: the client receives updates from the server when a stock changes its value<br>- Twitter feed updates: the client receives a new tweet every time one is sent<br>- push notifications</p><h3>Conclusion</h3><p>In conclusion, <strong>both approaches are valid</strong> and can be used to build specific software.<br>Websocket is more used and can be used also to develop an application that can use Server-sent events.<br>Server-sent Events have fewer ideal cases but for them, it’s very useful with less configuration and less time to create the updating system.</p><p>I have used both of them and no one is better than another, it depends on the specific context and what you need at that moment.</p><p>Knowing WebSocket and Server-sent events can help you in deciding which approach is better for every application.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=67c73d07b90f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to test Github Actions locally]]></title>
            <link>https://minompi.medium.com/how-to-test-github-actions-locally-5a6dad8da367?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a6dad8da367</guid>
            <category><![CDATA[test]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[act]]></category>
            <category><![CDATA[github-actions]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Mon, 07 Mar 2022 13:26:41 GMT</pubDate>
            <atom:updated>2022-03-07T13:36:57.690Z</atom:updated>
            <content:encoded><![CDATA[<p>One of the first things that I do in a project is to create a <strong>CD/CI</strong> process using <strong>Github Actions</strong> usually.<br>Why?<br>Because I would like to deploy as soon as possible with a process that launches tests for me automatically to understand if I can merge the feature and deploy it.<br>Nowadays Github Actions has a lot of integrations, tools, and containers to run your application.<br>But every time you create a Github Actions you need to test it and usually, you try to commit something to trigger it, you are testing manually your CD/CI.<br>For me it’s like testing my application manually, clicking buttons instead of automatic tests.</p><p>For this reason for me, it’s important to test my Github Actions without committing something because it’s not necessary.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*7Z5NDciyXIzGK791LriXrQ.png" /></figure><p><em>Photo by </em><a href="https://www.giuseppemaccario.com/it/continuous-deployment-con-github-actions-su-server-condiviso/"><em>https://www.giuseppemaccario.com/it/wp-content/uploads/2021/10/Continuous-Deployment-con-GitHub-Actions.png</em></a></p><p>I found this library perfect for testing Github Actions: <a href="https://github.com/nektos/act"><strong>act</strong></a>.</p><p>This library is very useful and easy to use, you can run locally your Github Actions and you have fast feedback on your workflows.</p><h3>How does it work?</h3><p>Act simulates the actions we would like to perform in the container of our Github Actions.<br>It creates a container capable of performing all the steps by properly simulating all the steps.<br>So we can see all the steps of the Github Actions and their results through simple instruction.</p><h3>Installation</h3><p>If you are using Homebrew (Linux, macOS) you can launch this command from your CLI:</p><pre>brew install act</pre><p>If you are not using Homebrew I recommend checking the Installation section inside the README file of the project because there are many ways and options to add it.</p><h3>How to use it</h3><p>To run the tool you need to write into your CLI:</p><pre>act</pre><p>This command runs the default (`push`) event.<br>When you run for the first time act, it will ask you to choose an image to be used as default and it will save that information inside the file ~/.actrc that contains configuration flags.</p><p>If you want to run a specific event you can launch:</p><pre>act pull_request</pre><p>For the specific event, I mean Github Events: <a href="https://docs.github.com/en/developers/webhooks-and-events/events/github-event-types">https://docs.github.com/en/developers/webhooks-and-events/events/github-event-types</a></p><p>To run a specific job you can launch:</p><pre>act -j your_job</pre><p>You can also launch command in dry mode like this:</p><pre>act -n</pre><h3>Environment variables and Secret variables</h3><p>Secrets and environment variables saved in GitHub can’t be used by act, but you can pass them and define them locally.</p><h4>Secrets</h4><pre>act -s KEY=VALUE — To pass secret from CLI<br>act — secret-file my.secrets — load secrets values from local.secrets file.</pre><h4>Environment variables</h4><pre>act -n KEY=VALUE — To pass environment variable from CLI<br>act — env-file my.env — load environment variables from local.env file.</pre><h3>Use Case</h3><p>I have used act many times in these months because I created many Github actions for my projects.<br>Every time that I change something I tried the action with <strong>act</strong>.</p><p>So, for me, it’s better to test it locally to save a lot of time.<br>The process could be:<br>- create your first Github Actions<br>- launch act to test changes<br>- improve or fix your Github Actions<br>- launch act to test changes</p><p>And then you can iterate until you are satisfied with your Github Action.</p><h4>Example</h4><p>I have created a simple example to test act and you can find it following this link: <a href="https://github.com/AlessandroMinoccheri/act-example">https://github.com/AlessandroMinoccheri/act-example</a></p><p>It’s a simple example to test act and it took me 2 minutes to install and launch <strong>act</strong>.<br>It’s very useful to see the output of your GitHub Actions to understand if it’s all ok or not.</p><h3>Limit</h3><p>There are a few limitations by using act (<a href="https://github.com/nektos/act#known-issues">https://github.com/nektos/act#known-issues</a>):<br>- Non-Linux Runners: act can works for Linux runners, not for the others, but it’s a Docker limitation on your workstation.<br>You can work around this by setting <strong>DOCKER_HOST</strong> before running act, with e.g:</p><pre>export DOCKER_HOST=$(docker context inspect — format ‘{{.Endpoints.docker.Host}}’)</pre><p>- Default images do not contain intentionally all the tools that GitHub Actions offers by default in their runners.</p><h3>Conclusion</h3><p>In my opinion, <strong>act can save you a lot of time to test your Github Actions without launching them every time</strong>.<br>It’s very easy and fast to use. <br>Usually, when you are running act and all it’s fine your Github Actions will not have problems.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a6dad8da367" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2021 Recap and 2022 Goals]]></title>
            <link>https://minompi.medium.com/2021-recap-and-2022-goals-9f3771437bb7?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f3771437bb7</guid>
            <category><![CDATA[achievement]]></category>
            <category><![CDATA[goals]]></category>
            <category><![CDATA[improvement]]></category>
            <category><![CDATA[careers]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Thu, 27 Jan 2022 07:31:02 GMT</pubDate>
            <atom:updated>2022-01-27T07:31:02.546Z</atom:updated>
            <content:encoded><![CDATA[<p>At the end of every year usually, I check my goals for the current year and I set them for the next year.<br>This is an activity that helps me to improve my skill build step by step career.</p><p>Building a <strong>career</strong> it’s difficult sometimes because you don’t know what you want next or what you want to achieve. <br>For this reason, I take some days to understand it and try to design the next steps for my career.<br>Sometimes I need to change a lot of things but it’s important to follow our dream.</p><p>Remember that a career is more than a job and every company (or most of them) is hiring developers.</p><p>So my goals for 2021 were:<br>- <strong>read more than 30 books</strong><br>- <strong>learn React</strong><br>- <strong>5 meetup as a speaker</strong><br>- <strong>write at least 5 articles</strong><br>- <strong>release phparkitect</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UwElkoF1DiRkOHXeB2_pSg.jpeg" /></figure><h3>Read more than 30 books</h3><p>I have read a lot of articles about: <br>“You need to read at least 20 books, 30 books 50 books..”</p><p>I have taken this advice and I set the goal of 30 books for 2021.<br>In the first three months, I read about 8 books and I was really happy about it.<br>But I decided to think about this behavior and what I’m trying to achieve in 2021.</p><p>My goal is not to read 30 books, my goal is to improve my skill, get a new point of view. So my goal is to learn not to read books only to check from my list this goal.</p><p>I decided to stop for a moment and change this behavior. <br>After that, I take my books and I continue to reading them more slowly, getting notes and thinking about what they try to share.<br>I have created a template in <a href="https://www.notion.so/"><strong>Notion</strong></a> to track my books and notes inside.<br>I started to create a visual mapping with <a href="https://miro.com/"><strong>Miro</strong></a> and at the end of the year I don’t achieve my goal of 30 books, I read 18 books but I am really satisfied with what I have learned in a year.</p><p>So it’s time to share the 3 best books that I have read this year:<br>- <a href="https://en.wikipedia.org/wiki/Antifragile_(book)"><strong>Antifragile</strong></a><br>- <a href="https://startup-scaleup-screwup.com/"><strong>Startup, Scaleup, Screwup</strong></a><br>- <a href="https://en.wikipedia.org/wiki/The_Goal_(novel)"><strong>The goal</strong></a></p><h3>Learn React</h3><p>Another goal for my 2021 was to learn <strong>React</strong>, and to learn React I meant to write a single page application with components and test obviously.<br>I have reached the goal before June following some articles and tutorials.<br>I did an application useful to manage my bank account.</p><p>I started watching some tutorials and create my first react <strong>Kata project</strong>.<br>A Kata is a project to learn something new without thinking about the idea. You can try new approaches, frameworks, and languages.</p><p>My first kata project with React was a simple to-do list where I had to create a list, edit it and view it.<br>After this, I have complicated the to-do list project with some features to understand well hooks and best practices.</p><h3>5 meetup as a speaker</h3><p>In 2021 I did exactly 5 talks:<br>- <a href="https://www.youtube.com/watch?v=jAmRsz1GpTQ">PugRomagna</a> 2 talks about hexagonal architecture in <strong>Symfony</strong> and another one about smart working<br>- <a href="https://www.jugmilano.it/">JUG Milano</a> about hexagonal architecture in <strong>Kotlin</strong><br>- <a href="https://www.meetup.com/it-IT/Ticino-Software-Craft/">Ticino Software Craft </a>about hexagonal architecture in <strong>Kotlin</strong><br>- <a href="https://roma.grusp.org/">PugRoma</a> about hexagonal architecture</p><p>Speaking activities are moments where you share something with other people but you are learning at the same time because you need to study concepts deeply to explain them to others.<br>It’s important to open your mind to questions and different points of view.<br>Every time that I did a talk I learned something and I met a lot of clever developers, I recommend to all the developers to try to share their knowledge with others because it’s a moment to network and learn together every time.</p><h3>Write at least 5 articles</h3><p>In 2021 I wrote<br>- <a href="https://dev.to/minompi/why-you-should-deploy-on-friday-without-fear-3c2p"><strong>Why you should deploy on Friday without fear</strong></a><br>- <a href="https://dev.to/minompi/how-dotfiles-can-save-you-a-lot-of-time-55oe"><strong>How dotfiles can save you a lot of time</strong></a><br>- <a href="https://dev.to/minompi/push-and-publish-docker-images-with-github-actions-8a3"><strong>Push and publish Docker images with GitHub Actions</strong></a><br>- <a href="https://dev.to/minompi/learning-a-new-programming-language-1d2j"><strong>Learning a new programming language</strong></a><br>- <a href="https://dev.to/minompi/phparkitect-put-your-architectural-rules-under-test-1c99"><strong>PHPArkitect: Put your architectural rules under test!</strong></a></p><p>It was very interesting to write these articles because explaining to others in a fluent and clear article sometimes could be difficult. <br>I tried to write small articles and answer all their questions.<br>Sometimes people contact me in private asking for advice or doubts about the article and their projects, and I am very happy to answer them and ask for a different point of view if it’s possible.</p><h3>Release PHParkitect</h3><p>The last goal was to release <a href="https://github.com/phparkitect/arkitect"><strong>PHPArkitect</strong></a><strong> </strong>in 2021.<br>It’s a library that helps you to keep your <strong>PHP</strong> codebase coherent and solid, by permitting you to add some architectural constraint check to your workflow.<br>The team is made up of a couple of people and I am one of them.<br>We developed the tool all year and we released it to all the world in May.<br>Nowadays we are working to improve the library day by day and at the moment we are using it in some projects.<br>I think that there are a lot of features to be done to improve the library.</p><p>Feel free to try it and give me feedback, please!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/666/1*HmezHW5GToSSYUl3pl17UA.jpeg" /></figure><h3>Goals 2022</h3><p>For 2022 I take some hours and I walk alone to understand what I would like to achieve next year.<br>Learning sometimes could be easy but focusing on the right things it’s difficult.</p><p>I thought about my career path and what I can do in the next years and I understand that this year I would like to:</p><p>- learn typescript because I think that it could be a good solution for many projects<br>- read books that can help me to improve my hard skill and soft skill. I wrote a list of books that can help me, and these are the first two books that I will read: <a href="https://www.amazon.com/Clean-Craftsmanship-Disciplines-Standards-Ethics/dp/013691571X"><strong>Clean Craftsmanship</strong></a>, <a href="https://www.amazon.com/Learning-Domain-Driven-Design-Aligning-Architecture/dp/1098100131/ref=sr_1_1?crid=3ATPWKPGJ322M&amp;keywords=Learning+Domain-Driven+Design&amp;qid=1643268343&amp;s=books&amp;sprefix=learning+domain-driven+design%2Cstripbooks-intl-ship%2C152&amp;sr=1-1"><strong>Learning Domain-Driven Design</strong></a> <br>- do at least 3 talks to continue my career as a speaker <br>- write at least 10 articles to share my knowledge and to understand deeply some concepts to share</p><p>At the moment these are my goals for 2022, I have scheduled some moments to check every point, and write down a path to achieve them during the year.<br>It’s important not only to understand your goal but it’s important to measure them and create a path to understand how to achieve them.</p><p>To do it you need to ask yourself:<br>- <strong>What is the definition of done to understand if this goal is achieved or not?</strong><br>- <strong>How can I achieve this goal?</strong></p><p>Answering these questions you can understand well your next steps to improve yourself and your career.</p><p><strong>Creating your career</strong> it’s one of the most difficult things to do because it depends on you usually.<br>You need to understand where do you want to go and what are next steps to achieve your goals.</p><p>It’s a never-ending path but could be amazing, it depends on you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f3771437bb7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PHPArkitect: Put your architectural rules under test!]]></title>
            <link>https://minompi.medium.com/phparkitect-put-your-architectural-rules-under-test-3c130a6e83dd?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/3c130a6e83dd</guid>
            <category><![CDATA[rules]]></category>
            <category><![CDATA[standards]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[static-code-analysis]]></category>
            <category><![CDATA[tools]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Mon, 03 Jan 2022 10:45:31 GMT</pubDate>
            <atom:updated>2022-01-03T10:45:31.125Z</atom:updated>
            <content:encoded><![CDATA[<p>In every project there is at least an architectural rule usually like: every class inside Controller directory should be called with suffix Controller.</p><p>I have seen a lot of projects in my career with many different types of rules.<br>Other examples could be when a team tries to apply the hexagonal architecture and inside the domain, you shouldn’t call external libraries or framework classes (there are exceptions but this is out of scope).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XKzTR8rLmh8ZCRC6xD9ACg.jpeg" /></figure><p>Usually, a team shares those rules during retrospective or dedicated moments to improve the software and to establish rules to follow.<br>But after some months usually, those rules could be violated by new members of the team or someone that doesn’t remember them.<br>So the next step is to write down into a README file or in a file all the rules but again they can be violated.</p><p>Another good solution is to write <strong>ADR</strong>: <a href="https://adr.github.io/">Architectural Decision Records</a> that explain the choice and the reason, but still, they can guarantee that will not be violated.</p><p>You need a tool to validate your architectural rules.<br><a href="https://github.com/phparkitect/arkitect">PHPArkitect</a> can do it for you.</p><p><strong>PHPArkitect</strong> is a tool that helps you to keep your PHP codebase coherent and solid, by permitting you to add some architectural constraint check to your workflow.<br>It was born in 2020 to satisfy the need to respect architectural rules in various projects.<br>In Java there is a similar tool from which we took inspiration: <a href="https://www.archunit.org/">archunit</a>.</p><p>Now PHPArkitect is public and you can find it <a href="https://github.com/phparkitect/arkitect">here</a></p><h3>Which problem is trying to solve PHPArkitect?</h3><p>As I explained before, PHPArkitect was born to help teams to define architectural rules in a project.<br>With this tool, you can add a new step with it into your continuous integration and you have all your architectural rules in a file, so new developers can understand easily the constraints of the project.</p><h3>How to install it?</h3><p>To install PHPArkitect you can use composer launching this command into your CLI:</p><pre>composer require — dev phparkitect/phparkitect</pre><p>You can also use a <strong>.phar</strong> file because you can have some conflicts with one or more of Phparkitect’s dependencies.<br>The Phar can be downloaded from GitHub:</p><pre>wget <a href="https://github.com/phparkitect/arkitect/releases/latest/download/phparkitect.phar">https://github.com/phparkitect/arkitect/releases/latest/download/phparkitect.phar</a><br>chmod +x phparkitect.phar<br>./phparkitect.phar check</pre><h3>How can you use it?</h3><p>To use PHPArkitect it’s necessary to create a file inside your root called phparkitect.php with your rules written inside it like this:</p><pre>&lt;?php</pre><pre>declare(strict_types=1);</pre><pre>use Arkitect\ClassSet;<br>use Arkitect\CLI\Config;<br>use Arkitect\Expression\ForClasses\HaveNameMatching;<br>use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;<br>use Arkitect\Rules\Rule;</pre><pre>return static function (Config $config): void {<br> $classSet = ClassSet::fromDir(__DIR__ . ‘/src’);<br> $r1 = Rule::allClasses()<br> -&gt;that(new ResideInOneOfTheseNamespaces(‘App\Order\Infrastructure\Controller’))<br> -&gt;should(new HaveNameMatching(‘*Controller’))<br> -&gt;because(“we want uniform naming”);</pre><pre>$config-&gt;add($classSet, $r1);<br>};</pre><p>And now you can launch from your CLI the command:</p><pre>./vendor/bin/phparkitect check</pre><p>If you want to use a different name for your file you can specify it when you launch the command like this:</p><pre>./vendor/bin/phparkitect check — config=/project/yourConfigFile.php</pre><h3>What can you do with PHPArkitect?</h3><p>With this tool, you can write your own rules for your project.<br>At the moment you can check if a class:</p><p>- depends on a namespace<br>- extends another class<br>- not extend another class<br>- have a name matching a pattern<br>- not have a name matching a pattern<br>- implements an interface<br>- not implement an interface<br>- depends on a namespace<br>- don’t have dependency outside a namespace<br>- reside in a namespace<br>- not reside in a namespace</p><p>Let’s make some examples:</p><p>Assume that if you want those classes inside a namespace that doesn’t depend on classes outside that namespace you can write this rule:</p><pre>$rule = Rule::allClasses()<br> -&gt;that(new ResideInOneOfTheseNamespaces(‘App\Catalog\Domain’))<br> -&gt;should(new NotHaveDependencyOutsideNamespace(‘App\Catalog\Domain’))<br> -&gt;because(‘domain should not have external dependencies’);</pre><p>If you want to be sure that classes inside a namespace are following certain naming rules you write a rule like this:</p><pre>$rule = Rule::allClasses()<br> -&gt;that(new ResideInOneOfTheseNamespaces(‘App\Order\Infrastructure\Controller’))<br> -&gt;should(new HaveNameMatching(‘*Controller’))<br> -&gt;because(“we want uniform naming”);</pre><p>If you want to be sure that all classes that extend a class are following certain naming rules you write a rule like this:</p><pre>$rule = Rule::allClasses()<br> -&gt;that(new Extend(AbstractType::class))<br> -&gt;should(new HaveNameMatching(‘*Type’))<br> -&gt;because(‘we want uniform form type naming’);</pre><p>You can also exclude some classes from the rules for example:</p><pre>$rule = Rule::allClasses()<br> -&gt;exclude([‘App\Order\Application\Service\Foo’])<br> -&gt;that(new ResideInOneOfTheseNamespaces(‘App\Order\Application\Service’))<br> -&gt;should(new HaveNameMatching(‘*Service’))<br> -&gt;because(“we want uniform naming”);</pre><h3>How to contribute</h3><p>PHPArkitect it’s young at the moment and a lot of things could be developed.<br>If you are interested you can:<br>- try the tool<br>- improve the documentation<br>- try to write your own rule<br>- open pull requests to fix bugs or to discuss new features with a draft<br>- open issues to ask something or to reveal a bug</p><p>You can help with a little effort to improve this project and help other developers.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3c130a6e83dd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Learning a new programming language]]></title>
            <link>https://minompi.medium.com/learning-a-new-programming-language-1adbc508c54d?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/1adbc508c54d</guid>
            <category><![CDATA[learn]]></category>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[learning-to-code]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Fri, 05 Nov 2021 07:58:59 GMT</pubDate>
            <atom:updated>2021-11-22T13:46:04.685Z</atom:updated>
            <content:encoded><![CDATA[<p>In this period every day, a new programming language could be released and can become one of the most interesting in a few months.<br>So it’s difficult for a developer to learn every day a new different programming language because you need the time to explore it.<br>Many times other developers ask me: <br>“<strong>How can I learn a new programming language?</strong>”</p><p>Well in my opinion there isn’t the perfect recipe to learn a new programming language because it depends principally on how the developer can learn new things.<br>Some people need to learn from books or others that prefer coding directly etc.</p><h3>SHU HA RI</h3><p>Before going deep into the argument, I would like to share the concept of SHU-HA-RI, because I think that it’s important to know when you start to learn something:</p><p>Shu-ha-ri is a concept of Japanese martial arts and describes the stages from learning to mastery, therefore a path that involves the presence of a teacher accompanying a student.<br>This concept was taken into Toyota to indicate the skills development model.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*dtkMwR4AvquKXVUYpQcijw.jpeg" /></figure><p>(image from:<a href="https://leadagilesolutions.com.au/a-mental-model-for-the-phases-of-mastery/"> https://leadagilesolutions.com.au/a-mental-model-for-the-phases-of-mastery/</a>)</p><p>Shu-Ha-Ri is a way of thinking about how you learn a technique and can be divided into three steps:</p><p>* Step one: <strong>Shu</strong>. The Sensei (the coach) protects the student by showing how to do it, without leaving room for errors and distortions. The practice must be performed as per the manual.<br>* Step Two: <strong>Ha</strong>. The student, independently, applies the practices respecting the standard. Here the student will be wrong, but he will understand even more.<br>* Step Three: <strong>Ri</strong>. The student applies the practice in complete autonomy, with strong creativity. He has understood the spirit and no longer feels “bound” by the rules. He might even revise the rules themselves.</p><p>This approach can be used in many different scopes: music, martial art, coding…</p><p>Usually, when I would like to learn a new programming language I try to follow the Shu-ha-ri approach trying to divide my learning time into <strong>different steps</strong>:</p><p>* Read the documentation<br>* Watch videos <br>* Follow people on Twitter that shares context about that language<br>* Find a mentor<br>* Learning by Doing (kata)<br>* Contributing to open-source projects<br>* Teach What You Learn<br>* Be Curious</p><h3>Read the documentation</h3><p>Sometimes it’s very annoying to read the documentation of something but don’t under evaluate this step because reading the documentation is the first approach to a new language, to understand how it works, how you can start, what you need in terms of software, tools, libraries.<br>Reading the “Get started” chapter, usually, helps you to enter into a new world and for me, it’s fantastic to see new things and how their work.</p><p><strong>You don’t have to read all the documentation</strong>, my advice it’s to read the first parts, to understand how can you start to write something and step by step learn new things.<br>Sometimes the documentation is not updated or is superficial, feel free to open a pull request or contact the support to improve that part.<br>This is another good step to participate in something and learn new things.</p><h3>Watch videos</h3><p>Nowadays there are a lot of videos about all things.<br>So it’s very common to find developers that share videos about the language that you would like to learn.<br>I usually search for many videos or playlists and watch the first minutes to understand if the level of the video is correct or not for me at that moment.<br>For example, six months ago I studied for a new language and I found an amazing video by an advocate of that language and I stopped that after 3 minutes because the level was too high for me at that moment.<br>I marked the video as “<strong>Watch later</strong>” and after two months I saw all the videos understanding all the things.<br>It depends on your level and skills to find the best videos for that moment for you but believe me, you have a lot of options on the web nowadays to find the best video for you!</p><h3>Follow people on Twitter that shares context about that language</h3><p>Twitter is a social network where you can find a lot of developers that share powerful context about everything.<br>My advice is to search for some developers that frequently share interesting content, and follow them.<br>The next step is to interact with them to ask something to clarify your doubts.<br>I have found a lot of kind developers that help me a lot and vice versa.</p><h3>Find a mentor</h3><p>Finding a mentor sometimes seems difficult and impossible, but I can guarantee that it could be very easy.<br>When I have to find a mentor, usually I am thinking of my colleagues or ex-colleagues first because I know already their skills.<br>If no one has the required skills I am searching on Twitter for example or LinkedIn or participating in community meetings.<br>When you will find your mentor it’s important to share with him your goals to set up your expectations.<br>With him, you can establish a study plan to archive your goals.<br>Once you have specified those things you need to schedule a meeting every one or two weeks with your mentor to check your progress.<br>Don’t forget to ask a lot of things and thoughts in your mind to understand well what you are doing.</p><h3>Learning by Doing</h3><p>Learning by doing it’s one of my favorite steps because I love to touch directly the code and find problems, things not clear and interesting points of view about this new language.<br>It’s very important to practice a lot to become more confident with the new language.<br>I usually create <strong>Kata projects</strong> to make a lot of practice. <br>Kata means “way of doing” and they are projects that you create yourself to learn something: new coding language, different approaches, architectures, etc.<br>You can create a new little project and experiment with what you would like to explore.<br>There are a lot of Kata projects and you can create your own, this is a list of possible kata:<br><a href="https://project-awesome.org/gamontal/awesome-katas">https://project-awesome.org/gamontal/awesome-katas</a></p><p>For example. I did twenty times the Tic-tac-toe game because every time I tried new things and a new way of doing it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*wHIXPRtYgRXowiDj5CMZTg.jpeg" /></figure><h3>Contributing to open-source projects</h3><p>Contributing to open-source projects could be another good solution to learn something about what you are studying, you can always ask questions creating issues or pull requests and you can try to create your first pull request starting from fixing some part of the documentation for example.<br>Open source projects can generate a lot of value and a new strategy to implement something.<br>You can write to contributors and maintainers to learn new things every day.<br>Don’t be scared to try something, open source can open to you a lot of doors.</p><h3>Teach What You Learn</h3><p>After studying something it’s important to <strong>share your knowledge</strong> with other developers. Try to teach what you have learned through a little talk with a few people or you can find a local meetup to try your new skills.<br>When you try to explain something to others you can realize if you know the argument or not, you can realize what you can study and see things from another point of view by answering questions during your talk.<br>Every time that I did a talk, after that, there were a lot of questions and we discussed those, understanding new approaches.</p><h3>Be Curious</h3><p>Every day you can learn something new, there are a lot of resources nowadays.<br>Now it’s up to you what you want to learn from today.<br>Be curious about new approaches, technologies, and all the things about your work.<br>Curiosity helps a developer with learning in two ways. First, it keeps you motivated during learning so you don’t get bored. Second, it highlights new learning opportunities that you would overlook.<br><strong>Curiosity is what makes great engineers stand out from regular ones.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1adbc508c54d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Push and publish Docker images with GitHub Actions]]></title>
            <link>https://minompi.medium.com/push-and-publish-docker-images-with-github-actions-1650dd965ba4?source=rss-21b9bb08545c------2</link>
            <guid isPermaLink="false">https://medium.com/p/1650dd965ba4</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[build]]></category>
            <category><![CDATA[automation-tools]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[github-actions]]></category>
            <dc:creator><![CDATA[AlessandroMinoccheri]]></dc:creator>
            <pubDate>Sun, 02 May 2021 17:47:33 GMT</pubDate>
            <atom:updated>2021-05-02T18:54:03.004Z</atom:updated>
            <content:encoded><![CDATA[<p>In many articles, I mentioned many times about using <a href="https://github.com/features/actions"><strong>GitHub Actions</strong></a> because they are a good choice for a lot of reasons.<br>Nowadays I can admit that there is another choice that I have explored and used a lot these days.<br>What I mean is the functionality of <strong>pushing your docker image through your GitHub Actions during your CI process</strong>.</p><p>Usually, when I want to publish my docker images to DockerHub, I need to do it manually by the command line, like this:</p><p><strong>Building the image</strong></p><pre>docker image build -t organization/project:0.1.0 .</pre><p><strong>Publishing to DockerHub</strong></p><pre><br>docker push organization/project:0.1.0</pre><p>It’s not a lot of work, but every time you fix or add a new feature you need to remember to build a new image and publish it.<br>Usually, <strong>I try to avoid manual operations</strong> because human error is possible, and automating what is repetitive for me is a best practice everywhere.</p><p>So for this reason, in one open-source project <a href="https://github.com/phparkitect/arkitect">Arkitect</a> where I’m contributing nowadays, we have a Dockerfile that needs to be published every time there is a push on master, or a new release comes out.</p><p>I can build and publish the Docker image manually every time, but I prefer to avoid this and I have tried exploring GitHub Actions to automate this process.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_4Ex1uUhL93a3bHyC-TgPg.png" /></figure><p>Exploring GitHub’s actions to automate the process of publishing a docker image to <strong>DockerHub</strong> was interesting because I found a lot of other interesting GitHub actions and many projects that do the automation that I like.</p><p>First of all, I have inserted inside my GitHub project into <strong>Settings-&gt;Secrets</strong>, two important repository secrets:<br>- <strong>DOCKERHUB_USERNAME</strong>: this is your username on Dockerhub or the name of your organization<br>- <strong>DOCKERHUB_TOKEN</strong>: this is the token and you can get it going on DockerHub in <strong>Account Settings-&gt;Security</strong>. Here you can generate a new Access Token. You can take the value and put it on GitHub.</p><p>Next step, I have created a file for the workflow inside GitHub and named it docker-publish.yml</p><p>The file is something like this:</p><pre>name: Arkitect<br>on:<br>  push:<br>    branches:<br>      — &#39;*&#39;<br>    tags:<br>      — &#39;*&#39;<br> pull_request:</pre><pre>jobs:<br>  publish_docker_images:<br>    runs-on: ubuntu-latest</pre><pre>    steps:<br>    — name: Checkout<br>      uses: actions/checkout@v2<br>    — name: Docker meta<br>      id: meta<br>      uses: crazy-max/ghaction-docker-meta@v2<br>      with:<br>        images: phparkitect/phparkitect<br>        tags: |<br>          type=raw,value=latest,enable=${{ endsWith(GitHub.ref, &#39;master&#39;) }}<br>          type=ref,event=tag<br>        flavor: |<br>          latest=false<br>     — name: Login to DockerHub<br>       if: GitHub.event_name != &#39;pull_request&#39;<br>       uses: docker/login-action@v1<br>       with:<br>         username: ${{ secrets.DOCKERHUB_USERNAME }}<br>         password: ${{ secrets.DOCKERHUB_TOKEN }}<br>     — name: Build and push<br>       uses: docker/build-push-action@v2<br>       with:<br>         context: .<br>         push: ${{ GitHub.event_name != &#39;pull_request&#39; }}<br>         tags: ${{ steps.meta.outputs.tags }}<br>         labels: ${{ steps.meta.outputs.labels }}</pre><p>But it’s not enough because this build will only start if the tests pass, so I have moved the content of this file inside my CI process to another workflow called: build.yml. This is the test suite.</p><p>So we need to create a new job that depends on the test job, thanks to the keyword “<strong>needs</strong>”, like this:</p><pre>name: Arkitect</pre><pre>on:<br>  push:<br>    branches:<br>      — &#39;*&#39;<br>    tags:<br>      — &#39;*&#39;<br>    pull_request:</pre><pre>jobs:<br>  build:</pre><pre>    runs-on: ubuntu-latest</pre><pre>    steps:<br>    — uses: actions/checkout@v2</pre><pre>    - name: Install PHP<br>      run : //stuff to install PHP</pre><pre>    - name: Test<br>      run: ./bin/phpunit</pre><pre>  publish_docker_images:<br>    needs: build<br>    runs-on: ubuntu-latest</pre><pre>    if: GitHub.ref == &#39;refs/heads/master&#39; || GitHub.event_name == &#39;release&#39;<br>    steps:<br>    — name: Checkout<br>      uses: actions/checkout@v2<br>    — name: Docker meta<br>      id: meta<br>      uses: crazy-max/ghaction-docker-meta@v2<br>      with:<br>        images: phparkitect/phparkitect<br>        tags: |<br>          type=raw,value=latest,enable=${{ endsWith(GitHub.ref, ‘master’) }}<br>          type=ref,event=tag<br>        flavor: |<br>          latest=false<br>    — name: Login to DockerHub<br>      if: GitHub.event_name != &#39;pull_request&#39;<br>      uses: docker/login-action@v1<br>      with:<br>        username: ${{ secrets.DOCKERHUB_USERNAME }}<br>        password: ${{ secrets.DOCKERHUB_TOKEN }}<br>    — name: Build and push<br>     uses: docker/build-push-action@v2<br>     with:<br>       context: .<br>       push: ${{ GitHub.event_name != &#39;pull_request&#39; }}<br>       tags: ${{ steps.meta.outputs.tags }}<br>       labels: ${{ steps.meta.outputs.labels }}</pre><p>In this example, as I said before, I have created a new job that depends on the job named “<strong>build</strong>”.<br>In this way, if the job named “build” fails, I don’t create a new docker image, because I want to create it only if the tests pass.</p><p>I have used these GitHub Actions:<br><a href="https://github.com/crazy-max/ghaction-docker-meta">crazy-max/ghaction-docker-meta@v2</a> : it extracts metadata (tags, labels) for Docker.<br><a href="https://github.com/docker/build-push-action">docker/build-push-action@v2</a>: it builds and pushes Docker images with <a href="https://GitHub.com/docker/buildx">Buildx</a> with the full support of the features provided by <a href="https://GitHub.com/moby/buildkit">Moby BuildKit</a> builder toolkit.</p><p>A condition that I have added to my docker push job is:</p><pre>if: GitHub.ref == &#39;refs/heads/master&#39; || GitHub.event_name == &#39;release&#39;</pre><p>Because I want to execute this job only:<br>- when there is a push on master<br>- when a new tag is created</p><p>This is necessary for me because I don’t want to create a new docker image every time a pull request is created.</p><p>When there is a push on master the workflow, create a new docker image with the tag “latest”.<br>When a new tag is released, the workflow creates a new docker image, with the tag equal to the tag of the project and the tag “latest” is recreated.<br>In this way, I am sure to publish the last version of the docker image every time with new features or bugs fixed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JzKdcgMYHRJJG97hN-0FnQ.png" /></figure><p>In conclusion, using <strong>GitHub Actions saves me a lot of time</strong> and repetitive work every time I need to publish my docker image for my project.<br>There are a lot of other processes that can be automated that I would like to explore and try in my projects, so as soon as possible I will publish other articles about this argument.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1650dd965ba4" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>