<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nikola Stojiljkovic</title>
    <description>The latest articles on DEV Community by Nikola Stojiljkovic (@nikolastojilj12).</description>
    <link>https://dev.to/nikolastojilj12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F442811%2F6c408d5e-a668-4a5d-8b07-ac410d82c9f7.jpg</url>
      <title>DEV Community: Nikola Stojiljkovic</title>
      <link>https://dev.to/nikolastojilj12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikolastojilj12"/>
    <language>en</language>
    <item>
      <title>Quick and easy local AI RAG setup with JetBrains IDE integration and browser UI</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Tue, 02 Jun 2026 22:29:16 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/quick-and-easy-local-ai-rag-setup-with-jetbrains-ide-integration-and-browser-ui-bh8</link>
      <guid>https://dev.to/nikolastojilj12/quick-and-easy-local-ai-rag-setup-with-jetbrains-ide-integration-and-browser-ui-bh8</guid>
      <description>&lt;p&gt;The hardest question when trying to adopt a new technology or workflow is "How do I even start?". Searching for the answer to that question is now more difficult than ever. Everything AI related is, guess what..., polluted with AI generated slop. From fake AI generated YouTube tutorials, to AI generated blogs and search results. Of course, most of it is just pure slop that doesn't work.&lt;/p&gt;

&lt;p&gt;Actual human personal experience is hard to find, so I'm here to share that with you. I'm going to post here my setup, from start to finish, just to provide an example of a working system. You are free to adapt each step to your own preferences.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;IMPORTANT&lt;/em&gt;: All of the software listed here is free, open source and is run locally. Because I'm honestly sick of articles and tutorials that have one purpose: to lure you in to using their own cloud hosted subscription based tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisites and my hardware
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Windows&lt;/li&gt;
&lt;li&gt;Docker (optional, for web UI... can be skipped if you want to use local Python instead)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My hardware:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ryzen 9 5950X&lt;/li&gt;
&lt;li&gt;64GB DDR4&lt;/li&gt;
&lt;li&gt;RTX 3080 12GB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe listing hardware configuration is relevant, maybe it's not. I've just listed it to show that my 5 years old workhorse is still pulling its weight, despite being 2-3 generations older than the current hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install ollama
&lt;/h2&gt;

&lt;p&gt;Website: &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;https://ollama.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open a PowerShell terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://ollama.com/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ollama is a free and open source application for downloading, managing and running LLMs locally. It has cloud features as well, but they are not mandatory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download and run your first local LLM model
&lt;/h2&gt;

&lt;p&gt;In our example, we'll use Gemma4. Gemma4 is the latest open source model from Google that can be run locally. The complete list of models available  to ollama is available here: &lt;a href="https://ollama.com/search" rel="noopener noreferrer"&gt;https://ollama.com/search&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your terminal:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This will both download and run Gemma4 locally (be ready for a multi-gigabyte download). Don't worry, the next time you run this command it will use the already downloaded model.&lt;/p&gt;

&lt;p&gt;Default ollama port is 11434. When the model finishes downloading, test it by opening &lt;a href="http://127.0.0.1:11434" rel="noopener noreferrer"&gt;http://127.0.0.1:11434&lt;/a&gt; . You should see a message "Ollama is running".&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Web UI
&lt;/h2&gt;

&lt;p&gt;To get a local web UI (that is very similar to ChatGPT) that supports Retrieval Augmented Generation (RAG), workflows and many other features, we'll use Open WebUI (&lt;a href="https://github.com/open-webui/open-webui" rel="noopener noreferrer"&gt;https://github.com/open-webui/open-webui&lt;/a&gt;). Although it can be setup using locally installed Python, I've decided to try out their Docker image instead. Since I have an Nvidia card, I've used their Nvidia GPU supported docker image.&lt;/p&gt;

&lt;p&gt;At the time of writing this article, the exact command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See Open WebUI's Github page or documentation to double-check if that command is still relevant.&lt;/p&gt;

&lt;p&gt;Again, prepare yourself for a multi-gigabyte download. Once the Docker image is downloaded and started, you can access the web UI at &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt; . It will prompt you to enter admin username and password for your &lt;strong&gt;local&lt;/strong&gt; instance, so you are free to enter whatever you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  JetBrains IDE integration (PHPStorm)
&lt;/h2&gt;

&lt;p&gt;We'll use PHPStorm as an example. Open your settings and go to &lt;strong&gt;Tools &amp;gt; AI Assistant &amp;gt; Providers &amp;amp; API Keys&lt;/strong&gt;. In the &lt;strong&gt;Thrid-paty AI providers section&lt;/strong&gt;, select &lt;strong&gt;Ollama&lt;/strong&gt; from the &lt;strong&gt;Provider&lt;/strong&gt; dropdown. Provide the URL to your locally running ollama instance (the default is &lt;a href="http://127.0.0.1:11434" rel="noopener noreferrer"&gt;http://127.0.0.1:11434&lt;/a&gt;) and click on &lt;strong&gt;Test Connection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This will add Ollama and any models available in it to your JetBrains AI Chat window:&lt;/p&gt;

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

&lt;p&gt;To use local Ollama (and Gemma4 LLM) in other parts of the IDE (code completion, code generation,...) scroll down to the &lt;strong&gt;Model Assignemnt&lt;/strong&gt; section of the same settings page and select your local LLM model (in our case, it's &lt;strong&gt;Ollama/gemma4:latest&lt;/strong&gt;):&lt;/p&gt;

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

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;The only thing that you need to remember is to start ollama and load your local LLM model before trying to use it in your IDE.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Symfony 8 AWS Secrets Bundle</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sat, 23 May 2026 18:26:31 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/symfony-8-aws-secrets-bundle-2nop</link>
      <guid>https://dev.to/nikolastojilj12/symfony-8-aws-secrets-bundle-2nop</guid>
      <description>&lt;p&gt;My previous bundle that supported Symfony 5 and 6 was downloaded over 210.000 times, so it looks like it was useful. :D I've decided to publish an updated one that follows new Symfony bundle architecture as a separate library. More in the second part of this article.&lt;/p&gt;

&lt;p&gt;Anyway...&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/constup-foss/symfony8-aws-secrets-bundle" rel="noopener noreferrer"&gt;https://github.com/constup-foss/symfony8-aws-secrets-bundle&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;This bundle allows you to use secrets stored in AWS Secrets Manager as parameter values in your Symfony 8 service container. If you are using AWS Secrets Manager to store encrypted secrets with access control that limits who (or what application) can see and use them through IAM roles, this bundle is for you.&lt;/p&gt;

&lt;p&gt;It supports several methods of authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;by loading a profile from your &lt;code&gt;~/.aws&lt;/code&gt; directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;by using long-term credentials (&lt;code&gt;AccessKeyId&lt;/code&gt; and &lt;code&gt;SecretAccessKey&lt;/code&gt;) from your AWS IAM user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;by using temporary AWS STS tokens&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using it is very simple and does not require any additional programming from your part. Just set a value of a desired environment variable to the name of your AWS secret, use the provided env var processor to process that environment variable in your service container and you are ready to use the value. That's it.&lt;/p&gt;

&lt;p&gt;The bundle supports using an endpoint to connect to AWS. Useful if your AWS connection is behind your corporate infrastructure or if you want to perform integration tests on something like LocalStack. It also supports fetching individual JSON keys from your AWS secret. Just name the key after the name of the secret when assigning a value to your environment variable.&lt;/p&gt;

&lt;p&gt;Complete documentation is available in the repository including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A practical step-by-step example how to use the bundle to load database connection credentials in DoctrineORM;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to use the bundle in different environments (bare metal, docker, AWS CodeBuild pipeline)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A little bit of history and why feedback matters
&lt;/h2&gt;

&lt;p&gt;My original AWS Secrets Bundle (&lt;a href="https://github.com/constup-foss/aws-secrets-bundle" rel="noopener noreferrer"&gt;https://github.com/constup-foss/aws-secrets-bundle&lt;/a&gt;) was published in August 2021 for Symfony 5. It was just something that I needed for my job at the time and decided to publish it. Apart from just a couple of pull requests, mainly to support Symfony 6 and later 7, there wasn't much feedback. Barely any GitHub stars (11 in total, mostly from my friends), barely any issues. I honestly thought that no one uses it, and since I've mostly moved my work to Node and TypeScript, I just forgot about it.&lt;/p&gt;

&lt;p&gt;Fast forward 4 and a half years. I've logged in to Packagist to add a new composer library. No one really logs in to Packagist unless they need to publish something. When you do, the statistics are on a page that you don't need to visit. But, I was in a "cleanup mode"... cleaning up old and obsolete repositories, separating my GitHub account to my personal one and one for FOSS,... so I needed to see if I need to deprecate or delete some libraries.&lt;/p&gt;

&lt;p&gt;And the number of was simply there: 212.549 downloads.&lt;/p&gt;

&lt;p&gt;I have abandoned the project a long time ago simply because there was no indication that anyone was using it.&lt;/p&gt;

&lt;p&gt;So, if you are using a library, consider sending a star. It's not about vanity, it's not even about showing gratitude. It's about letting library maintainers know that their work is used so that they don't abandon it thinking that no one does... just like I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  A really simple solution made by Symfony
&lt;/h2&gt;

&lt;p&gt;Symfony made a library to help with this: &lt;a href="https://github.com/symfony/thanks" rel="noopener noreferrer"&gt;https://github.com/symfony/thanks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Require it in your projects as a dev dependency and do &lt;code&gt;composer thanks&lt;/code&gt;. It will send stars to libraries that your project is using.&lt;/p&gt;

&lt;p&gt;Anyway... That's it for now. I hope my bundle serves you well. And don't forget to star it ;)&lt;/p&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>aws</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JaCoCo XML to HTML - my new FOSS tool written completely in PowerShell</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Thu, 06 Feb 2025 10:31:56 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/jacoco-xml-to-html-my-new-foss-tool-written-completely-in-powershell-4gia</link>
      <guid>https://dev.to/nikolastojilj12/jacoco-xml-to-html-my-new-foss-tool-written-completely-in-powershell-4gia</guid>
      <description>&lt;p&gt;I was looking for an HTML generator for Pester's unit tests coverage report XML and couldn't find one which does not depend on 3rd party tools/languages and is completely free.&lt;/p&gt;

&lt;p&gt;So, I've built one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/constup/JaCoCo-XML-to-HTML-PowerShell" rel="noopener noreferrer"&gt;https://github.com/constup/JaCoCo-XML-to-HTML-PowerShell&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pure PowerShell without dependencies&lt;/li&gt;
&lt;li&gt;Code coverage statistics per group, package and source file&lt;/li&gt;
&lt;li&gt;Source code coverage with colored lines, automatic source code language detection and syntax highlighting&lt;/li&gt;
&lt;li&gt;All supported statistics are covered: instructions, branches, lines, complexity, methods and classes&lt;/li&gt;
&lt;li&gt;Dark and light themes&lt;/li&gt;
&lt;li&gt;Support for custom themes (Bootstrap or your own custom CSS)&lt;/li&gt;
&lt;li&gt;Simple, but rich, well documented configuration (config file) with minimum mandatory fields - exactly 3: XML file, source code directory and HTML destination directory. The rest are pure customization options.&lt;/li&gt;
&lt;li&gt;Easy integration with Pester&lt;/li&gt;
&lt;li&gt;Mozilla Public License 2.0 (free and open source)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: I haven't finished writing all the tests, so it's marked as a "pre-release". My manual testing is confirming that it works on Pester's coverage XML reports, and I've used it on Windows and Linux (Mac testing pending).&lt;/p&gt;

</description>
      <category>jacoco</category>
      <category>java</category>
      <category>powershell</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Impressions on GitHub Copilot and PHPStorm - March 2023</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Mon, 06 Mar 2023 11:12:53 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/impressions-on-github-copilot-and-phpstorm-march-2023-4h40</link>
      <guid>https://dev.to/nikolastojilj12/impressions-on-github-copilot-and-phpstorm-march-2023-4h40</guid>
      <description>&lt;p&gt;After the initial promo year of free access, GitHub released a commercial version of Copilot a while ago. While the price tag isn't anything special ($10 a month or $100 a year), when you consider the fact that there are many tools, services, IDE plugins,... priced at about $10 to $25 a month, the costs quickly pile up. When you add subscriptions which are not work related, it can become a bit overwhelming. So, the question for each subscription service is - is it worth it? Here are my impressions which you may find useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good, not great
&lt;/h2&gt;

&lt;p&gt;First of all, let's set something straight - whatever Copilot can do, it can't be classified as great. It does many things good (or good enough), but not great. You can simply feel the architecture behind the AI in every single code or comment suggestion it makes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Copilot does good
&lt;/h2&gt;

&lt;p&gt;The first thing which Copilot does good is &lt;strong&gt;writing comments for the already existing code&lt;/strong&gt;. I am in the process of revisiting and refactoring some old PHP 7.4 code to PHP 8.2, along with the upgrade of Symfony and PHPUnit. There are parts of the code which I remember being exceptionally complex to write and optimize, which inevitably produced code which is difficult to understand now, 2 years from the time the code was written. Copilot is handy in this situation. I only need to open a comment on top of the code, or start a new docblock comment line, and the suggested description is generated. Copilot's suggestions in this case are OK and mostly true, but I do need to read and try to understand the exact meaning of the generated comment, then run through the code and see if the suggestion was right. &lt;strong&gt;About 80%-90% of the time it is, but there are cases where it can generate a misleading comment which would make more damage than help if left unchecked.&lt;/strong&gt; It's important to note that the accuracy of the generated comment does not depend on the size or complexity of the code. It can be 100% accurate for a complex code, but fail on more simple one (and vice versa). Generated comments are more like good and useful guidelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refactoring and rewriting existing code&lt;/strong&gt; is one of the stronger points of Copilot. If you take a look at Terms of service, you might notice that you're giving the right to Copilot to read and analyze the code of your project and any open tab in your IDE. I can simply feel this being used extensively. For example, if I have two projects opened and trying to rewrite some old code, it will start offering code suggestions based on the currently opened file (tab) of the other project. However, this is a double-edged sword, since it will force suggestions based on the old code. That's fine if I just want to rewrite something and make minimum adjustments (like renaming properties, variables, methods,...), but if I really want to refactor and improve the code, Copilot simply gets in my way with suggestions based on the old code - and it keeps doing it so aggressively that I simply want to disable it until I'm done refactoring. In addition to this, it will almost certainly skip suggesting empty string or array initialization, even if the old code has it and even if it makes perfect sense in the code. The worst part is that it gradually tries to mix the new code with the old one, which does create a solid amount of mess. But, sometimes - it just works perfectly.&lt;/p&gt;

&lt;p&gt;If your code follows a certain architecture and is using design patterns extensively, Copilot really shines. After all, it's made to follow patterns. Following a standard for naming classes and methods and using descriptive names can also help significantly, since it's based on a natural language model and can (in some form) "understand" the context and purpose of the code based on names. For example, include "DataProvider" in the name of a class or trait and it will start suggesting code ideal for use in PHPUnit's data providers (especially if your other data providers follow the same architecture and naming patterns). The same goes for value objects, factories, adapters,...&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Copilot fails
&lt;/h2&gt;

&lt;p&gt;The most obvious fail point is based on the architecture of any ML application today - it's trained on the existing data and will suggest solutions which are the most common for a particular situation. In my case, that's refactoring old value objects to use constructor property promotion and eliminating getters. Neural network behind Copilot is trained on numerous lines of code using getters - and it will almost exclusively suggest getters over direct property access. It does read and remember the code written previously in a class or a method, and will (eventually) adapt and follow my lead, but that's only for that particular file I'm editing at the moment. When I open a new file and start writing fresh code, it will most likely forget the suggestion rules from the previous file. It will simply fall back to the model which it was trained on, until I start rejecting its suggestions again and typing my own solutions.&lt;/p&gt;

&lt;p&gt;Code generated by Copilot is far from being reliable. While it does offer some good suggestions, especially if you first write what you want to do in a comment and let it generate the code, it does not have any knowledge of your application, types or objects which you're using. Although sometimes the accuracy of the suggested code really manages to surprise me, there are much more cases where it just spews out garbage which I need to clean up. The garbage does make some sense, when you take into account that Copilot's neural network is based on natural language - not source code. The most obvious example is that it fairly often suggests using properties which do not exist in my objects, but can be seen as logical given the context. Again, it's the same situation as with generating comments - it does manage to provide good guidelines, but the code needs to be checked manually.&lt;/p&gt;

&lt;p&gt;While we're at reliability, even if generated code's syntax is correct and it uses a proper set of variables, properties and methods which do exist in my code, the suggested result may not exactly do what I'm expecting. I have tested this while rewriting the old code which does have unit test coverage. About 90% of the time, unit tests, written for the manually written code, will fail for the Copilot generated code, if I let Copilot derive the logic itself instead of just letting it copy the old code. The dangerous side of this is that the generated code, when read as natural language, will almost certainly make at least some sense, but the implemented code will simply not work. I do need to carefully read through each generated code suggestion and confirm the logic behind the code, which might waste more time than simply writing the code myself.&lt;/p&gt;

&lt;p&gt;And, lastly, the integration of Copilot, along with JetBrains code completion is a bit clumsy. There are many situations where these two overlap and that can generate some mess. It also doesn't help that Copilot is activated and tries to generate code when typing a  space, a tab or a new line (Enter). It really gets in the way of proper code formatting, which is annoying. I'm also having issues with Copilot's code suggestions being added when I don't want them to be added, simply because of muscle memory when typing a well formatted code. However, that's not the problem of Copilot itself, it's a problem of the IDE plugin. Having a dedicated keyboard shortcut for activating Copilot and the ability to disable suggestions until that keyboard shortcut is pressed would be great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Even though it has some bright moments, after using it for a while on a real project, I am not entirely sure whether it speeds things up or slows the development down. I can not shake the feeling that I need to double check everything it generates, and that can be a bit tiresome. Especially if you take into account the existence of JetBrains own code completion which I can use out of the box without giving it much thought. Sure, JetBrains code completion is a bit more narrow and it can't generate whole blocks of code, but at least it has a proven track record and I simply know that I don't need to check the code it generates at all. I am certain of one thing, though - the workflow when using Copilot, compared to not using it, is completely different. &lt;/p&gt;

&lt;p&gt;Maybe the best way to describe working with Copilot, compared to classic code completion, is to paraphrase Kandi from "Two and a half men":&lt;/p&gt;

&lt;p&gt;"With JetBrains code completion it's kind of like going on Space Mountain - it's a good ride, but there is never any real danger. With Copilot, it's like being in a backseat of a car driven by a really smart kangaroo - it may go up on the curb a couple of times, but it will get you there."&lt;/p&gt;

&lt;p&gt;I will give it one more month and test on other languages, primarily TypeScript, but at the current state - it's not worth the money.&lt;/p&gt;

&lt;p&gt;Buying me a coffee, on the other hand, is well worth the money :)&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>ai</category>
      <category>php</category>
      <category>phpstorm</category>
    </item>
    <item>
      <title>The most efficient way to debug problems with PHPUnit mocks</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sun, 05 Feb 2023 10:52:40 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/the-most-efficient-way-to-debug-problems-with-phpunit-mocks-2fhj</link>
      <guid>https://dev.to/nikolastojilj12/the-most-efficient-way-to-debug-problems-with-phpunit-mocks-2fhj</guid>
      <description>&lt;p&gt;PHPUnit can be overwhelming to those who are just learning the basics of programming and/or unit testing in PHP. It is a powerful and robust tool which has been a cornerstone of unit testing in PHP world for many years now, which means it has a huge set of features covering almost any case you could encounter.&lt;/p&gt;

&lt;p&gt;One of the most powerful features of PHPUnit are &lt;a href="https://phpunit.readthedocs.io/en/10.0/test-doubles.html?highlight=stubs#stubs" rel="noopener noreferrer"&gt;stubs&lt;/a&gt; and &lt;a href="https://phpunit.readthedocs.io/en/10.0/test-doubles.html?highlight=stubs#mock-objects" rel="noopener noreferrer"&gt;mocks&lt;/a&gt;. They give you the ability to detach the rest of your code from the part which you are trying to test. You can mock anything - from (other) methods in a class you are testing to dependencies, abstract classes or even traits and interfaces.&lt;/p&gt;

&lt;p&gt;The first step, of course, is building the mock, and it usually goes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$serviceMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMockBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;YourService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;disableOriginalConstructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;onlyMethods&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'anotherMethodInYourClass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'yetAnotherMethod'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from the methods pictured in the above example, you also have many others, like &lt;code&gt;setConstructorArgs()&lt;/code&gt; and &lt;code&gt;setMethods()&lt;/code&gt;, but we will not go deeper into what they do. What is important in our case is that there are many ways of how exactly you are going to create a mock object, which depends on your needs. You may need to mock a set of dependencies, an abstract class, an interface,... &lt;/p&gt;

&lt;p&gt;If you are still learning (or even if you don't keep up with the changes between versions of PHPUnit), you may end up "guessing" which set of methods you are going to call when creating your mocks. Even StackOverflow is full of answers like "&lt;em&gt;The following way of creating a mock works for me&lt;/em&gt;" - without any information or context provided.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well, let's provide some context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PHPUnit, under the hood, is creating a mock class just like you would write any class. It generates source code for the class, trait or interface which you are trying to mock and fills it with mocked property and return values. One of the checks PHPUnit performs is that the generated mock class code is a valid PHP code. This is done with a less known built-in PHP function &lt;a href="https://www.php.net/manual/en/function.eval.php" rel="noopener noreferrer"&gt;&lt;code&gt;eval($someString)&lt;/code&gt;&lt;/a&gt;. This function evaluates whether &lt;code&gt;$someString&lt;/code&gt; contains a valid PHP code. A bit of warning, though, as the official documentation states: &lt;em&gt;The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That being said, PHPUnit prepares the source code of the generated mocked class and stores it in a string, which is then evaluated using the &lt;code&gt;eval()&lt;/code&gt; function. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are getting errors while trying to create or use mocks, you are not sure what exactly is happening under the hood and how the generated mock class &lt;strong&gt;actually&lt;/strong&gt; looks like - there is a way to see the actual contents (complete source code) of the mocked class, during debugging.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key point to look at is the &lt;code&gt;PHPUnit\Framework\MockObject\MockClass&lt;/code&gt; class and its &lt;code&gt;generate()&lt;/code&gt; method. In PHPUnit 9.6 it goes like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;class_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mockName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;classCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nb"&gt;call_user_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mockName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;'__phpunit_initConfigurableMethods'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;configurableMethods&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mockName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you set a breakpoint at &lt;code&gt;eval($this-&amp;gt;classCode)&lt;/code&gt; you will be able to see the contents of &lt;code&gt;$this-&amp;gt;classCode&lt;/code&gt; which, obviously, contains the complete source code of the generated mock class. The best part is - it's even formatted properly, so you won't have any issues reading it.&lt;/p&gt;

&lt;p&gt;You are now free to experiment with different types of mocks and options for their creation, while looking at how exactly your way of creating mocks affects the end result - the mocked object. Have fun!&lt;/p&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>testing</category>
      <category>phpunit</category>
    </item>
    <item>
      <title>Mock nested PHP default functions in PHPUnit tests</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sat, 28 Jan 2023 23:07:30 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/mock-nested-php-default-functions-in-phpunit-tests-5c9k</link>
      <guid>https://dev.to/nikolastojilj12/mock-nested-php-default-functions-in-phpunit-tests-5c9k</guid>
      <description>&lt;p&gt;Let's say you have the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ComposerFileService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;fetchComposerJsonObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$composerJsonFilePath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;?object&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$composerJsonFilePath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test this method in PHPUnit, use &lt;code&gt;php-mock/php-mock-phpunit&lt;/code&gt; library. First, install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require --dev php-mock/php-mock-phpunit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second step is to use &lt;code&gt;\phpmock\phpunit\PHPMock&lt;/code&gt; trait in your PHPUnit test class. We can then write a unit test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @dataProvider fetchComposerJsonObject_HappyFlow
 *
 * @param string $composerJsonFilePath
 * @param string $fileGetContentsMockValue
 * @param object $jsonDecodeMockValue
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testFetchComposerJsonObject_HappyFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$composerJsonFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$fileGetContentsMockValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="nv"&gt;$jsonDecodeMockValue&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$fileGetContentsMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getFunctionMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ComposerFileService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'file_get_contents'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$fileGetContentsMock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$composerJsonFilePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fileGetContentsMockValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$jsonDecodeMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getFunctionMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ComposerFileService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'json_decode'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$jsonDecodeMock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fileGetContentsMockValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$jsonDecodeMockValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMockBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ComposerFileService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;disableOriginalConstructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;onlyMethods&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fetchComposerJsonObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$composerJsonFilePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$jsonDecodeMockValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data provider for this test is simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;fetchComposerJsonObject_HappyFlow&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$faker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'happy flow'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'composerJsonFilePath'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;word&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'fileGetContentsMockValue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;word&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'jsonDecodeMockValue'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt; &lt;span class="s1"&gt;'key'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;word&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to properly test this method, we did the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$faker&lt;/code&gt; in the data provider is simply using &lt;a href="https://fakerphp.github.io" rel="noopener noreferrer"&gt;https://fakerphp.github.io&lt;/a&gt; to generate random data for our tests. It's not that relevant for our example.&lt;/li&gt;
&lt;li&gt;We are not using a real file from the filesystem. Unit tests should not do that.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file_get_contents&lt;/code&gt; and &lt;code&gt;json_decode&lt;/code&gt; (PHP's default) functions are not called directly, but mocked.&lt;/li&gt;
&lt;li&gt;We are testing that &lt;code&gt;file_get_contents&lt;/code&gt; is getting called once, with the value of &lt;code&gt;$composerJsonFilePath&lt;/code&gt;. The return value is randomly generated (by faker), and is irrelevant in the context of testing the &lt;code&gt;file_get_contents&lt;/code&gt; function. We'll just need it in order to properly test &lt;code&gt;json_decode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We are testing that &lt;code&gt;json_decode&lt;/code&gt; is getting called once, with the value of what &lt;code&gt;file_get_contents&lt;/code&gt; returned.&lt;/li&gt;
&lt;li&gt;And finally, we are testing that our method returned the result of calling &lt;code&gt;json_decode&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information and examples of mocking and spying on PHP's default functions, take a look at the following libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/php-mock/php-mock" rel="noopener noreferrer"&gt;https://github.com/php-mock/php-mock&lt;/a&gt; - a testing library which mocks non deterministic built-in PHP functions;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/php-mock/php-mock-phpunit" rel="noopener noreferrer"&gt;https://github.com/php-mock/php-mock-phpunit&lt;/a&gt; - integrates the function mock library PHP-Mock with PHPUnit;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>testing</category>
      <category>phpunit</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>[PHP Guidelines series] Adapter design pattern + a dangerous workaround to implement Class Adapter</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sun, 22 Jan 2023 00:07:10 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/php-guidelines-series-adapter-design-pattern-a-dangerous-workaround-to-implement-class-adapter-26g5</link>
      <guid>https://dev.to/nikolastojilj12/php-guidelines-series-adapter-design-pattern-a-dangerous-workaround-to-implement-class-adapter-26g5</guid>
      <description>&lt;p&gt;As announced &lt;a href="https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5"&gt;here&lt;/a&gt;, I am working on a series of posts related to good and bad development practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adapter design pattern
&lt;/h2&gt;

&lt;p&gt;The third design pattern covered by this series of articles is Adapter design pattern. The main article, its sub-articles and a solid amount of runnable examples is available at: &lt;a href="https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Structural/Adapter" rel="noopener noreferrer"&gt;https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Structural/Adapter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having the ability to use an interface or class, which might come from a third party (Composer) library, and is incompatible with interfaces that your application can use, is pretty neat.&lt;/p&gt;

&lt;p&gt;The theory defines a couple of ways to implement the Adapter, however, only one of them is available in PHP - the so called "Object Adapter". Other ways ("Class Adapter" and "Two way adapter") can not be implemented in PHP because they require a language which supports multiple inheritance, which PHP doesn't.&lt;/p&gt;

&lt;p&gt;I've come across a couple of resources which are describing a workaround to implement the Class Adapter in PHP (or in any language which does not support multiple inheritance) including a really simplified example. The example looks like it works and does the job, but has a terrible flaw which I have covered (with examples) in the linked repository. &lt;/p&gt;

&lt;h2&gt;
  
  
  More to come later
&lt;/h2&gt;

&lt;p&gt;While the article and examples are providing a solid coverage of the Adapter design pattern, if observed as a separate concept and implemented on a controlled set of examples, there is also a need to cover it from a different perspective - usage in the real world. There is a couple of things which bothers me regarding Adapter and a couple of other design patterns which deserve separate dedicated analysis. I simply can not shake the feeling that the 24 "well known" and (numerously) repeated design patterns are a bit bloated, and that the Adapter, although useful, belongs to this bloatware. But, more on that later in a separate article.&lt;/p&gt;

&lt;p&gt;Enjoy. Comment. Like. Subscribe.&lt;/p&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>[PHP Guidelines series] Abstract Factory design pattern - and why it's bad</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sat, 14 Jan 2023 12:42:15 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/php-guidelines-series-abstract-factory-design-pattern-and-why-its-bad-gbb</link>
      <guid>https://dev.to/nikolastojilj12/php-guidelines-series-abstract-factory-design-pattern-and-why-its-bad-gbb</guid>
      <description>&lt;p&gt;As announced &lt;a href="https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5"&gt;here&lt;/a&gt;, I have started working on a series of posts related to good and bad development practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract Factory design pattern
&lt;/h2&gt;

&lt;p&gt;The second design pattern covered by this series of articles is the Abstract Factory design pattern. The main article, its sub-articles and an &lt;strong&gt;extensive amount of practical examples&lt;/strong&gt; (which you can run either directly or from a bundled Docker container) is available at: &lt;a href="https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Creational/AbstractFactory" rel="noopener noreferrer"&gt;https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Creational/AbstractFactory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Abstract Factory design pattern is one of the 23 well known design patterns covered in many books and online resources. That, however, doesn't stop it from being deeply flawed, poorly named and architecturally inconsistent. Abstract Factory repository section contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Theoretical definition of the Abstract Factory design pattern with practical (runnable examples);&lt;/li&gt;
&lt;li&gt;Analysis of its name, definition and components;&lt;/li&gt;
&lt;li&gt;A viable alternative (Service Bundle) defined in detail and compared to the Abstract Factory design pattern;&lt;/li&gt;
&lt;li&gt;Runnable code examples and deep analysis of working with both the Abstract Factory and Service bundle approach through a series of articles on real world use when:

&lt;ul&gt;
&lt;li&gt;adding a new property;&lt;/li&gt;
&lt;li&gt;adding a new family;&lt;/li&gt;
&lt;li&gt;adding a new family member;&lt;/li&gt;
&lt;li&gt;adding a new Product;&lt;/li&gt;
&lt;li&gt;adding a new subfamily;&lt;/li&gt;
&lt;li&gt;working with methods common to more than one Product, family and/or subfamily.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;All of this and more has been covered in the repository. I will just copy the conclusions here, but you are welcome (and encouraged) to read through the articles in the repository and run through the provided examples.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is the most comprehensive coverage of actually working with Abstract Factories that you will find online or offline.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusions from the repository
&lt;/h2&gt;

&lt;p&gt;Abstract Factory design pattern seems like a creative and effective way to manage families of products, but it really is not. It is a half-way implemented Service Bundle which has many architectural and practical limitations. Working around these limitations, if at all possible, is difficult and can lead, in many cases, to code quality degradation over time. By using encapsulation, as defined in OOP theory, it also promotes creation of monster classes with multiple responsibilities without any defined, structured way to handle the complexity and modularize the code.&lt;/p&gt;

&lt;p&gt;It has an incomplete definition (missing family name property, missing inclusion of Family Resolver in its list of components), and is named contrary to any logic or standards.&lt;/p&gt;

&lt;p&gt;Abstract Factory design pattern suffers form architectural inconsistency - it uses and promotes encapsulation, but at the same time recommends treating Factories as special cases (separate services). It is defined as a creational design pattern, but also manages service (functionality) classification as a side effect.&lt;/p&gt;

&lt;p&gt;Code architecture is forced to follow a fixed family classification and is not flexible enough to properly support functionality which breaks this classification. Real-world usability is, thus, limited.&lt;/p&gt;

&lt;p&gt;It also suffers from unnecessary code repetition.&lt;/p&gt;

&lt;p&gt;This article and its sub-articles have demonstrated, through practical examples, that using a Service Bundle is a much more effective, more flexible and more practical way to achieve the same things as Abstract Factory.&lt;/p&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>oop</category>
    </item>
    <item>
      <title>[PHP Guidelines series] Final classes as a warning sign</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Sat, 14 Jan 2023 12:12:39 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/php-guidelines-series-final-classes-as-a-warning-sign-9n9</link>
      <guid>https://dev.to/nikolastojilj12/php-guidelines-series-final-classes-as-a-warning-sign-9n9</guid>
      <description>&lt;p&gt;As announced &lt;a href="https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5"&gt;here&lt;/a&gt;, I have started working on a series of posts related to good and bad development practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final classes as a warning sign
&lt;/h2&gt;

&lt;p&gt;The next chapter deals with one of the warning signs in PHP development - final classes.&lt;/p&gt;

&lt;p&gt;I am not, in this post, going to go into details on what are final classes and how exactly they are a warning sign. There is a whole article with examples available in the main repository of this series. Let's just say that final classes are functionally useless and can be easily overridden by using a Decorator Design pattern.&lt;/p&gt;

&lt;p&gt;The whole article, with analysis and conclusions is available here: &lt;a href="https://github.com/constup/php-guidelines/tree/master/src/WarningSigns/FinalClasses" rel="noopener noreferrer"&gt;https://github.com/constup/php-guidelines/tree/master/src/WarningSigns/FinalClasses&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>[PHP Guidelines series] Introduction and Factory Method Design Pattern</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Fri, 19 Aug 2022 21:22:00 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/01-php-development-practices-introduction-and-factory-method-45l9</link>
      <guid>https://dev.to/nikolastojilj12/01-php-development-practices-introduction-and-factory-method-45l9</guid>
      <description>&lt;p&gt;As announced &lt;a href="https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5"&gt;here&lt;/a&gt;, I have started working on a series of posts related to good and bad development practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to the series
&lt;/h2&gt;

&lt;p&gt;Since this is the first post in the series, I would like to present the format of the posts and examples.&lt;/p&gt;

&lt;p&gt;In order to provide direct, usable examples which you can run, and to tie documentation to the code, I have decided to write this series as Markdown documentation inside a Symfony 6 project hosted on GitHub. Symfony 6 was chosen because I simply needed a comfortable framework to present the examples in, but the examples themselves are not related to any framework.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Each covered topic will have examples which you can read, run, or play with directly.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The intended way of using the repository is to use it as an online learning, reference and examples resource, but you are free to clone the repo if you want to actually run the examples. You can either run it locally, if you have PHP 8.1 installed and active, or in a provided Docker container.&lt;/p&gt;

&lt;p&gt;The repository is available on GitHub at: &lt;a href="https://github.com/constup/php-guidelines" rel="noopener noreferrer"&gt;https://github.com/constup/php-guidelines&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Factory Method Design Pattern
&lt;/h2&gt;

&lt;p&gt;The first covered topic is the Factory Method Design Pattern: &lt;a href="https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Creational/FactoryMethod" rel="noopener noreferrer"&gt;https://github.com/constup/php-guidelines/tree/master/src/DesignPatterns/Creational/FactoryMethod&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Factory Method Design Pattern is one of the 23 well known design patterns covered in many books and online resources. However, after a deep dive into the theory and practice, I've came to some interesting conclusions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The knowledge which can be found on the first page of Google search results, has significantly degraded. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Top results from websites dedicated to explaining design patterns are either incomplete, cover only one aspect of the pattern, or are simply wrong. The most important part is - each source explains the Factory Method pattern differently, which can be very confusing to students and new developers. &lt;/p&gt;

&lt;p&gt;My intention with this post was to provide a more complete picture, covering the Factory Method design pattern from multiple angles with multiple different implementations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Factory Method Design Pattern, although well known, is not as good for your code as you might think.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have covered the theory, provided examples, explained in detail why it's bad and provided a practical alternative. Motivation behind this is to try and root out bad development practices, regardless of whether they are well known and widely used or not.&lt;/p&gt;

&lt;p&gt;I hope that you will find this resource helpful. Feedback is welcome.&lt;/p&gt;

&lt;p&gt;If you liked the article,...&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/puEW3HvWvP" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt=" " width="434" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>oop</category>
    </item>
    <item>
      <title>Announcement: Detailed PHP development practices series</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Mon, 04 Jul 2022 17:04:00 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5</link>
      <guid>https://dev.to/nikolastojilj12/announcement-detailed-php-development-practices-series-1jg5</guid>
      <description>&lt;p&gt;This post is an announcement of upcoming series of posts. Target audience of the series are primarily PHP and OOP developers in general (although some languages might have different flavors of OOP).&lt;/p&gt;

&lt;p&gt;It will be written from a perspective of primarily PHP backend developer with 12+ years of experience working in Magento/Zend framework and Symfony (although I do prefer raw PHP and writing code which is independent from any framework). I have worked on enough both brand new and completely ruined legacy projects that I've started to see multiple patterns of behavior leading to code degradation. It's time to put that experience on paper, summarize and spread the knowledge.&lt;/p&gt;

&lt;p&gt;The series will cover a lot of stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Object Oriented Programming in PHP and in general, with a hint of Functional Programming and other paradigms&lt;/li&gt;
&lt;li&gt;SOLID principles&lt;/li&gt;
&lt;li&gt;Design patterns&lt;/li&gt;
&lt;li&gt;Warning signs and bad practices&lt;/li&gt;
&lt;li&gt;Good development practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, this will not be just another series of generic tutorials with dry information available everywhere else. This will be a focused effort of analyzing software development practices and potential problems in them by running through well known and established principles - and criticizing them to oblivion when and if needed. The reason is simple: many software development practices are dangerous and create more problems than they solve, but they are still being repeated in numerous online tutorials/courses and taught in schools just because they are "well known and established". I'm sorry, but I'm more utilitarian and pragmatic than dogmatic about everything in life, including work and programming. If something deserves bashing and discarding, it will be bashed to hell and forgotten like Google Glass.&lt;/p&gt;

&lt;p&gt;Everything in the series will be well documented, covered with arguments, theoretical and practical examples. It will be all available in a GitHub repository along with samples integrated into a Symfony 6 application.&lt;/p&gt;

&lt;p&gt;So, feel free to follow me and expect the articles soon.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Technical Alignment Process within Enterprise Application Chain - Part 3 - Running the alignment</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Tue, 21 Jun 2022 07:50:54 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-3-running-the-alignment-5fhg</link>
      <guid>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-3-running-the-alignment-5fhg</guid>
      <description>&lt;p&gt;In the previous two articles, we've seen what are technical alignments, who is involved in the process and how Technical Lead's preparations should look. It's now time to wrap the subject up and describe the process of running the alignment.&lt;/p&gt;

&lt;p&gt;This article is written from a perspective of a Technical Lead and is intended for Technical Leads, Team Leaders and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Alignment Process
&lt;/h2&gt;

&lt;p&gt;But first, let's take a look at what we'll need to have at the beginning of the alignment process. From the end of the previous article, we can see that four key things are needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An answer to the question: What are we trying to solve?&lt;/li&gt;
&lt;li&gt;A list of possible technical solutions.&lt;/li&gt;
&lt;li&gt;A page in our project's documentation which describes the problem and potential solutions.&lt;/li&gt;
&lt;li&gt;A list of contacts of other teams and a Solution Designer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we have all of the above, the alignment process can start. The steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contact a Solution Designer&lt;/strong&gt;: The first step of starting the actual alignment process is to contact a Solution Designer and present your idea. A Solution Designer needs to know why you are requesting a change, the rough (high-level) plan of possible solutions and which teams you predicted to be impacted by your solutions. After you provide all this information, ask the Solution Designer to provide an assessment on whether other teams could be impacted. Agree with the Solution Designer on who should organize the first alignment session (you or the Solution Designer). Agree with Solution Designer and your Product Owner whether a support story needs to be created for other teams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The first alignment session&lt;/strong&gt;: All potentially impacted teams should be present on the first alignment session. You will present the change and potential solutions in this initial meeting and gather feedback on which systems are impacted. All systems which are not impacted are not mandatory to participate in the future alignment sessions. Those who are impacted will stay in alignment sessions as long as necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run the alignment sessions until its completely clear to all involved teams what needs to be done and how&lt;/strong&gt;: The goals of alignment sessions are:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;to narrow down the list of possible solutions to the most feasible/best solution for all involved systems. Even if that solution is not the best or simplest for your team, if it's agreed on during the alignment process, your team needs to be ready to implement it. That's why it's important to propose only solutions which are acceptable for your team and for which your team team has an actual implementation plan;&lt;/li&gt;
&lt;li&gt;to create an implementation plan for your team;&lt;/li&gt;
&lt;li&gt;to create an implementation plan for other teams;&lt;/li&gt;
&lt;li&gt;to have enough technical details and requirements for creating user stories which will describe the solution in such detail that all developers would have enough information in the story and can start working on the solution after refinement;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provide the results of the alignment to your Product owner&lt;/strong&gt;: Product owner should be able to read and understand requirements for the agreed solution and break down the requirements to individual user stories. If needed, provide help and feedback to the Product Owner about which stories are needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;&lt;strong&gt;What you should have at the end&lt;/strong&gt;&lt;/u&gt;: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Documented clear set of requirements and technical details.&lt;/li&gt;
&lt;li&gt;Breakdown of the feature to user stories.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This concludes the series of articles about technical alignments.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>collaboration</category>
    </item>
  </channel>
</rss>
