<?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: Mati Andreas</title>
    <description>The latest articles on DEV Community by Mati Andreas (@alphpkeemik).</description>
    <link>https://dev.to/alphpkeemik</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%2F128640%2F1b6afd48-7bd0-445a-ac71-6912ffcca0a2.jpg</url>
      <title>DEV Community: Mati Andreas</title>
      <link>https://dev.to/alphpkeemik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alphpkeemik"/>
    <language>en</language>
    <item>
      <title>Caching and local storage in PWA</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Sun, 28 Mar 2021 14:09:12 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/caching-and-local-storage-in-pwa-4ig</link>
      <guid>https://dev.to/alphpkeemik/caching-and-local-storage-in-pwa-4ig</guid>
      <description>&lt;p&gt;&lt;em&gt;Image from &lt;a href="https://blog.vuestorefront.io/caching-on-production" rel="noopener noreferrer"&gt;https://blog.vuestorefront.io/caching-on-production&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Base technologies like Vue.js, Vuex, and SSR, Service Workers are used in or team to build modern e-commerce frontends. The Vue Storefront framework PWA will be used as the application skeleton for starting a new project.&lt;/p&gt;

&lt;p&gt;Whenever it's possible, the service worker cache is in use. For easier service worker cache management, Google provided Workbox is in use.&lt;br&gt;
Service worker cache is used mainly for catalog (category, product, and attribute list and detail) and CMS (pages, blocks, banners).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Service Workers cache works like we're consistently executing the backend requests to invalidate the local cache. It's the NetworkFirst mode. That means there is virtually no risk of stale / non-invalidated data served from the local cache &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://blog.vuestorefront.io/caching-on-production" rel="noopener noreferrer"&gt;https://blog.vuestorefront.io/caching-on-production&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;LocalStorage or IndexedDB (depending on browser support, abstracted with LocalForage library) are mainly used for storing user-based data like cart, login token, made orders, personal data, other choices (like favorite products).&lt;br&gt;
The user-based cache is updated on demand (on login, viewing order list) and has no end-of-life by default. End-of-life is added case-by-case depending on the business needs.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>caching</category>
      <category>vue</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Step by step estimation guide</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Sun, 28 Mar 2021 13:49:25 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/step-by-step-estimation-guide-57no</link>
      <guid>https://dev.to/alphpkeemik/step-by-step-estimation-guide-57no</guid>
      <description>&lt;h2&gt;
  
  
  Why this article
&lt;/h2&gt;

&lt;p&gt;At some point, as a developer, each one of us has had to estimate something. Sometimes estimation is easy, sometimes hard. Easy when you know and hard when there is a lot of unknowns. And it does not matter if you are already using PERT or voting for #NoEstimates.&lt;/p&gt;

&lt;p&gt;With this article, I want to give a simple step-by-step guide to those who are just starting or struggling with it.&lt;/p&gt;

&lt;p&gt;But note! This document bases on subjective personal experiences. Figures are exemplary and depend highly on a "bunch of work" to be estimated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preliminary estimation
&lt;/h2&gt;

&lt;p&gt;A project manager, team lead, architect, etc., walk to you (or slacks, emails, zooms) and ask for an estimation.&lt;/p&gt;

&lt;p&gt;1) Take a deep breath, move your mind off from current work and make a preliminary estimation &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an hour,&lt;/li&gt;
&lt;li&gt;a day,&lt;/li&gt;
&lt;li&gt;a week,&lt;/li&gt;
&lt;li&gt;a month,&lt;/li&gt;
&lt;li&gt;much more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Make yourself and the person who requests the estimation aware of the preliminary estimation and therefore the inaccuracy of the assessment: &lt;/p&gt;

&lt;p&gt;b) magnitude &lt;strong&gt;1 hour&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;30 seconds spent - &lt;strong&gt;preliminary estimation&lt;/strong&gt;, &lt;/li&gt;
&lt;li&gt;5 minutes spent -  &lt;strong&gt;estimation&lt;/strong&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;c) magnitude &lt;strong&gt;100 hours&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 minutes spent - &lt;strong&gt;black magic&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;1 hour spent - &lt;strong&gt;preliminary estimation&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;10 hours spent - &lt;strong&gt;estimation&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3)  Consult with the estimation questioner about the need to spend more time for preliminary estimation or/and estimation. &lt;/p&gt;

&lt;p&gt;4) Make a list of key points based on that black magic / preliminary estimation - a &lt;strong&gt;technical specification&lt;/strong&gt; skeleton.&lt;/p&gt;

&lt;p&gt;In my opinion, estimation makes us faster developers by forcing us to compose functionality beforehand in our minds - &lt;strong&gt;technical specification&lt;/strong&gt;  - thus spearing time in the future, otherwise spending of false keystrokes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estimation
&lt;/h2&gt;

&lt;p&gt;The estimation questioner has confirmed preliminary extra time to be spent on getting a more detailed estimation.&lt;/p&gt;

&lt;p&gt;Finish the &lt;strong&gt;technical specification&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;magnitude &lt;strong&gt;1 hour&lt;/strong&gt; - 2-3 sentences;&lt;/li&gt;
&lt;li&gt;magnitude &lt;strong&gt;100 hours&lt;/strong&gt; - at least two documents: 

&lt;ul&gt;
&lt;li&gt;to client - &lt;strong&gt;adjusted functional requirements&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;to developer - &lt;strong&gt;technical specification&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adjusted functional requirements&lt;/strong&gt; are a mirrored-back and specified explanation to a customer about this "bunch of work" outcome. &lt;br&gt;
Estimation must also include testing, documentation, and communication! &lt;/p&gt;

&lt;h2&gt;
  
  
  Work
&lt;/h2&gt;

&lt;p&gt;Follow the &lt;strong&gt;technical specification&lt;/strong&gt; given in the estimation stage.&lt;br&gt;
If you can't follow it or it does not seem complete, notify the estimation questioner ASAP, and then you can decide together either &lt;strong&gt;to move back to the estimation stage&lt;/strong&gt; or not. Similarly, when bugs are reported back by any party, weigh if it is a missing initially planned feature or new feature request.&lt;/p&gt;

</description>
      <category>estimation</category>
      <category>estimating</category>
      <category>pert</category>
      <category>noestimates</category>
    </item>
    <item>
      <title>Improving quality with Git CLI and PhpStorm</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Fri, 08 Jan 2021 17:14:49 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/improving-quality-with-git-cli-and-phpstorm-27dc</link>
      <guid>https://dev.to/alphpkeemik/improving-quality-with-git-cli-and-phpstorm-27dc</guid>
      <description>&lt;p&gt;Bugs are an inevitable part of software and mistakes are an inevitable part of being a human. That can't be denied but should be dealt with. In this post I want to show how I have learned to make lesser mistakes when making code changes and committing them to Git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Always check your commit

&lt;ul&gt;
&lt;li&gt;Use the command line&lt;/li&gt;
&lt;li&gt;Or use PhpStorm&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Use UI tool for merging&lt;/li&gt;

&lt;li&gt;Don't be over confident&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔍 Always check your commit
&lt;/h2&gt;

&lt;p&gt;You have made some changes and you are ready to commit them. But maybe you were distracted by some event during development or you don't feel your best today. Check and double check what you are committing!&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 Use the command line
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git diff --staged&lt;/code&gt; are the best commands for that. &lt;br&gt;
&lt;code&gt;git status&lt;/code&gt; shows you what files changes are ready to commit. In the example there are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;two changes staged - ready to commit and &lt;/li&gt;
&lt;li&gt;two changes not staged:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;you@computer:path/to/your/project&lt;span class="nv"&gt;$ &lt;/span&gt;git status
On branch master
Your branch is up to &lt;span class="nb"&gt;date &lt;/span&gt;with &lt;span class="s1"&gt;'origin/master'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Changes to be committed:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git reset HEAD &amp;lt;file&amp;gt;..."&lt;/span&gt; to unstage&lt;span class="o"&gt;)&lt;/span&gt;

        deleted:    assets/js/configurator/MessageFactory.js
        modified:   assets/js/tests/configurator/base_logic.test.js

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git checkout -- &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;

        modified:   assets/js/tests/configurator/base_logic.test.js

Untracked files:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to include &lt;span class="k"&gt;in &lt;/span&gt;what will be committed&lt;span class="o"&gt;)&lt;/span&gt;

        assets/js/tests/file_is_added.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;☝ Note that &lt;em&gt;base_logic.test.js&lt;/em&gt; is in both states!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git diff --staged&lt;/code&gt; shows changes to be committed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;you@computer:path/to/your/project&lt;span class="nv"&gt;$ &lt;/span&gt;git diff &lt;span class="nt"&gt;--staged&lt;/span&gt;
diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/assets/js/configurator/MessageFactory.js b/assets/js/configurator/MessageFactory.js
deleted file mode 100644
index e63cfde..0000000
&lt;span class="nt"&gt;---&lt;/span&gt; a/assets/js/configurator/MessageFactory.js
+++ /dev/null
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,17 +0,0 @@
-&lt;span class="s2"&gt;"use strict"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
-
&lt;span class="nt"&gt;-class&lt;/span&gt; MessageFactory extends Module &lt;span class="o"&gt;{&lt;/span&gt;
- truncated &lt;span class="k"&gt;for &lt;/span&gt;example
-&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;-module&lt;/span&gt;.exports &lt;span class="o"&gt;=&lt;/span&gt; MessageFactory&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="se"&gt;\ &lt;/span&gt;No newline at end of file
diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/assets/js/tests/configurator/base_logic.test.js b/assets/js/tests/configurator/base_logic.test.js
index 940372a..cb9256d 100644
&lt;span class="nt"&gt;---&lt;/span&gt; a/assets/js/tests/configurator/base_logic.test.js
+++ b/assets/js/tests/configurator/base_logic.test.js
@@ &lt;span class="nt"&gt;-6&lt;/span&gt;,7 +6,7 @@ chai.should&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 chai.use&lt;span class="o"&gt;(&lt;/span&gt;sinonChai&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 describe&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Configurator'&lt;/span&gt;, &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
-    describe&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Base Logic'&lt;/span&gt;, &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
+    describe&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Row is changed'&lt;/span&gt;, &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="nb"&gt;let &lt;/span&gt;MainLoader &lt;span class="o"&gt;=&lt;/span&gt; require&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./main_loader.js'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="nb"&gt;let &lt;/span&gt;errorMessage &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Not enough parents or too many child products selected!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         describe&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'simple'&lt;/span&gt;, &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝ &lt;a href="https://johnkary.net/blog/git-add-p-the-most-powerful-git-feature-youre-not-using-yet/" rel="noopener noreferrer"&gt;Note that there is a easy way to skip some of the changes when staging&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 Or use PhpStorm
&lt;/h2&gt;

&lt;p&gt;Sometimes there are too many or complex changes that &lt;code&gt;git diff&lt;/code&gt; is not enough. Most IDE's have views for helping to understand what you have changed. &lt;br&gt;
☝ &lt;a href="https://medium.com/better-programming/why-you-should-write-small-git-commits-c9a042737aa6" rel="noopener noreferrer"&gt;You should always make commits as small as possible&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To see only added changed files in the project tree, select "Default Changelist" from the project menu:&lt;br&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%2Fi%2Fuiywvafl74palc859tol.jpg" 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%2Fi%2Fuiywvafl74palc859tol.jpg" alt="Selecting Default Changelist" width="800" height="362"&gt;&lt;/a&gt;&lt;br&gt;
After selecting "Default Changelist", IDE displays a list of changed and added files, staged for commit:&lt;br&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%2Fi%2Fp63opt4crznle2pujrkz.jpg" 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%2Fi%2Fp63opt4crznle2pujrkz.jpg" alt="Default Changelist view" width="649" height="482"&gt;&lt;/a&gt;&lt;br&gt;
☝ PhpStorm shows here only changed and new files that are added to git for committing (staged) and not deleted files.&lt;/p&gt;

&lt;p&gt;For seeing all files (changed, added, deleted), use Version Control Window:&lt;br&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%2Fi%2Feoo25qb1d27f7xsmvpml.jpg" 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%2Fi%2Feoo25qb1d27f7xsmvpml.jpg" alt="Opening Version Control Window" width="800" height="226"&gt;&lt;/a&gt;&lt;br&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%2Fi%2F8h23liwkk35oexgmqwd6.jpg" 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%2Fi%2F8h23liwkk35oexgmqwd6.jpg" alt="Version Control Window" width="800" height="212"&gt;&lt;/a&gt;&lt;br&gt;
Right click on a file to see more actions including "Show Diff".&lt;/p&gt;

&lt;p&gt;In opened file window, IDE shows you changes made to file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;line added on row 2 ,&lt;/li&gt;
&lt;li&gt;line removed between 4-5, &lt;/li&gt;
&lt;li&gt;and changed on row 9.
&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%2Fi%2Fjzt9nx5qyy8pxm9l49n9.png" alt="IDE file changes" width="800" height="415"&gt;
When hovering the mouse on a change hinting mark (green rectangle, red triangle, blue rectangle), IDE shows the previous version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;☝ Be aware that IDE does not differ changes that are and are not staged for commit!&lt;/p&gt;

&lt;p&gt;You can jump to the next change in a longer file using the keyboard:&lt;br&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%2Fi%2Frdmrxu8pgtkhdvd5mce0.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%2Fi%2Frdmrxu8pgtkhdvd5mce0.png" alt="IDE jump to next change" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also compare the full file with "Compare with Same Repository Version" action:&lt;br&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%2Fi%2Fhulrn1alz7grmv202r72.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%2Fi%2Fhulrn1alz7grmv202r72.png" alt="Compare with Same Repository Version" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  ⚡ Use UI tool for merging
&lt;/h2&gt;

&lt;p&gt;Sometimes merge conflicts happen, either when you are squash merging to master, rebasing master to your feature branch or popping changes from stash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;you@computer:path/to/your/project&lt;span class="nv"&gt;$ &lt;/span&gt;git merge &lt;span class="nt"&gt;--squash&lt;/span&gt; origin/KEY-123
Auto-merging templates/configurator/product_configurator.twig
Auto-merging public/build/configurator.product_configurator.js
CONFLICT &lt;span class="o"&gt;(&lt;/span&gt;content&lt;span class="o"&gt;)&lt;/span&gt;: Merge conflict &lt;span class="k"&gt;in &lt;/span&gt;public/build/configurator.product_configurator.js
Auto-merging assets/js/tests/configurator/main_loader.js
Auto-merging assets/js/configurator/Data.js
CONFLICT &lt;span class="o"&gt;(&lt;/span&gt;content&lt;span class="o"&gt;)&lt;/span&gt;: Merge conflict &lt;span class="k"&gt;in &lt;/span&gt;assets/js/configurator/Data.js
Squash commit &lt;span class="nt"&gt;--&lt;/span&gt; not updating HEAD
Automatic merge failed&lt;span class="p"&gt;;&lt;/span&gt; fix conflicts and &lt;span class="k"&gt;then &lt;/span&gt;commit the result.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are not familiarized yourself with vimdiff, then your tool for solving merge conflicts should be IDE.&lt;br&gt;
Use the resolve conflicts action and continue from there and don't be afraid - remember you can always start over if something goes wrong - that's the beauty of Git.&lt;br&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%2Fi%2F0qpvu7bwmfsh4nsa7sc5.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%2Fi%2F0qpvu7bwmfsh4nsa7sc5.png" alt="Opening Resolve Conflicts" width="800" height="168"&gt;&lt;/a&gt;&lt;br&gt;
☝ When there is a possibility that &lt;code&gt;stash pop&lt;/code&gt; produces merge conflicts, use &lt;code&gt;stash apply&lt;/code&gt; instead!&lt;br&gt;
☝ Resolve Conflicts action is only available if any merge conflicts are waiting to be resolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  💣 Don't be overconfident
&lt;/h2&gt;

&lt;p&gt;During the time between starting and finishing this article I did not bother to check the diff from &lt;code&gt;git --squash merge&lt;/code&gt; from really small change and the result after commit and push build error occurred:&lt;br&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%2Fi%2Fgjpchu0rdhw6kgro3kcu.jpg" 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%2Fi%2Fgjpchu0rdhw6kgro3kcu.jpg" alt="Don't be overconfident" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Postscript
&lt;/h2&gt;

&lt;p&gt;When you have come so far, you will reach even further. Keep going! &lt;/p&gt;

</description>
      <category>git</category>
      <category>phpstorm</category>
      <category>codequality</category>
      <category>howto</category>
    </item>
    <item>
      <title>Vuex explained through PHP</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Wed, 06 Jan 2021 17:35:59 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/vuex-explained-through-php-22mb</link>
      <guid>https://dev.to/alphpkeemik/vuex-explained-through-php-22mb</guid>
      <description>&lt;p&gt;Vue.js was not around when I and many other developers started to code years ago. Even jQuery was just released. And if you have been using jQuery in front-end as a (PHP backend) developer, understanding all the aspects of Vuex flow could be tricky.&lt;/p&gt;

&lt;p&gt;Let's see first this example from real 2007 code, still in production:&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;$myrow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;mysql_fetch_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;mysql_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;"select * from albums where number LIKE '"&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;mysql_real_escape_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'number'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"'"&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;b&amp;gt;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$myrow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' album &amp;amp;#39;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$myrow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'&amp;amp;#39;&amp;lt;/b&amp;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 simple PHP page, data is taken from database and printed out.&lt;/p&gt;

&lt;p&gt;Now let's try to write it in Vuex + Vue component like flow in PHP:&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="c1"&gt;# VUEX&lt;/span&gt;
&lt;span class="nv"&gt;$GLOBALS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'album_data'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;actionLoadCurrentAlbum&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;$number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;## Backend API call&lt;/span&gt;
    &lt;span class="nv"&gt;$myrow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;mysql_fetch_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;mysql_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"select * from albums where number LIKE '"&lt;/span&gt;
        &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;mysql_real_escape_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"'"&lt;/span&gt;
    &lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nf"&gt;mutationCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$myrow&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;mutationCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;?array&lt;/span&gt; &lt;span class="nv"&gt;$albumData&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$GLOBALS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'album_data'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$albumData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getCurrentAlbum&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$GLOBALS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'album_data'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Vue Component&lt;/span&gt;
&lt;span class="c1"&gt;## Script&lt;/span&gt;
&lt;span class="nf"&gt;actionLoadCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'number'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$albumData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;## template&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;b&amp;gt;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$albumData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' album &amp;amp;#39;'&lt;/span&gt; 
    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;stripslashes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$albumData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'number'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'&amp;amp;#39;&amp;lt;/b&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in JavaScript as Vuex and Vue component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vuex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;album_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;loadCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://example.com/some/path/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;setCurrentAlbum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&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="na"&gt;mutations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;albumData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;album_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;albumData&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;getCurrentAlbum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;album_data&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="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;album&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;beforeCreate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loadCurrentAlbum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;album_data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;b&amp;gt;{{ album_data.name }} album &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;#39;{{ album_data.number }}&amp;amp;#39;&amp;lt;/b&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have &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%2Fz7h7qeiexp4q7ea9p6nf.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%2Fz7h7qeiexp4q7ea9p6nf.png" alt="Vuex" width="701" height="551"&gt;&lt;/a&gt; example translated from year 2007 PHP page.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>vuex</category>
      <category>php</category>
      <category>templating</category>
    </item>
    <item>
      <title>A memory leak in Doctrine</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Mon, 28 Dec 2020 11:28:35 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/a-memory-leak-in-doctrine-455n</link>
      <guid>https://dev.to/alphpkeemik/a-memory-leak-in-doctrine-455n</guid>
      <description>&lt;p&gt;When building a new PHP application with Doctrine (doctrine/orm 2.7.4), our team discovered that in some long-running commands memory usage was building up. &lt;br&gt;
We went through the basic checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application is running in production mode - our experience has shown, when is not, then Doctrine SQL logger could eat up memory - checked.&lt;/li&gt;
&lt;li&gt;Doctrine clear is called regularly - when it's not, then objects persist in Doctrine internal in-memory cache - checked.&lt;/li&gt;
&lt;li&gt;No other code in our application was not obviously &lt;a href="https://dev.to/alphpkeemik/write-clean-good-code-correct-caching-in-php-26k5"&gt;building its own memory cache&lt;/a&gt; - checked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Due to the amount of data generated by the long-running process, we weren't able to use obvious choices as &lt;a href="https://blackfire.io" rel="noopener noreferrer"&gt;Blackfire&lt;/a&gt;.&lt;br&gt;
After a little googling we decided to use &lt;a href="https://github.com/arnaud-lb/php-memory-profiler" rel="noopener noreferrer"&gt;php-memprof&lt;/a&gt; as a tool to collect data. Sadly there was no expert to take to read KCacheGrind so we dumped data as an array using &lt;code&gt;memprof_dump_array&lt;/code&gt; and find by &lt;a href="https://github.com/alphpkeemik/php-memory-profiler-array-analyser" rel="noopener noreferrer"&gt;analysing output&lt;/a&gt; that memory is building up somewhere in Doctrine.&lt;/p&gt;

&lt;p&gt;After good old-fashioned "comment out some code to see if the error disappears" we discovered that the memory was building up due to usage of &lt;code&gt;Doctrine\ORM:Query::getOneOrNullResult&lt;/code&gt; in &lt;a href="https://github.com/alphpkeemik/queue-command/commit/d29069293d9608e375f7e20e4e880c7bf9206b01" rel="noopener noreferrer"&gt;our shared library&lt;/a&gt;. &lt;br&gt;
The memory leak was tough so subtle, that it increased only ~20MB on every thousand calls. &lt;/p&gt;

&lt;p&gt;After &lt;a href="https://github.com/alphpkeemik/queue-command/commit/d29069293d9608e375f7e20e4e880c7bf9206b01" rel="noopener noreferrer"&gt;changing getOneOrNullResult to execute&lt;/a&gt; memory leak disappeared.&lt;/p&gt;

&lt;p&gt;Our application is now working smoothly but the problem in Doctrine still needs to be tracked down.&lt;/p&gt;

</description>
      <category>memoryleak</category>
      <category>doctrine</category>
      <category>php</category>
    </item>
    <item>
      <title>Write clean &amp; good code - correct caching in PHP</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Mon, 28 Dec 2020 10:31:42 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/write-clean-good-code-correct-caching-in-php-26k5</link>
      <guid>https://dev.to/alphpkeemik/write-clean-good-code-correct-caching-in-php-26k5</guid>
      <description>&lt;p&gt;Another caching article you think and feel &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F3%2F3f%2FFacepalm_jeez.jpg%2F128px-Facepalm_jeez.jpg" 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%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2F3%2F3f%2FFacepalm_jeez.jpg%2F128px-Facepalm_jeez.jpg" title="🤦" alt="alt text" width="128" height="96"&gt;&lt;/a&gt;. And &lt;a href="https://medium.com/vimeo-engineering-blog/its-not-legacy-code-it-s-php-1f0ee0462580" rel="noopener noreferrer"&gt;who writes PHP these days&lt;/a&gt;. But wait, it's not only about caching and PHP, these are only used as examples here.&lt;/p&gt;

&lt;p&gt;When writing on another topic a need arose to point out one extra thing in writing a &lt;a href="http://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html" rel="noopener noreferrer"&gt;clean&lt;/a&gt; and &lt;a href="https://codinginfinite.com/ten-best-programming-practices-tips-tricks" rel="noopener noreferrer"&gt;good&lt;/a&gt; code: &lt;strong&gt;don't invite the wheel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider example&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;Foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$bar&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bar&lt;/span&gt; &lt;span class="nv"&gt;$bar&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;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;&lt;span class="p"&gt;;&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;getBar&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;$someValue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;mixed&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;key_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$someValue&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;cache&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$someValue&lt;/span&gt;&lt;span class="p"&gt;]&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="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBySomeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$someValue&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$someValue&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;It seems very easy to code and test. So let's write it. But what about cache invalidation and memory usage?&lt;br&gt;
So let's add them... by using library. For PHP is Monolog the standard, so&lt;br&gt;
&lt;code&gt;composer install monolog/monolog&lt;/code&gt;&lt;br&gt;
and change &lt;code&gt;Foo&lt;/code&gt; to&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;Foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$cacheItemPool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$bar&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;CacheItemPoolInterface&lt;/span&gt; &lt;span class="nv"&gt;$cacheItemPool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;Bar&lt;/span&gt; &lt;span class="nv"&gt;$bar&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;cacheItemPool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$cacheItemPool&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;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;&lt;span class="p"&gt;;&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;resolve&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;$someValue&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"bar/&lt;/span&gt;&lt;span class="nv"&gt;$someValue&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$cacheItem&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="n"&gt;cacheItemPool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cacheKey&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="nv"&gt;$cacheItem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isHit&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$cacheItem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&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;bar&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBySomeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$someValue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nv"&gt;$cacheItem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expiresAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'P1D'&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;cacheItemPool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cacheItem&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;$cacheItem&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&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;



</description>
      <category>php</category>
      <category>caching</category>
      <category>cleancode</category>
      <category>goodcode</category>
    </item>
    <item>
      <title>Testing doctrine migration in Symfony project</title>
      <dc:creator>Mati Andreas</dc:creator>
      <pubDate>Thu, 13 Jun 2019 08:23:20 +0000</pubDate>
      <link>https://dev.to/alphpkeemik/testing-doctrine-migration-in-symfony-project-3n42</link>
      <guid>https://dev.to/alphpkeemik/testing-doctrine-migration-in-symfony-project-3n42</guid>
      <description>&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Checkout to the master branch &lt;br&gt;
&lt;code&gt;git checkout master&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update database to match current doctrine schema, also removing excess tables &lt;br&gt;
&lt;code&gt;php bin/console d:s:u --force --complete&lt;/code&gt;, where &lt;code&gt;d:s:u&lt;/code&gt; is automatic short version of &lt;code&gt;doctrine:schema:update&lt;/code&gt;, provided by Symfony console.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NB! It deletes all tables from the database that are not in doctrine schema!&lt;br&gt;
If you want to keep some tables (migration table could also be removed), then run &lt;code&gt;php bin/console d:s:u --dump-sql --complete&lt;/code&gt;&lt;br&gt;
do display excess  tables, remove them manually and then run &lt;code&gt;php bin/console d:s:u --force&lt;/code&gt; to make schema up-to-date with master.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add all migrations&lt;code&gt;php bin/console d:m:v --all --add -n&lt;/code&gt;&lt;br&gt;
where &lt;code&gt;d:m:v&lt;/code&gt; is automatic short version of &lt;code&gt;doctrine:migrations:version&lt;/code&gt;, provided by Symfony console.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Checkout to your feature branch &lt;code&gt;git checkout KEY-123&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run migrations &lt;code&gt;php bin/console d:m:m -n&lt;/code&gt;, where &lt;code&gt;d:m:m&lt;/code&gt; is automatic short version of &lt;code&gt;doctrine:migrations:migrate&lt;/code&gt;, provided by Symfony console.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>php</category>
      <category>symfony</category>
      <category>doctrine</category>
      <category>migrations</category>
    </item>
  </channel>
</rss>
