<?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>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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt="Image description"&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt="Image description"&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;/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;/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;/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;/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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkugdh9szk858ncio2mzi.png" alt="Image description"&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="Image description" 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"&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"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X7spxQ-k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kugdh9szk858ncio2mzi.png" alt="Image description" 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="Image description" 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"&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"&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"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X7spxQ-k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kugdh9szk858ncio2mzi.png" alt="Image description" 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>
    <item>
      <title>Technical Alignment Process within Enterprise Application Chain - Part 2 - Alignment steps - Preparation</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Tue, 21 Jun 2022 07:50:34 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-2-alignment-steps-preparation-1b3a</link>
      <guid>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-2-alignment-steps-preparation-1b3a</guid>
      <description>&lt;p&gt;When you need to implement something which has an impact on other systems in the chain an alignment is needed. In this situation your Technical Lead initiates the alignment and leads the alignment process by organizing and running the meetings (technical spikes). For this process to be effective, you can follow some base guidelines outlined in this article.&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;
  
  
  Preparation steps for a Technical Alignment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What you need to have before you start&lt;/strong&gt;: You'll need to have a clearly defined issue, feature or improvement requirement. The key question which you should have an answer for before you start alignment preparation is: &lt;u&gt;What do we need to solve?&lt;/u&gt; How should we solve it comes later in the preparation process;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start it in documentation, update documentation&lt;/strong&gt;: Your team is probably using some software to collaborate with other teams and write technical and project documentation (Confluence, some type of a Wiki, ...). Technical alignments are usually done through a combination of mail communication and group calls. There is a lot of information flowing during the alignment process which needs to be filtered into development requirements at the end of the process. The easiest way to do it is to have "Meeting minutes" document after each alignment session and to summarize conclusions from mail communication after some part of the solution becomes clear and agreed upon by all involved teams. For this purpose, you'll need a section in your project's documentation where you can put notes and requirements for all currently active technical alignments. Otherwise, your requirements will get lost in e-mails and notes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Formulate the base of a solution idea&lt;/strong&gt;: If you need to lead the technical implementation of some solution, it's important to have a clearly defined idea of what and how it needs to be done. It's recommended that developers first investigate possible solutions either through investigating the issue or by building requirements for a new feature/improvement from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Narrow down possible solutions and be prepared to implement any of them&lt;/strong&gt;: If there are more than one possible solutions, narrow them down to those which are technically feasible. If you don't like some solution or implementation method or the team is not confident whether it can be done or not - rule it out as a possible solution. When alignments and technical spikes start, you already need to have a clear information on what exactly needs to be done so you can know the impact on other teams/systems in the chain. Proposing a solution which you are not ready to implement only adds confusion to the alignment process. &lt;u&gt;You need to be confident about the solution you are proposing.&lt;/u&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Have team meetings if needed&lt;/strong&gt;: Team meetings and brainstorming sessions for a feature are a great way to clearly define goals and possible implementation methods for a feature. If you feel that the investigation will last for a decent amount of time and can't be done alongside current workload in the sprint, request an investigation user story to be created. The result of the story should be proposals for solutions and it's best to have them documented. This documentation will later serve in the alignment process and creation of a user story (or stories).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assess the impact on other systems&lt;/strong&gt;: Once you have a set of possible solutions, you'll need to assess whether your solutions &lt;u&gt;could&lt;/u&gt; have an impact on other systems. Don't spend too much time on analyzing whether there is an impact or not. That would become clear on the first alignment session, because team leads from other teams are the ones who need to understand your proposed changes and assess whether it has an impact on them or not. If you even remotely think that some application in the chain might be impacted, include their Technical Lead in the alignment process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prepare the list of contacts&lt;/strong&gt;: A Solution Designer is the first contact that you need to have. Solution Designer is responsible for planning and overseeing implementation of the solution on application chain level. If needed, a Solution Designer will create high level architecture for implementation of the solution for other teams. You will also need contacts of potentially impacted teams and their Technical Leaders.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Keep the list of contacts in your project's documentation or team collaboration space. All team members should have access to all relevant contacts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Include and keep the Product Owner updated&lt;/strong&gt;: Even early in the preparation process, your Product Owner should be informed about the issue/feature that needs to be implemented. The only information that a Product Owner needs are why something needs to be done and whether you have potential solutions for it. If needed, the Product Owner could be asked to prepare an investigation story (for which you'll need to provide an estimate in story points).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What you should have at the end&lt;/strong&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;What are you trying to solve?&lt;/li&gt;
&lt;li&gt;A list of possible technical solutions.&lt;/li&gt;
&lt;li&gt;A page in your documentation which describes the problem and potential solutions. You will use and modify this page during the alignment process.&lt;/li&gt;
&lt;li&gt;Contacts for other teams or team leads and a Solution Designer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next article in the series will describe the actual Technical Alignment process.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>collaboration</category>
    </item>
    <item>
      <title>Technical Alignment Process within Enterprise Application Chain - Part 1 - What are technical alignments and who's involved</title>
      <dc:creator>Nikola Stojiljkovic</dc:creator>
      <pubDate>Tue, 21 Jun 2022 07:50:14 +0000</pubDate>
      <link>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-1-what-are-technical-alignments-and-whos-involved-18l4</link>
      <guid>https://dev.to/nikolastojilj12/technical-alignment-process-within-enterprise-application-chain-part-1-what-are-technical-alignments-and-whos-involved-18l4</guid>
      <description>&lt;p&gt;When working in an enterprise environment with several (or a lot) of applications developed in different languages, technologies or even on different platforms, but still tightly connected to each other, changing one minor thing in one application can have huge impact on the chain. That's why technical alignments exist. But in order for them to exist, you must first have a proper structure within your organization to support it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assumptions
&lt;/h2&gt;

&lt;p&gt;Before we start, let's be clear which environment we're talking about here. We are talking about a connected set of web services, business, sales and analytics management software usually combined with one or more front-end facing applications (parts of the system which your consumers will use).&lt;/p&gt;

&lt;p&gt;Target audience are team leaders, solution designers or development team members interested in how an alignment process works and who are the participants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical alignments
&lt;/h2&gt;

&lt;p&gt;Technical alignment is a process of making sure that a change in one application will not result in problems or that it doesn't crash some other application in the chain. The more applications there are in the chain, the greater the possibility of a change having an impact on the chain is. Of course, if you have a lot connected applications, teams working on individual applications, no matter how skilled they are in their area, can and will overlook an impact of a change in some other application. If that happens and the technical alignment was not done, the "blame game" is the last thing you want to do because none of the teams technically failed - the process itself was wrong.&lt;/p&gt;

&lt;p&gt;A good technical alignment will have one or more meeting sessions between Technical Leaders from each team and a Solution Designer. The result will be an architectural solution for a change which will have a minimum impact on involved applications (in order to reduce development costs) and at the same time be the best possible technical solution (in order to bring value to the system). Sometimes multiple solutions will be possible with different balance between development costs and actual value (or quality) of a solution, so decisions in which solution the company will invest should be coordinated by a business oriented staff - a Change Manager. No matter how many solutions there are after technical alignments are completed, each solution and its implementation method in each affected application should be completely clear to all involved teams. When the business decision is made, the teams should be ready to start implementing what they've agreed on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Leaders
&lt;/h2&gt;

&lt;p&gt;Flat team structures are bad. In theory, giving your team freedom to decide who will work on which part of application brings more satisfaction to the people involved in development and can work in smaller isolated teams. Having a flat team structure in an enterprise environment, however, only brings chaos and late delivery.&lt;/p&gt;

&lt;p&gt;In order to avoid that, a Technical Leader should exist in each team. Technical Leader's responsibility is to have enough knowledge of the application he/she is responsible for to either assess the impact of the change on their own application or know which team member has the most knowledge about that particular part of the application where the change has the most impact. During the alignment process, Technical Leaders are communicating with Technical Leaders from other teams in order to properly implement a change and avoid chain instability or application incompatibility.&lt;/p&gt;

&lt;p&gt;Since in a typical enterprise environment you will most likely have applications written in completely different technologies and underlying architectural principles, having a bunch of Technical Leaders throw ideas at each other will usually not result in a constructive and productive conversation. In order to have a productive alignment session with a reasonable amount of time spent, an overseer is needed who can understand each viewpoint from a technical perspective and filter out bad or nonconstructive ideas. That brings us to the role of a Solution Designer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution designers
&lt;/h2&gt;

&lt;p&gt;Apart from the team and a team leader, you'll need a dedicated person who will be in charge of overseeing the architecture of the whole chain (or a part of it which can be logically separated from the rest) and coordinating changes. They are usually called Solution Designers or Architects. Solution Designers must be technical staff with both extensive development experience and great soft skills.&lt;/p&gt;

&lt;p&gt;If you have a manager with little to none understanding of the underlying technology behind each application on this position, you will have a lot of well organized but sadly nonconstructive meetings where each team propose their own "best solution" and brainstorm ideas forever. On the other hand, having highly technically skilled person without soft skills will either result in the same chaos as with a manager (if your Solution Designer is a "soft" decision maker) or result in a risk of making wrong architectural decisions in multiple applications because your Solution Designer's "no compromise" decision making approach is a Single Point Of Failure in your application chain. Both of these bad types of Solution Designers can and will cost your company a decent amount of time and money: lost hours on nonconstructive meetings which could have been used to bring value to the project, bad architectural decisions which produce more problems than they resolve, necessity for system overhaul and refactoring in multiple applications,.. you name it.&lt;/p&gt;

&lt;p&gt;So what does a good Solution Designer do? A good Solution Designer will organize meetings with Technical Leaders, understand the change from the technical perspective, analyze possible architectural solutions for the change by using his/her own technical knowledge and be open for considering solutions proposed by Technical Leads. A good Solution Designer must be able to ask the most challenging technical questions and continue to drive the communication with Technical Leads until even the smallest bit of unclarity is removed. "Is-this-part-clear?" should be the informal nickname of your Solution Designer. Ultimately, a Solution Designer should be an effective decision maker able to push the architectural decisions to all involved teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change Managers
&lt;/h2&gt;

&lt;p&gt;There are three main dimensions of a technical solution: development cost, technical value and time needed to implement the solution across the chain (or how fast the change will be seen by end-users).&lt;/p&gt;

&lt;p&gt;I was going to write a bit about each of these three dimensions, but this article is primarily intended for technical staff (ex. team leaders, solution designers and developers). So, let's just say that a Change Manager takes these three dimensions into account when making the decision on which of the proposed solutions will be accepted.&lt;/p&gt;

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

&lt;p&gt;Now that we have the whole personnel structure ready, the communication and decision making should be more clear and efficient when implementing a change in an enterprise environment. The only thing we need to do now is to prepare and start the technical alignment process. That's something which will be posted in one of the articles in the future.&lt;/p&gt;

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