<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Backend engineering blog · Mihai Nicolae</title><description>Practical notes and guides on Symfony, AWS Lambda, codebase analysis, developer tooling and AI-assisted development.</description><link>https://mnic.dev/blog</link><language>en</language><atom:link href="https://mnic.dev/rss.xml" rel="self" type="application/rss+xml"/><item><title>A custom middleware for Symfony Messenger to discard(not send) or not handle certain messages</title><link>https://mnic.dev/blog/configure-symfony-messenger-to-discard-certain-messages</link><guid isPermaLink="true">https://mnic.dev/blog/configure-symfony-messenger-to-discard-certain-messages</guid><description>A guide on how to create a custom middleware for Symfony Messenger to discard(not send) or not handle certain messages.</description><pubDate>Fri, 21 Jun 2024 08:18:37 GMT</pubDate><content:encoded>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, I’ve been working on a project where I needed to implement a logic where certain messages from Symfony Messenger would not get sent or handled if they met certain criteria. It was pretty hard to find a working solution and Symfony documentation didn’t provide a clear answer, so after I found a solution, I decided to write this article to help others who might encounter the same issue.&lt;/p&gt;
&lt;h2 id=&quot;how-symfony-messenger-works&quot;&gt;How Symfony Messenger works&lt;/h2&gt;
&lt;p&gt;When you dispatch a message in Symfony Messenger, it goes through a couple of predefined middlewares. The order is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;add_bus_name_stamp_middleware&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dispatch_after_current_bus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;failed_message_processing_middleware&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;YOUR CUSTOM MIDDLEWARES&lt;/li&gt;
&lt;li&gt;&lt;code&gt;send_message&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handle_message&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;creating-a-custom-message-interface&quot;&gt;Creating a custom message interface&lt;/h2&gt;
&lt;p&gt;Here is a basic example of how you can create a custom message interface that will work with your custom middleware.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App\Messenger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CustomMessageInterface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; shouldSendEmail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s create a message that implements this interface.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App\Messenger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SendEmailMessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CustomMessageInterface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __construct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // If the email ends with @test.com, we should not send the email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; shouldSendEmail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; bool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; str_ends_with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getEmail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;@test.com&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getEmail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; $this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;email;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;creating-the-custom-middleware&quot;&gt;Creating the custom middleware&lt;/h2&gt;
&lt;p&gt;Now, let’s create the custom middleware that will check if the message should be sent or not.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;php&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App\Messenger\Middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; App\Messenger\CustomMessageInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Symfony\Component\Messenger\Envelope&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Symfony\Component\Messenger\Middleware\MiddlewareInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Symfony\Component\Messenger\Middleware\StackInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Symfony\Component\Messenger\Stamp\ReceivedStamp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SendEmailMiddleware&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MiddlewareInterface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Envelope&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $envelope, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;StackInterface&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $stack)&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Envelope&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        $message &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $envelope&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMessage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ($message &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; CustomMessageInterface&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $message&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;shouldSendEmail&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            $envelope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $envelope&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ReceivedStamp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__CLASS__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $stack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;($envelope, $stack);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;registering-the-custom-middleware&quot;&gt;Registering the custom middleware&lt;/h2&gt;
&lt;p&gt;To register the custom middleware, you need to add it to the &lt;code&gt;messenger.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;framework&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;  messenger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    buses&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;      messenger.bus.default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        middleware&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;App\Messenger\Middleware\SendEmailMiddleware&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;sending-but-not-handling-the-message&quot;&gt;Sending but not handling the message&lt;/h2&gt;
&lt;p&gt;If you want to send the message but not handle it, you can use the &lt;code&gt;HandledStamp&lt;/code&gt; class instead.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$envelope &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $envelope&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; HandledStamp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Handled from email middleware&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;__CLASS__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is very useful when you need to implement a custom logic for lots of messages, and you don’t want to clutter your code with if statements in each handler or dispatcher. If you only have one message that needs this logic, you can implement it directly in the handler or right before the dispatch.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note: This is also very useful when you don’t have any handlers configured for the messages, but instead sending messages async to a queueing system, like RabbitMQ. In this case, the handler can be another application which you don’t have access to&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>messenger</category><category>middleware</category><category>php</category><category>symfony</category><author>hi@mnic.dev (Mihai Nicolae)</author></item><item><title>How to set up and deploy a Telegram bot as a Lambda function for free</title><link>https://mnic.dev/blog/how-to-setup-and-deploy-a-telegram-bot-as-a-lambda-function-for-free</link><guid isPermaLink="true">https://mnic.dev/blog/how-to-setup-and-deploy-a-telegram-bot-as-a-lambda-function-for-free</guid><description>A guide on how to set up and deploy a Telegram bot as a Lambda function for free, using Terraform.</description><pubDate>Sat, 01 Jun 2024 08:15:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, I’ve had an idea to create a Telegram bot that would notify me when stocks that I am interested in have a significant change in price. I wanted to have a simple way to keep track of the stocks that I am interested in without having to check the stock market every day.&lt;/p&gt;
&lt;p&gt;This is just my use case, but you can adapt this guide to any other use case that you might have in mind.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before we start, make sure you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;AWS account&lt;/code&gt; with free tier activated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Terraform&lt;/code&gt; installed on your machine. You can find the installation instructions &lt;a href=&quot;https://developer.hashicorp.com/terraform/install?product_intent=terraform&quot;&gt;here&lt;/a&gt; For macOS users, you can install Terraform using Homebrew:
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; terraform&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;AWS &lt;code&gt;CLI&lt;/code&gt; installed on your machine. You can find the installation instructions &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html&quot;&gt;here&lt;/a&gt; For macOS users, you can install the AWS CLI using the following commands:
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;https://awscli.amazonaws.com/AWSCLIV2.pkg&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;AWSCLIV2.pkg&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; installer&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -pkg&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; AWSCLIV2.pkg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -target&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Python, GO, or any other programming language that you are comfortable with. In this guide, I will use &lt;code&gt;Python&lt;/code&gt; to create the logic of the Lambda function.&lt;/li&gt;
&lt;li&gt;For easier development and deployment, also install &lt;code&gt;make&lt;/code&gt; on your machine. You can find the installation instructions &lt;a href=&quot;https://www.gnu.org/software/make/&quot;&gt;here&lt;/a&gt; For macOS users, you can install &lt;code&gt;make&lt;/code&gt; using Homebrew:
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; make&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Telegram&lt;/code&gt; account&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;create-the-actual-telegram-bot&quot;&gt;Create the actual Telegram bot&lt;/h2&gt;
&lt;p&gt;The first step is to create a new bot using the &lt;code&gt;BotFather&lt;/code&gt; on Telegram. You can find the BotFather by searching for it on Telegram.&lt;/p&gt;
&lt;p&gt;Just start a new chat with this Bot and type &lt;code&gt;/newbot&lt;/code&gt;. The BotFather will guide you through the process of creating a new bot. After the bot is created, you will receive a &lt;code&gt;token&lt;/code&gt; that you will need later, so make sure to save it.&lt;/p&gt;
&lt;p&gt;You can see an example of how to create a new bot using the BotFather in the image below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;example-1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1236&quot; height=&quot;1652&quot; src=&quot;https://mnic.dev/_astro/ex1.DrWOySRn_1NODQi.webp&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;create-your-project&quot;&gt;Create your project&lt;/h2&gt;
&lt;h3 id=&quot;handler&quot;&gt;Handler&lt;/h3&gt;
&lt;p&gt;Create a new directory on your machine where you will store all the necessary files for this project. You can name this directory &lt;code&gt;telegram_bot&lt;/code&gt;. In this directory, create a new directory named &lt;code&gt;code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Inside the &lt;code&gt;code&lt;/code&gt; directory, create a new file named &lt;code&gt;lambda_function.py&lt;/code&gt;. This file will contain the logic of the Lambda function. It must also declare the &lt;code&gt;lambda_handler&lt;/code&gt; function, which is the entry point for the Lambda function. For this example, I tried to keep it simple and only send back the message that the users send. If you want the logic of the stock prices change, you can check the GitHub repository &lt;a href=&quot;https://github.com/mdnicolae/my_lambda_function&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is the content of my &lt;code&gt;lambda_function.py&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; boto3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;secretsmanager &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; boto3.client(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;secretsmanager&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get_secret&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(secret_name):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; secretsmanager.get_secret_value(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;SecretId&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;secret_name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        secret &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; json.loads(response[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SecretString&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; secret&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    except&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Error retrieving secret: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Retrieve the Telegram token from Secrets Manager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;secrets &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; get_secret(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;telegram/bot_token&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; secrets.get(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;TELEGRAM_TOKEN&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; secrets &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;TELEGRAM_API_URL&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://api.telegram.org/bot&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{TELEGRAM_TOKEN}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TELEGRAM_TOKEN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lambda_handler&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(event, context):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;body&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; event:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            body &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; json.loads(event[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;body&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;message&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                chat_id &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;message&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;chat&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; body[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;message&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                send_message(chat_id, text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        except&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; json.JSONDecodeError:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Failed to decode JSON body&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # Check if the event is coming from EventBridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;source&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; event &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; event[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;source&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;aws.events&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            #Do something else when event is from EventBridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Event from EventBridge&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Unhandled event type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &apos;statusCode&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                &apos;body&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: json.dumps(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Bad Request&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &apos;statusCode&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &apos;body&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: json.dumps(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Success&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; send_message&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(chat_id, text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TELEGRAM_API_URL&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;sendMessage&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    payload &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;chat_id&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: chat_id, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: text, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;parse_mode&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Markdown&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requests.post(url, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;payload)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        response.raise_for_status()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    except&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requests.RequestException &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Error sending message: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;This repo contains also the configs for EventBride, to trigger the lambda function periodically on Stock Market opening hours and it also saves the stocks registered by the users in DynamoDB and sends notifications to all the users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;requirementstxt&quot;&gt;requirements.txt&lt;/h3&gt;
&lt;p&gt;Create a new file named &lt;code&gt;requirements.txt&lt;/code&gt; in the same directory. This file will contain the dependencies that the Lambda function needs to have installed. my file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;boto3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;urllib3==1.26.6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;finnhub-python&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: The &lt;code&gt;finnhub-python&lt;/code&gt; package is used to get the stock prices. The &lt;code&gt;boto3&lt;/code&gt; package is used to interact with AWS services.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;makefile&quot;&gt;Makefile&lt;/h3&gt;
&lt;p&gt;Create a new file named &lt;code&gt;Makefile&lt;/code&gt; in the same directory. This file will contain the commands that we will use to build and deploy the Lambda function.&lt;/p&gt;
&lt;p&gt;Here is the content of my &lt;code&gt;Makefile&lt;/code&gt; that you can also use:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;makefile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# This creates the AWS resources defined in the terraform file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	terraform init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	terraform apply -auto-approve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# This command is used to zip the code and upload it to S3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;zip-code&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	zip -r telegram_bot.zip ./code/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	aws s3 cp telegram_bot.zip s3://telegram-bot-lambda-bucket/telegram_bot.zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# This command is used to install the dependencies that will be used as a layer for the lambda function and upload them to S3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;zip-layer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	pip3 install --no-cache-dir -r ./code/requirements.txt -t ./python&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	zip -r python.zip ./python/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	aws s3 cp python.zip s3://telegram-bot-lambda-bucket/python.zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;	terraform apply -auto-approve&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;terraform&quot;&gt;Terraform&lt;/h3&gt;
&lt;p&gt;This file is used to create the necessary resources for the Lambda function. As I previously said, I will keep it simple and only create the Lambda function. If you want the full example, checkout the GitHub repository.&lt;/p&gt;
&lt;p&gt;Create a new file named &lt;code&gt;main.tf&lt;/code&gt; in the root directory. This file will contain the Terraform configuration for the Lambda function.&lt;/p&gt;
&lt;p&gt;Here is the content of my &lt;code&gt;main.tf&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;provider&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  region&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;eu-central-1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws_iam_role&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;lambda_role&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;lambda_role&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  assume_role_policy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; jsonencode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Version &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;2012-10-17&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Statement &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      Effect &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Allow&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      Principal &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Service &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;lambda.amazonaws.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      Action &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;sts:AssumeRole&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws_iam_role_policy_attachment&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;lambda_policy&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aws_iam_role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lambda_role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  policy_arn&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws_s3_bucket&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;lambda_bucket&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;telegram-bot-lambda-bucket&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws_lambda_function&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;telegram_bot&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  s3_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aws_s3_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lambda_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bucket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  s3_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;           =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;telegram_bot.zip&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  function_name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;telegram_bot&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;             =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aws_iam_role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lambda_role&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;arn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  handler&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;lambda_function.lambda_handler&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  runtime&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;python3.8&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  timeout&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;          =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;aws_lambda_layer_version&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;my_layer&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  layer_name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;my-bot-layer&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  s3_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aws_s3_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;lambda_bucket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;bucket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  s3_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;           =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;python.zip&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  compatible_runtimes&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;python3.8&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;deploy-the-lambda-function-and-layer&quot;&gt;Deploy the Lambda function and layer&lt;/h2&gt;
&lt;p&gt;Now that we have all the necessary files and configurations, we can deploy the Lambda function. First, configure your AWS CLI by running the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; configure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don’t manage to configure it, check out this YouTube tutorial: &lt;a href=&quot;https://www.youtube.com/watch?v=dZgLNL869YU&quot;&gt;AWS CLI Configuration&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then, you need to run the following command to create the necessary resources in AWS:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apply&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the resources are created, you can run the following command to zip the code and the layer and upload them to S3:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; zip-code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; zip-layer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the code and the layer are uploaded to S3, you can go to the AWS console and check if the Lambda function was created successfully.&lt;/p&gt;
&lt;h2 id=&quot;iam-role&quot;&gt;IAM Role&lt;/h2&gt;
&lt;p&gt;Go to the AWS console and search for &lt;code&gt;IAM&lt;/code&gt;. Click on &lt;code&gt;Roles&lt;/code&gt; and search for the role that was created by Terraform. You should see a role named &lt;code&gt;lambda_role&lt;/code&gt;. Click on it and attach the following policies that will allow your Lambda function to interact with other AWS services:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;roles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1178&quot; height=&quot;1450&quot; src=&quot;https://mnic.dev/_astro/roles.CAYlpug7_Z1SDEag.webp&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;create-a-new-function-url&quot;&gt;Create a new Function URL&lt;/h2&gt;
&lt;p&gt;To receive messages from Telegram, you need to set up a webhook. You can do this by sending a request to the Telegram API, but first, you need to have a public URL for your lambda function. Recently, AWS introduced the &lt;code&gt;Function urls&lt;/code&gt; that allows you to create a public URL for your Lambda function.&lt;/p&gt;
&lt;p&gt;Go to the AWS console, search for &lt;code&gt;Lambda&lt;/code&gt;, click on &lt;code&gt;Configuration&lt;/code&gt;, and then click on &lt;code&gt;Function urls&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In here, you can create a new URL for your Lambda function. After the URL is created, you can use it to set up the Telegram webhook.&lt;/p&gt;
&lt;h2 id=&quot;set-up-the-telegram-webhook&quot;&gt;Set up the Telegram webhook&lt;/h2&gt;
&lt;p&gt;This is pretty simple, you just need to send a request to the Telegram API to set up the webhook. This webhook will tell telegram to send all the messages for the bot to the URL that you just created. You can do this by running the following command in your terminal:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://api.telegram.org/botTOKEN/setWebhook&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\?&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;FUNCTION_URL/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just replace &lt;code&gt;TOKEN&lt;/code&gt; with the token that you received from the BotFather and &lt;code&gt;FUNCTION_URL&lt;/code&gt; with the URL that you received from AWS.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-secrets-manager&quot;&gt;Setting up the Secrets Manager&lt;/h2&gt;
&lt;p&gt;One more thing that you need to do is to set up the &lt;code&gt;Telegram token&lt;/code&gt; in the &lt;code&gt;Secrets Manager&lt;/code&gt;. Go to the AWS console, search for &lt;code&gt;Secrets Manager&lt;/code&gt;, and click on &lt;code&gt;Store a new secret&lt;/code&gt;. Name it &lt;code&gt;telegram/bot_token&lt;/code&gt; and add a new key-value pair with the key &lt;code&gt;TELEGRAM_TOKEN&lt;/code&gt; and the value the token that you received from the BotFather.&lt;/p&gt;
&lt;h2 id=&quot;testing-the-lambda-function&quot;&gt;Testing the Lambda function&lt;/h2&gt;
&lt;p&gt;If everything was configured correctly, you can test the Lambda function by sending a message to your bot on Telegram. It should respond with the same message that you sent.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this guide, I showed you how to set up and deploy a Telegram bot as a Lambda function with free resources, using Terraform. If you encounter any issues, feel free to ping me and I will gladly help you. You can find me on my socials in the footer of this website.&lt;/p&gt;
</content:encoded><category>aws</category><category>devops</category><category>lambda</category><category>serverless</category><category>telegram</category><category>terraform</category><author>hi@mnic.dev (Mihai Nicolae)</author></item><item><title>How analyzing your codebase can save you time and money</title><link>https://mnic.dev/blog/how-analyzing-your-codebase-can-save-you-time-and-money</link><guid isPermaLink="true">https://mnic.dev/blog/how-analyzing-your-codebase-can-save-you-time-and-money</guid><description>A comprehensive guide about hotspots in your codebase, cognitive complexity and avoiding disasters by being proactive. An article inspired by the book &quot;Your Code as a Crime Scene&quot; by Adam Tornhill with practical examples.</description><pubDate>Tue, 13 Feb 2024 18:15:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Recently, I’ve come across a book entitled &lt;code&gt;&quot;Your Code as a Crime Scene&quot;&lt;/code&gt;, written by &lt;code&gt;Adam Tornhill&lt;/code&gt;. You can find the book &lt;a href=&quot;https://pragprog.com/titles/atcrime/your-code-as-a-crime-scene/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is a book that I highly recommend to anyone who is interested in software development, especially if you are a software engineer, team lead, or architect.&lt;/p&gt;
&lt;h2 id=&quot;so-what-is-actually-a-hotspot&quot;&gt;So, what is actually a hotspot?&lt;/h2&gt;
&lt;p&gt;To gain a deeper understanding of this concept, let’s take a moment to explore the realm of the &lt;code&gt;criminal world&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Locations where crimes occur are rarely just a simple point on a map. They usually follow a pattern and are often near the actual location of the offender.&lt;/p&gt;
&lt;p&gt;Maybe you’ve seen this in movies, where detectives use &lt;strong&gt;a map&lt;/strong&gt; with pins and strings to connect them or draw big circles to see &lt;strong&gt;where the crimes overlap&lt;/strong&gt;. In the software world, just like in the criminal one, we can also &lt;code&gt;pinpoint hotspots&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These are the places in our codebase that can cost us a lot of &lt;code&gt;time&lt;/code&gt; and &lt;code&gt;money&lt;/code&gt; if they are not addressed properly.&lt;/p&gt;
&lt;h2 id=&quot;ok-but-how-to-find-hotspots-in-your-project&quot;&gt;OK, but how to find hotspots in your project?&lt;/h2&gt;
&lt;p&gt;The first step is to identify the needs of your project. The techniques can vary depending on the size of the codebase, the number of developers, the complexity of the project, and so on.&lt;/p&gt;
&lt;h3 id=&quot;codecity&quot;&gt;CodeCity&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CodeCity&lt;/code&gt; is a simple and intuitive tool for software analysis.&lt;/p&gt;
&lt;p&gt;It provides a visual representation of your codebase, where each package is represented as a &lt;code&gt;city block&lt;/code&gt; and each class is depicted as &lt;code&gt;a building&lt;/code&gt;. The height of the building corresponds to the &lt;code&gt;number of methods&lt;/code&gt;, while the base represents the number of &lt;code&gt;attributes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to know more about CodeCity, or even try it out, you can find it &lt;a href=&quot;http://wettel.github.io/codecity.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Below is an example of a CodeCity visualization:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;codecity&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;710&quot; height=&quot;388&quot; src=&quot;https://mnic.dev/_astro/codecity.DevoO8bX_2mT3h3.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this visualization, we can easily identify the hotspots. The &lt;code&gt;tallest&lt;/code&gt; building, which is also the most &lt;code&gt;intense&lt;/code&gt; in color, represents the biggest hotspot in this case, which would be a good starting point for &lt;code&gt;further analysis&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note: While CodeCity is a fun tool, you should use it with other tools and techniques to get a complete picture of your threats and potential bottlenecks&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;codescene&quot;&gt;CodeScene&lt;/h3&gt;
&lt;p&gt;Researchers proved that the &lt;code&gt;frequent changes&lt;/code&gt; to the same code generally indicate declining quality of the code.&lt;/p&gt;
&lt;p&gt;So, in order to have a clear picture of our possible bottlenecks, we need to combine the &lt;code&gt;complexity&lt;/code&gt; of the code with the &lt;code&gt;frequency of changes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is where &lt;code&gt;CodeScene&lt;/code&gt; comes into play.&lt;/p&gt;
&lt;p&gt;It connects to your GIT provider and analyzes the &lt;strong&gt;commits&lt;/strong&gt; and &lt;strong&gt;pull requests&lt;/strong&gt; to provide a clear visualization of your codebase.&lt;/p&gt;
&lt;p&gt;It also provides a &lt;code&gt;hotspot analysis&lt;/code&gt;, which is a great starting point for identifying the areas that need attention.&lt;/p&gt;
&lt;p&gt;I took the liberty to fork the &lt;code&gt;doctrine/orm&lt;/code&gt; repository and analyze it with CodeScene:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;doctrine-orm&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2290&quot; height=&quot;1650&quot; src=&quot;https://mnic.dev/_astro/doctrine-orm-1.Czu2SJwy_Z1xWBMg.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can already see that doctrine/orm has a lot of hotspots, especially in the &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;One of the most interesting ones is the &lt;code&gt;UnitOfWork.php&lt;/code&gt; file, which has been the subject of many changes and refactorings in the past. Its &lt;strong&gt;complexity&lt;/strong&gt; grew exponentially over time, along with &lt;strong&gt;tight coupling&lt;/strong&gt; with other classes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;doctrine-orm-2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2338&quot; height=&quot;1618&quot; src=&quot;https://mnic.dev/_astro/doctrine-orm-2.sahAgo6M_Z13QOBS.webp&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: CodeScene is actually developed by Adam Tornhill! You can have fun with it &lt;a href=&quot;https://codescene.io/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;preventing-measures&quot;&gt;Preventing measures&lt;/h2&gt;
&lt;p&gt;While most of the disasters cannot be predicted in real life, we have the privilege to prevent some of them in the software world.&lt;/p&gt;
&lt;p&gt;I will present some of the most important measures that &lt;code&gt;any developer&lt;/code&gt; or team lead should take which require &lt;strong&gt;minimal&lt;/strong&gt; to &lt;strong&gt;none&lt;/strong&gt; starting costs but can have &lt;code&gt;huge&lt;/code&gt; impacts &lt;strong&gt;in the long run&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;1-quality-of-code-reviews&quot;&gt;1. Quality of Code Reviews&lt;/h3&gt;
&lt;p&gt;Code Review should take an important part in the development process. A good and thorough code review can prevent a lot of hotspots from appearing in the first place.&lt;/p&gt;
&lt;p&gt;What makes a code review &lt;strong&gt;effective&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A clear picture&lt;/strong&gt;: The reviewer should have a clear picture of the feature or bug that is being addressed. It should understand both, the &lt;code&gt;business&lt;/code&gt; and the &lt;code&gt;technical requirements&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live code reviews&lt;/strong&gt;: Always aim to have &lt;code&gt;live code reviews&lt;/code&gt;. It doesn’t matter if you work in the same office or remotely. If you do code review while talking to the author, you will have a better understanding of the changes and the author’s intentions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-pair-programming&quot;&gt;2. Pair Programming&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Pair programming&lt;/code&gt; is a technique where two developers work on the same code at the same time. It is a great way to prevent hotspots since the code is being reviewed by someone else in &lt;code&gt;real-time&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;3-static-analysis&quot;&gt;3. Static Analysis&lt;/h3&gt;
&lt;p&gt;There are a lot of tools that can help you with static analysis when you write your code. For instance, in JetBrains IDEs, you can use the &lt;code&gt;SonarLint&lt;/code&gt; extension to analyze your code on the fly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: I use the &lt;code&gt;SonarLint&lt;/code&gt; extension along with the &lt;code&gt;InlineError&lt;/code&gt; one. It is a great combination that helps visualize the issues in the code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is a dummy example I wrote just to show you how it looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;sonar-lint-php&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2534&quot; height=&quot;1312&quot; src=&quot;https://mnic.dev/_astro/sonarLint.o_v224Mt_bja7h.webp&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;SonarLint&lt;/code&gt; extension identifies unused variables, popular code smells, and also calculates the &lt;code&gt;cognitive complexity&lt;/code&gt; of your methods.&lt;/p&gt;
&lt;h3 id=&quot;4-team-knowledge&quot;&gt;4. Team Knowledge&lt;/h3&gt;
&lt;p&gt;It is important to have a team that is &lt;code&gt;knowledgeable&lt;/code&gt; about the codebase. This can be achieved by having a good &lt;code&gt;onboarding process&lt;/code&gt; with strong confluence documentations for all the business and technical flows.&lt;/p&gt;
&lt;p&gt;One good starting point is also to have a common &lt;code&gt;knowledge sharing&lt;/code&gt; session, where each team member presents something notable he/she implemented in the past weeks.&lt;/p&gt;
&lt;p&gt;Finding authors that contributed a lot to the codebase but are no longer in the team can also be a good starting point. Those areas are usually the most problematic ones since the current team members are not familiar with the code, and that area of the code may be a ticking time bomb.&lt;/p&gt;
&lt;h3 id=&quot;5-refactoring&quot;&gt;5. Refactoring&lt;/h3&gt;
&lt;p&gt;Refactoring can also be a good example of how you can keep your code clean and avoid disasters.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Large-scale refactorings should always be done only when you have real benefits from them. The costs of refactoring and the potential risks that come with it may outweigh the benefits.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>analysis</category><category>design</category><category>software</category><author>hi@mnic.dev (Mihai Nicolae)</author></item></channel></rss>