<?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: Sasha Blagojevic</title>
    <description>The latest articles on DEV Community by Sasha Blagojevic (@blackcat_dev).</description>
    <link>https://dev.to/blackcat_dev</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%2F34714%2F233b9ff1-93a2-4a2c-9751-20971ad0ef41.jpg</url>
      <title>DEV Community: Sasha Blagojevic</title>
      <link>https://dev.to/blackcat_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blackcat_dev"/>
    <language>en</language>
    <item>
      <title>Go for PHP or Any Other Developer</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Mon, 27 Jan 2020 10:23:01 +0000</pubDate>
      <link>https://dev.to/jsguru_io/go-for-php-or-any-other-developer-4jbb</link>
      <guid>https://dev.to/jsguru_io/go-for-php-or-any-other-developer-4jbb</guid>
      <description>&lt;p&gt;&lt;span&gt;Long time no read! I’ve been quite busy building awesome stuff for our clients so I haven’t had the time to write in quite a while. I still don’t have it to be frank, but this is gonna be a somewhat short read so I managed to squeeze it into my schedule.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="h.i61btza3x0es"&gt;&lt;span&gt;TLDR&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;If you’re not interested in the story behind this &lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt; just skip to the end. I highly recommend covering these resources if you’re considering learning&lt;/span&gt;&lt;span&gt; GO.&lt;/span&gt;&lt;sup&gt;[c]&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id="h.nzbnrmddxobs"&gt;&lt;span&gt;Why Go suddenly?&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;I’ve been helping out on an awesome big data / IoT project which is powered by none other then GO! Our client was coming from a Python background and when you add the terms Big Data and Internet of Things to this mix you can clearly see why GO is a natural fit for this project. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;It has been really interesting switching from PHP to Go lang. I must admit at the beginning it was a bit of a challenge to wrap my head around all of the different concepts. Not only was I switching from a scripting language to a compiled one, but Go lang is also a functional language, where as PHP supports both the &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://sasablagojevic.com/object-oriented-programming&amp;amp;sa=D&amp;amp;ust=1580123772171000"&gt;Functional&lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://sasablagojevic.com/object-oriented-programming&amp;amp;sa=D&amp;amp;ust=1580123772171000"&gt; and &lt;/a&gt;&lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://sasablagojevic.com/object-oriented-programming&amp;amp;sa=D&amp;amp;ust=1580123772172000"&gt;Object Oriented Paradigm&lt;/a&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;To add fuel to the fire GO lang has its own twist with its concurrency model - &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://gobyexample.com/goroutines&amp;amp;sa=D&amp;amp;ust=1580123772172000"&gt;goroutines&lt;/a&gt;&lt;/span&gt;&lt;span&gt; and &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://gobyexample.com/channels&amp;amp;sa=D&amp;amp;ust=1580123772172000"&gt;channels&lt;/a&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;When your client demands GO lang as the power train you can be pretty sure it’s not going to be a walk in the park, you can expect it to be a high performance / high load type of a project so there will be no cutting corners and optimization needs to be on your mind all the time!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;I’d consider my role in this project as kind of a sheepdog since I was setting the path and guiding our junior developers as they do tend to behave like lost sheep sometimes. Client being the shepherd in this analogy I guess lol.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="h.mzc1zd1v7tsl"&gt;&lt;span&gt;Major Differences between PHP and GO&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;Aside from the obvious fact that GO is a compiled language these are some of the major differences: &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span&gt;Switch&lt;/span&gt;&lt;span&gt; statement does not fall through by default, you have to explicitly add the fallthrough keyword&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt;For&lt;/span&gt;&lt;span&gt; is the same as &lt;/span&gt;&lt;span&gt;While&lt;/span&gt;&lt;span&gt;, that’s the only loop keyword&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;span&gt;There are no Classes / Objects, there are &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://gobyexample.com/structs&amp;amp;sa=D&amp;amp;ust=1580123772174000"&gt;Structs&lt;/a&gt;&lt;/span&gt;&lt;span&gt; which have some of the behaviour, they can have members and methods defined on them&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt;There are no explicit access modifiers like &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://www.php.net/manual/en/language.oop5.visibility.php&amp;amp;sa=D&amp;amp;ust=1580123772174000"&gt;public, protected and private&lt;/a&gt;&lt;/span&gt;&lt;span&gt; but there is a naming convention&lt;/span&gt;&lt;span&gt;. If you declare a variable / type  / function lowercase first it will be treated as private on the package level, if you define a member / method lowercase first on a Struct it will not be accessible publicly. On the other hand if you write them uppercase first it will be publicly accessible.&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt;Since there are no Classes there is no Inheritance, but we can achieve Polymorphism because GO has &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go&amp;amp;sa=D&amp;amp;ust=1580123772175000"&gt;Interfaces&lt;/a&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt;Interfaces in GO have their own twist and are a bit different than in PHP. While in PHP you have to specify which class implements what interface in GO every data type implements an empty interface{} by default. You can think of this interface{} as something similar to &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://www.typescriptlang.org/docs/handbook/basic-types.html%23any&amp;amp;sa=D&amp;amp;ust=1580123772175000"&gt;TypeScript’s any&lt;/a&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt; When you create your own custom interfaces you will need to add the implementation of these methods on the desired structs. GO will not check if the interfaces are satisfied during the build process, unlike some other compiled languages, it will be evaluated during runtime when the actual method is called, if you call the method on a &lt;/span&gt;&lt;span&gt;Struct&lt;/span&gt;&lt;span&gt; that does not satisfy the type hinted &lt;/span&gt;&lt;span&gt;Interface&lt;/span&gt;&lt;span&gt; your application will fail.&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span&gt;There are no exceptions in a traditional sense, there are no try / catch blocks although there is a &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://github.com/golang/go/issues/32437&amp;amp;sa=D&amp;amp;ust=1580123772176000"&gt;proposal to introduce try&lt;/a&gt;&lt;/span&gt;&lt;span&gt;. What we have though are &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://blog.golang.org/defer-panic-and-recover&amp;amp;sa=D&amp;amp;ust=1580123772176000"&gt;panics and recover&lt;/a&gt;&lt;/span&gt;&lt;span&gt;, but recover can only be used to recover from a panic that happened on different goroutine. How do we handle errors then? Well, GO functions have multiple return values. Usually the first value is the desired result and the second value is the error if there is any, otherwise nil. &lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span&gt;I’m of the opinion that each language should be written in its idiomatic way, that is the way to get the most out of the language and in addition your code will be easily understandable by the wider community and new developers that might join you or replace you later on. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;That’s the whole point behind language style guides, admittedly some have a more strict some less, some don’t have one at all - PHP didn’t have one for a long time before PSRs came into play and our community was honestly a mess, a million of different styles and approaches that just unnecessarily added to our cognitive load. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;That being said this is a list of resources that you most definitely should read if you want to write idiomatic Go and follow community best practices:&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="h.n614kz22bv9f"&gt;&lt;span&gt;Must Read / Watch List&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://github.com/golang/go/wiki/CodeReviewComments%23package-names&amp;amp;sa=D&amp;amp;ust=1580123772178000"&gt;Official Go Code Review Comments&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://github.com/golang-standards/project-layout&amp;amp;sa=D&amp;amp;ust=1580123772178000"&gt;Go Standard Project Layout (Community)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1&amp;amp;sa=D&amp;amp;ust=1580123772178000"&gt;Ben Johnson - Standard Package Layout (Community)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://blog.golang.org/package-names&amp;amp;sa=D&amp;amp;ust=1580123772179000"&gt;Go Docs - Package Naming&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://peter.bourgon.org/go-best-practices-2016/&amp;amp;sa=D&amp;amp;ust=1580123772179000"&gt;Peter Bourgon - Go Best Practices Six Years In (QCon London 2016)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://peter.bourgon.org/go-for-industrial-programming/&amp;amp;sa=D&amp;amp;ust=1580123772180000"&gt;Peter Bourgon - Go For Industrial Programming (GopherCon EU 2018)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://www.youtube.com/watch?v%3DMzTcsI6tn-0&amp;amp;sa=D&amp;amp;ust=1580123772180000"&gt;Ashley McNamara + Brian Ketelsen. Go best practices (GopherCon Russia 2018)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://talks.golang.org/2014/names.slide%231&amp;amp;sa=D&amp;amp;ust=1580123772180000"&gt;Andrew Gerrard GoLand Talks 2014 (Google)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;&lt;a href="https://www.google.com/url?q=https://talks.golang.org/2014/organizeio.slide%231&amp;amp;sa=D&amp;amp;ust=1580123772180000"&gt;David Crawshaw - Organizing Go Code 2014 (Google)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>php</category>
    </item>
    <item>
      <title>Running multiple versions of PHP on MacOS with Homebrew</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Wed, 18 Dec 2019 09:09:09 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/running-multiple-versions-of-php-on-macos-with-homebrew-1hj7</link>
      <guid>https://dev.to/blackcat_dev/running-multiple-versions-of-php-on-macos-with-homebrew-1hj7</guid>
      <description>&lt;p&gt;I'm a big proponent of Baby Steps Doctrine, yep I think I just coined this term. What do I mean by that? Short version I like keeping things simple, now let's get to the long one.&lt;/p&gt;

&lt;p&gt;I don't like adding unnecessary complexity if there is no need for that. I've noticed that people often add complexity to their systems and their workflow just because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Everybody else seems to be doing it&lt;/li&gt;
&lt;li&gt;It's a new shiny technology so it means it must be the next best solution (remember the SQL is dead long live NoSQL, now it's Restful is dead long live GraphQL, tomorrow it will be something else, yadda yadda yadda)&lt;/li&gt;
&lt;li&gt;Facebook / Google / Some other big company is doing it, therefore, it must be a best practice and I should be doing it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;We should be adding complexity only if there is an upside to that trade-off&lt;/strong&gt;. Just because it works in the case of some big company does not mean it adds value to the &lt;em&gt;mom and pop store&lt;/em&gt; you're working for, or the side hustle you're working on.&lt;/p&gt;

&lt;p&gt;Does running and configuring Docker really add value if you're working in a small team 1-5 people or even worse if you're working alone and you're not running a distributed system? &lt;/p&gt;

&lt;p&gt;Maybe Homestead / Vagrant is enough? Or maybe you don't even need that and can use your local dev machine?&lt;/p&gt;

&lt;p&gt;When I start out coding as my first step I like to use my local dev machine, a 2017 Macbook Pro. With time different projects for various reasons required different PHP versions so I had to run multiple PHP versions on my local machine.&lt;/p&gt;

&lt;p&gt;Thanks to Homebrew you can do it fairly easy. For newer PHP versions like 7.3 it's just running: &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;brew install php@7.3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For PHP 7.0/5.6 that are deprecated and not officially supported by the Homebrew team you have one additional step, you need to add &lt;a title="Homebrew Tap" href="https://docs.brew.sh/Taps" rel="noopener"&gt;a tap&lt;/a&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap exolnet/homebrew-deprecated

brew install php@7.0

brew install php@5.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you install PHP with homebrew the default location should be &lt;strong&gt;/usr/local/Cellar/php@7.3/&lt;/strong&gt; and there should be a symbolic link to &lt;strong&gt;/usr/local/bin/opt/php@7.3/&lt;/strong&gt;. Check out my &lt;a title="PHP location on macOS when installed with Homebrew" href="https://stackoverflow.com/questions/48585578/where-does-homebrew-install-php-on-mac-high-sierra/48629909#48629909" rel="noopener"&gt;Stack Overflow response&lt;/a&gt; for more info on this topic.&lt;/p&gt;

&lt;p&gt;To change the version of the PHP used by your shell you need to add it to your path by running:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'export PATH="/usr/local/opt/php@7.3/bin:$PATH"' &amp;gt;&amp;gt; ~/.bash_profile
echo 'export PATH="/usr/local/opt/php@7.3/sbin:$PATH"' &amp;gt;&amp;gt; ~/.bash_profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: This won't work if you're using the new &lt;em&gt;zsh&lt;/em&gt; shell which came with the Catalina update because it ignores &lt;em&gt;.bash_profile&lt;/em&gt; and &lt;em&gt;.bashrc &lt;/em&gt;configuration files. To continue using &lt;em&gt;bash&lt;/em&gt; as your default shell and to upgrade it to a newer version check out this &lt;a title="Upgrade bash on macOS" href="https://itnext.io/upgrading-bash-on-macos-7138bd1066ba" rel="noopener"&gt;awesome article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, what if you want to use a different version of PHP that's installed on your system? Well, you'd have to manually change your &lt;em&gt;.bash_profile&lt;/em&gt; to point to a different version.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH="/usr/local/opt/php@7.0/bin:$PATH"
export PATH="/usr/local/opt/php@7.0/sbin:$PATH"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing that manually multiple times a day can be a bit tedious so let's automate that. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;strong&gt;phpver&lt;/strong&gt; my small PHP binary script from &lt;a title="phpver script" href="https://gist.github.com/sasa-b/883fd9810f773e3e200bdf8ea073f93b" rel="noopener"&gt;Github gist&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Put it in &lt;strong&gt;/usr/local/bin&lt;/strong&gt; or somewhere else and make a symbolic link to &lt;strong&gt;/usr/local/bin&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Make it executable by running &lt;strong&gt;chmod +x /usr/local/bin/phpver&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can change your active PHP version by running &lt;strong&gt;phpver {version_number}&lt;/strong&gt; in your shell anywhere in the system. For example to change from version 7.3 to 7.0 you would just have to run &lt;strong&gt;phpver 7.0&lt;/strong&gt; and restart the terminal for the changes to take effect.&lt;br&gt;&lt;br&gt;That's it, hope this comes in handy to someone because it sure did to me.&lt;br&gt;&lt;br&gt;Have fun and keep coding! &lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Three Reasons Why You Should Visit Web Summer Camp</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Tue, 03 Sep 2019 20:35:09 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/three-reasons-why-you-should-visit-web-summer-camp-oac</link>
      <guid>https://dev.to/blackcat_dev/three-reasons-why-you-should-visit-web-summer-camp-oac</guid>
      <description>&lt;p&gt;Yes, I used one of those clickbait titles and no I'm not ashamed, not at all, because now that you've clicked you might as well read it, you obviously have no better things to do.&lt;/p&gt; 




&lt;p&gt;&lt;a title="Web Summer Camp Rovinj 2019" href="https://2019.websummercamp.com" rel="noopener"&gt;Web Summer Camp&lt;/a&gt; is a place where the nerds go to recuperate from all those Friday deploys, all those &lt;em&gt;just make it work we'll rewrite it properly later&lt;/em&gt;, all those&lt;em&gt; if it works don't refactor it doesn't matter it's written in Sanskrit&lt;/em&gt; moments or rather should I say decisions that we're left to live with.&lt;/p&gt;

&lt;p&gt;At least here, you'll be surrounded by like-minded experts and aspiring professionals who yearn for knowledge and ways to improve their craft. It won't take too much time to find a shoulder to cry on about your &lt;em&gt;legacy spaghetti-monster &lt;/em&gt;codebase that you have to deal with daily and if not you're one lucky bastard, you...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web Summer Camp is that good of an experience that I'm a tad bit selfish about it, it is the only conference I'm a little afraid of promoting and talking about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Knowledge&lt;/h3&gt;

&lt;p&gt;Rovinj Web Summer Camp has a really strong line-up. You will be able to attend workshops from industry experts on both software development and project management. You will get your hands dirty and go more in-depth than on regular conferences. &lt;/p&gt;

&lt;p&gt;I attended the PHP track because having to deal with a legacy codebase at my job I caught on the DDD(Domain Driven Design) bug because I witness every day what happens when you go the SDD route. It's not a coincidence it sounds so similar to STD because it's as equally bad. I'm talking about Sales Driven Design. A &lt;em&gt;code first - think later &lt;/em&gt;approach. Just glue the new feature on top, however you know, as long as we're getting new customers it's peachy. It doesn't matter it's making you're code unmaintainable, for Pete's sake it's increasing the sales! We will think about the maintainability later and this only ever happens when everything grinds to a halt and then, of course, the developers are the ones to blame it's the easy way out.&lt;/p&gt;

&lt;p&gt;When it comes to greenfield projects (thanks Pim for learning me a new phrase lol) my feeling is that HDD(Hype Driven Development) is the prevalent approach. We need that new shiny thing to be successful otherwise we are doomed! We need the X framework or the Y complex technology because scalability and a certain Z unicorn uses it. Surely with it, we will be as successful as they are, just look at their valuation. There's no other way to solve that particular problem even though we have 1 000 000 times fewer users and a developer team of 3, but John is on vacation so basically it's 2.&lt;/p&gt;

&lt;p&gt;&lt;a title="Stefan Priebsch Twitter Profile" href="https://twitter.com/spriebsch" rel="noopener"&gt;Stefan Priebsch&lt;/a&gt; did a great job teaching us the core concepts of Domain-Driven Design and his workshop was my favourite. It was an eye-opening experience for me. People, we are doing it all wrong! &lt;strong&gt;We are doing the things in the reverse order, we are trying to model the domain so it fits the technologies we decided to use, instead of picking the technologies that fit our domain.&lt;/strong&gt; Yes I know it's yesterday's news to a lot of you experienced guys and gals, but I'm new to this so bear with me and let me rant a bit. &lt;/p&gt;

&lt;p&gt;Kevin Dunglas' workshop plays into the previous sentiments. He and the Symfony team have solved the complex issue of real-time app communication between different clients be they mobile or web by using already available technologies like HTTP's Server Side Events. I didn't even know SSE existed. You see, sometimes we don't need the shiniest new thing SEE existed before Web Sockets. You're welcome for the brief web history lesson lol.&lt;/p&gt;

&lt;p&gt;Lastly, I really enjoyed the workshop by &lt;a title="Tomas Votruba Twitter Profile" href="https://twitter.com/VotrubaT" rel="noopener"&gt;Tomas Votruba&lt;/a&gt; and &lt;a title="Honza Mikeš Twitter Profile" href="https://twitter.com/mikes_honza" rel="noopener"&gt;Honza Mikeš&lt;/a&gt;. They built &lt;a title="Rector PHP" href="https://getrector.org/" rel="noopener"&gt;Rector PHP&lt;/a&gt; a great tool that automates the process of refactoring code. It's like meta-programming on steroids. I dared them to try and refactor an old method with lots of nasty if statements and nested array keys and they would've solved it if only the time had allowed it. You should definitely check their tool out or even maybe contribute if you're up to it!&lt;/p&gt;

&lt;h3&gt;Networking&lt;/h3&gt;

&lt;p&gt;I've met so many amazing people that I have to keep an excel sheet of their names and pictures because I suck at remembering names and I don't want them to get offended. Ask &lt;a title="Pim Elshof Twitter Profile" href="https://twitter.com/Pelshoff" rel="noopener"&gt;Pim Elshof&lt;/a&gt; if you don't believe me, I called him Tim like a gazillion of times. I'm joking about the sheet of course but I probably should do it. &lt;/p&gt;

&lt;p&gt;As &lt;a title="Mario Blažek Twitter Profile" href="https://twitter.com/phpanarchist" rel="noopener"&gt;Mario Blažek&lt;/a&gt; said, "Where would you get the opportunity to play pool with core contributor of Symfony &lt;a title="Nicolas Greekas Twitter Profile" href="https://twitter.com/nicolasgrekas" rel="noopener"&gt;Nicolas Grekas&lt;/a&gt;" or when would I get the opportunity to have a &lt;em&gt;romantic dinner*&lt;/em&gt; at the beach, on an island with &lt;a title="Zoran Twitter Profile" href="https://twitter.com/zoran_antolovic" rel="noopener"&gt;Zoran&lt;/a&gt;, &lt;a title="Pim Elshof Twitter Profile" href="https://twitter.com/Pelshoff" rel="noopener"&gt;Pim Elshof&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a title="Viking Twitter Profile" href="https://twitter.com/CEismar" rel="noopener"&gt;Claes&lt;/a&gt; my Viking half-brother and &lt;a title="Honza Mikeš Twitter Profile" href="https://twitter.com/mikes_honza" rel="noopener"&gt;Honza Mikeš&lt;/a&gt; the co-creator of &lt;a title="Rector PHP" href="https://getrector.org/" rel="noopener"&gt;Rector PHP&lt;/a&gt;. When I say &lt;em&gt;romantic dinner&lt;/em&gt; I mean eating like pigs and drinking beer under candles.&lt;/p&gt;

&lt;p&gt;Web Summer Camp is that good of an experience that I'm a tad bit selfish about it, it is the only conference I'm a little afraid of promoting and talking about. I mean don't get me wrong I want them to become bigger and better or whatever the goal of the organizers is, I just don't like sharing things that are precious to me. Aside from knowledge, I like to share knowledge.&lt;/p&gt;

&lt;p&gt;Truly, all three days I was feeling like I was visiting relatives at the seaside. I just felt at home somehow.&lt;/p&gt;

&lt;h3&gt;Fun, lots of fun&lt;/h3&gt;

&lt;p&gt;Web Summer Camp is a 3 day 24 hours a day event. Don't worry not all hours are mandatory, it's not an introverts hell. The organizers really go out of their way to make you feel welcome and not only facilitate the workshops but also entertain you after the workshops.&lt;/p&gt;

&lt;p&gt;What really made an impression on me was the fact that, let's call him &lt;em&gt;Chief Organizer,&lt;/em&gt; &lt;a title="Ivo Twitter Profile" href="https://twitter.com/ilukac" rel="noopener"&gt;Ivo&lt;/a&gt; personally greets everyone and stops for a chat. The rest of the guys and gals are awesome as well and kudos to them because it must have been exhausting being available to the attendees 24/7.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;off workshop&lt;/em&gt; program consisted of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beer powered panel with experts,&lt;/li&gt;
&lt;li&gt;Unconference,&lt;/li&gt;
&lt;li&gt;Two boat trips to nearby islands,&lt;/li&gt;
&lt;li&gt;3 drink ups and&lt;/li&gt;
&lt;li&gt;Everyday exercises (morning swims or runs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I mean come on now? Who else offers that level of attendee engagement?&lt;/p&gt;

&lt;h4&gt;Rovinj itself(bonus reason)&lt;br&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pVTNnXnl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/145/rovinj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pVTNnXnl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/145/rovinj.jpg" alt="Rovinj Old Town" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;..as if the three previous reasons were not enough to make you start filling up your piggy bank. Rovinj is a go-to place for architecture fans. The old town is breath taking! As a matter of fact, I first found out about the amazing architecture of Old Town Rovinj on a &lt;em&gt;beautiful places kinda &lt;/em&gt;Instagram page, as soon as I saw it I knew I had to visit it, and so I did. This was my second time here and still, I had to take pictures of every street, every corner, every building all over again!&lt;/p&gt;

&lt;p&gt;I'll end this post with the words of a famous cyborg assassin: &lt;em&gt;&lt;strong&gt;I'll be back.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>conference</category>
      <category>networking</category>
      <category>javascript</category>
    </item>
    <item>
      <title>PHP Tuples</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Sun, 09 Jun 2019 23:47:11 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/php-tuples-4069</link>
      <guid>https://dev.to/blackcat_dev/php-tuples-4069</guid>
      <description>&lt;p&gt;How do we call a gopher and an elephant dating? A tuple. &lt;/p&gt;

&lt;p&gt;Wow, this makes no sense whatsoever...ok, we should move on now...&lt;/p&gt;

&lt;p&gt;I've been working in &lt;strong&gt;golang&lt;/strong&gt; for quite some time and I started to pick up some patterns subconsciously. Since golang has &lt;a title="Golang - Multiple Return Values" href="https://gobyexample.com/multiple-return-values" rel="noopener"&gt;multiple return values&lt;/a&gt;, which I find quite useful and am a big fan of, I started doing this more and more in &lt;strong&gt;php&lt;/strong&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$contentRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$perPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$filters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sorts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// or the even sweeter shorthand syntax&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$contentRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$perPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$filters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sorts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we are doing here is just destructuring the plain ole' integer indexed array, commonly know in more CS uppity circles as a &lt;a title="Lists" href="https://en.wikipedia.org/wiki/List_(abstract_data_type)" rel="noopener"&gt;list&lt;/a&gt;. But there is a downside to this approach, arrays are kinda like blackboxes, we don't have a clue what's in them, it could be anything. Let's take a look at &lt;strong&gt;&lt;em&gt;getSlice&lt;/em&gt; &lt;/strong&gt;method signature to get a better understanding:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&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;getSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$perPage&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;$filters&lt;/span&gt; &lt;span class="o"&gt;=&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;$sorts&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// something, something&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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;You see, we don't know what type the array's members will be and there is really no way to enforce it, so we could easily introduce some nasty bugs if we were to accidentally put some unexpected values.&lt;/p&gt;

&lt;p&gt;We can tweak this approach a bit by adding &lt;span&gt;doc blocks&lt;/span&gt; to the method signature which will help our IDE and static analysis tools like &lt;a title="PHPStan" href="https://github.com/phpstan/phpstan" rel="noopener"&gt;PHPStan&lt;/a&gt; to know what values are expected:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * @return array&amp;lt;int,string&amp;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;getTitleAndName&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="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="s2"&gt;"Supreme Overlord"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Sasa Blagojevic"&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;Wait, what? Why are we using a different example now? Well, this has its limitations as well, &lt;span&gt;doc blocks&lt;/span&gt; only add value if all the array's members are of the same type. In our first example that's not the case. So what do we do now?&lt;/p&gt;

&lt;h3&gt;Say welcome to &lt;strong&gt;PHP Tuples&lt;/strong&gt;
&lt;/h3&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;Tuple&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ArrayAccess&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;$values&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="nv"&gt;$values&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$values&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="kt"&gt;final&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;offsetExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$offset&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="k"&gt;isset&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;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$offset&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="kt"&gt;final&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;offsetGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$offset&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="k"&gt;isset&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;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$offset&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;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$offset&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;final&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;offsetSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&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="kt"&gt;final&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;offsetUnset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$offset&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;Let's dissect this code snippet a bit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We've implemented the &lt;a title="PHP ArrayAccess Interface" href="https://www.php.net/manual/en/language.oop5.final.php" rel="noopener"&gt;&lt;em&gt;ArrayAccess&lt;/em&gt;&lt;/a&gt; interface to make the objects of the class &lt;em&gt;Tuple&lt;/em&gt; accessible as arrays&lt;/li&gt;
&lt;li&gt;We've left the &lt;em&gt;&lt;strong&gt;offsetSet&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;offsetUnset&lt;/strong&gt;&lt;/em&gt; methods with empty bodies so that our tuples are immutable, we don't want to introduce bugs by accidentally mutating their state&lt;/li&gt;
&lt;li&gt;We've made all the implemented methods &lt;em&gt;&lt;strong&gt;final&lt;/strong&gt;&lt;/em&gt; so other developers can't override them and break the underlying behaviour of our tuple, except the constructor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is going to be our generic tuple. To make things more strict and explicit we will make custom tuple classes on per case basis by extending our &lt;em&gt;Generic Tuple&lt;/em&gt; class and adding types to the constructor:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContentSlice&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Tuple&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * ContentSlice constructor.
     * @param array&amp;lt;int, Content&amp;gt; $items
     * @param int $count
     */&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;array&lt;/span&gt; &lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&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;Let's apply this new found knowledge to our first example:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContentRepository&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;getSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$perPage&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;$filters&lt;/span&gt; &lt;span class="o"&gt;=&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;$sorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// something, something&lt;/span&gt;
        &lt;span class="nv"&gt;$items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ContentSlice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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;Now if we were to put wrong values in the &lt;em&gt;ContentSlice&lt;/em&gt; constructor the code would explode. So what we have achieved now is that we have both &lt;span&gt;multiple return values&lt;/span&gt; and &lt;span&gt;explicit and strict code&lt;/span&gt; like in golang.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/xT0xeJpnrWC4XWblEk/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/xT0xeJpnrWC4XWblEk/giphy.gif" alt="Mind blown" width="350" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is why learning new languages is great, you will stretch out your brain and force it to solve problems in a different way that is idiomatic to the new language. This new knowledge will then pay dividens in your main language when you start to apply all the cool concepts that you've subconsciously or conscioulsy picked up. This is a great way to hone your skills.&lt;/p&gt;

&lt;p&gt;I had this random thought tonight and wanted to share this with you guys (my imaginary audience). I find this pretty cool and I'm probably going to try it out in a project to see how it fares in real world applications, what are your thoughts about &lt;strong&gt;PHP Tuples&lt;/strong&gt;?&lt;/p&gt;

</description>
      <category>php</category>
      <category>go</category>
      <category>discuss</category>
    </item>
    <item>
      <title>PHP Serbia was a blast</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Tue, 28 May 2019 23:59:19 +0000</pubDate>
      <link>https://dev.to/jsguru_io/php-serbia-was-a-blast-3fn7</link>
      <guid>https://dev.to/jsguru_io/php-serbia-was-a-blast-3fn7</guid>
      <description>&lt;p&gt;&lt;em&gt;Originaly published at &lt;a href="https://sasablagojevic.com/php-serbia-was-a-blast"&gt;sasablagojevic.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's time we talked about the phelephant in the room. *Ba Dum Tss! Get it? This is double wordplay, elephant in the room and php + elephant == phelephant. Ok, I'm gonna stop now...&lt;/p&gt;




&lt;p&gt;I wanted to summarise my impressions after the &lt;a title="PHP Serbia 2019 conference" href="https://2019.phpsrbija.rs/" rel="noopener"&gt;PHP Serbia 2019 conference&lt;/a&gt; since this was my first time attending. I thought it might be helpful to those people who are on the fence whether it's worth visiting it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR &lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;&lt;strong&gt;PHP Serbia 2019 line-up&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The line-up&lt;/strong&gt; and the topics covered were all really good. &lt;a title="Zeev Suraski" href="https://twitter.com/zeevs" rel="noopener"&gt;Zeev Suraski&lt;/a&gt; was this year's keynote and he gave us an overview of the PHP since he joined the band of brothers known as &lt;em&gt;php internals devs&lt;/em&gt; and more importantly all the cool stuff that will be included in the upcoming php7.4 and php8. Yep guys, php8 will be coming hopefully by the end of 2020. Oh how the time flies by, I mean I haven't been in this game that long and I witnessed the amazing evolution from php5 to php8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ow_GEkXo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/139/zeev.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ow_GEkXo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/139/zeev.jpg" width="880" height="1062"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I said, all the talks were good but the ones that stood out to me and I recommend you watch when the organizers share the videos are the following (in no particular order):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Hello my name is "if"  &lt;/em&gt;by &lt;a href="https://twitter.com/movetodevnull" rel="noopener"&gt;Sebastian Feldman&lt;/a&gt;, not only did he dance like a madman and put Michael Jackson to shame, but he also gave us a low-level insight and deeper understanding of how different types of if statements work under the hood in php, yes you might have thought that a ternary if statement is just a shorthand way of writing a regular if statement, but when it gets converted to &lt;a title="Zend Opcodes" href="https://x-team.com/blog/learn-about-php-opcodes/" rel="noopener"&gt;opcodes&lt;/a&gt; it's actually not, and the same goes for using the null coalescing statement.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Git legit&lt;/em&gt;  by &lt;a href="https://twitter.com/vanamerongen" rel="noopener"&gt;Pauline Vos&lt;/a&gt; explained the difference between &lt;strong&gt;git rebase&lt;/strong&gt; and &lt;strong&gt;git merge&lt;/strong&gt; strategies in an easily digestible way, even by dummies like myself. Now we can finally put this feud to rest and just pick one that aligns with us philosophically because this is the same shit as OOP vs FP, one is not better than the other they both have their trade-offs. There is no silver bullet in software development no matter how strong we try to find it!&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;You're not a {framework} developer! - &lt;/em&gt;if you are a Symfony or Laravel fanboy you might strongly disagree with this one :D, but &lt;a href="https://twitter.com/tdutrion" rel="noopener"&gt;Thomas Dutrion&lt;/a&gt; gave a good starting point on how to abstract and protect ourselves from the framework. There were some really good examples for both Symfony and Laravel frameworks on how to abstract at both the &lt;em&gt;Model&lt;/em&gt; and &lt;em&gt;Controller&lt;/em&gt; level. &lt;span&gt;Our domain logic shouldn't know about our infrastructure (framework)&lt;/span&gt;, this is my key takeaway from this talk, at least that's how I understood it and it makes perfect sense to me now. For those of you who are saying &lt;em&gt;But how often do we change a framework&lt;/em&gt;? we are not necessarily going to change the framework itself but we need to protect ourselves from future updates of &lt;em&gt;our framework&lt;/em&gt; as well. Each major version will have breaking changes and choosing not to update will compromise both performance and security of our codebase - that's how we get legacy codebases that everybody hates working with.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Making architecture explicit  &lt;/em&gt;by &lt;a href="https://twitter.com/hgraca" rel="noopener"&gt;Herberto Graca&lt;/a&gt;, we all know that organizing code and folders can be a pain in the ass and a huge liability if done poorly. Well, Herberto had some great charts and breakdowns on organizing code the &lt;a title="Domain Driven Development" href="https://medium.com/the-coding-matrix/ddd-101-the-5-minute-tour-7a3037cf53b8" rel="noopener"&gt;DDD&lt;/a&gt; way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I highly suspect that &lt;a href="https://twitter.com/@marcelpociot" rel="noopener"&gt;Marcel Pociot's&lt;/a&gt; talk &lt;em&gt;Getting started with WebSockets&lt;/em&gt; and &lt;a href="https://twitter.com/@faguo" rel="noopener"&gt;Damien Seguy's&lt;/a&gt; &lt;em&gt;T&lt;/em&gt;&lt;em&gt;op 10 PHP coding traps&lt;/em&gt; were awesome as well but unfortunately, I did not attend them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1qZCercY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/139/IMG_0263.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1qZCercY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sasablagojevic.com/img/content/139/IMG_0263.jpg" width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is me winning a free ticket for PHPSerbia 2020 and a Phelephant on the conf quiz :D&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Venue and organization&lt;/h3&gt;

&lt;p&gt;The venue is a big theater in &lt;a title="Zemun" href="https://theculturetrip.com/europe/serbia/articles/top-10-things-to-see-and-do-in-zemun-serbia/" rel="noopener"&gt;Zemun&lt;/a&gt;, there were two tracks A and B, B being the smaller one obviously. Well, it was quite smaller compared to A, so what happened was that all the people that were interested in a talk at track B could not fit in or chose not to stand. This only happened two times though. Gauging the audience's interest and which speaker should get the short stick end is tricky, so maybe, as Damien Seguy suggested, attendees could vote somehow, when the lineup is known, which talks they're interested in so the organizers at least have some estimate. &lt;/p&gt;

&lt;p&gt;There were food and beverages in abundance. I was well fed and watered like a plant xD. I must highlight that the food was really tasty and the Conferences' craft beer as well. What I also really liked compared to other conferences I attended (that being &lt;a title="Webcamp Zagreb" href="https://2019.webcampzg.org/" rel="noopener"&gt;Webcamp Zagreb&lt;/a&gt; times two lol) they had a real espresso machine so I could get my daily 37 doses of macchiato, yes I'm an addict and I'm not ashamed. I basically didn't spend a dime the whole day throughout the conference there was really no need to.&lt;/p&gt;

&lt;p&gt;In general, the organizers did a great job and they were very welcoming, &lt;span&gt;you just felt at home from day one&lt;/span&gt;. &lt;/p&gt;

&lt;p&gt;My only pet peeve is that maybe the talks could be a bit shorter so we have a small pause in between them to reset our brains, chit-chat, drink a coffee or whatevz or maybe I'm just spoiled by WebcampZg.&lt;/p&gt;

&lt;h3&gt;Final verdict&lt;/h3&gt;

&lt;p&gt;I give it a solid &lt;strong&gt;9/10&lt;/strong&gt; just because I'm afraid if I gave them 10 they'll get lazy. Now is the time for you to stop thinking and start preparing for the next one!&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;P.S. Thanks to my company &lt;a title="JSGuru - Your reliable software development partner" href="https://jsguru.io" rel="noopener"&gt;JSGuru&lt;/a&gt; for paying the ticket, I mean who doesn't like free stuff! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originaly published at &lt;a href="https://sasablagojevic.com/php-serbia-was-a-blast"&gt;sasablagojevic.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>conference</category>
    </item>
    <item>
      <title>Why You Should Care What You Npm Install</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Thu, 20 Dec 2018 13:36:52 +0000</pubDate>
      <link>https://dev.to/jsguru_io/why-you-should-care-what-you-npminstall-267c</link>
      <guid>https://dev.to/jsguru_io/why-you-should-care-what-you-npminstall-267c</guid>
      <description>&lt;p&gt;As if we haven't learned anything from the &lt;em&gt;&lt;a href="https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/" rel="noopener noreferrer"&gt;Left-pad&lt;/a&gt;&lt;/em&gt; debacle on November 26th the Javascript world was shaken once again.&lt;/p&gt;




&lt;p&gt;A popular Npm library with over 2 million installs had a backdoor. Wait, what?! Yep, you heard it correctly the &lt;em&gt;&lt;a href="https://github.com/dominictarr/event-stream/issues/116" rel="noopener noreferrer"&gt;event-stream&lt;/a&gt;&lt;/em&gt; library which was not archived at that time and was used all over the place from your garage script kiddie to enterprise systems was infected with an obnoxious back-door, a crypto miner /stealer/something. From now on we will call it the C - virus for dramatic effect.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Damn crypto hype, it's high time the bubble burst and let us go on with our lives. - &lt;a href="https://twitter.com/blackcat_dev" rel="noopener noreferrer"&gt;Me&lt;/a&gt;, December 2018&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, how did it happen? Well, a combination of unfortunate circumstances and the author's faith in people led us here where we are today.&lt;br&gt;
The author stopped using and maintaining the library a long time ago. Since it wasn't archived over time it became a dependency of many projects and lo and behold one day a good Samaritan slid into his inbox and offered to take the burden of maintaining the library upon himself and to carry the torch onwards, but he was not good, was he now.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1067124100332744704-828" src="https://platform.twitter.com/embed/Tweet.html?id=1067124100332744704"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1067124100332744704-828');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1067124100332744704&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The author transferred the rights of the Npm module to this kind stranger but left the module's code on his Github account since there were some problems with name conflict when he tried to transfer it to the stranger's account, or so he says, but I suppose they weren't accidental either. This Samaritan was one nefarious schemer.&lt;br&gt;
As soon as he got hold of the library he removed the publishing rights of the old author, added the &lt;code&gt;flatmap-stream&lt;/code&gt; module which contained the C-virus, did a minor version bump and finally a new release on Npm.&lt;br&gt;
The event-stream library was updated to the new minor version all over the world.&lt;br&gt;
As soon as he planted the C-virus, he removed the &lt;code&gt;flatmap-stream&lt;/code&gt; module from the library and then he did a major version bump and once again a new release on Npm. Quite smart isn't it? Now there was nothing suspicious in the codebase but since it was a major version update most of the systems wouldn't update to it because they are version locked to the previous major version thus they would still have the infected code.&lt;br&gt;
Even one of my coworkers got infected, barely anyone noticed, but Kevin Beaumont.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1067125660014051330-270" src="https://platform.twitter.com/embed/Tweet.html?id=1067125660014051330"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1067125660014051330-270');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1067125660014051330&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;That was a brief summary and I probably missed a step or two but you get the picture.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;SHORT NOTICE:&lt;/strong&gt;&lt;br&gt;
We shouldn't blame the author, he probably didn't really think it through that much but maintaining open source software is a real hassle and can be really mentally draining on the authors, especially in today's entitled society where people expect everything for nothing. So let's not put the blame on him.&lt;/p&gt;



&lt;p&gt;Now let's get back on track! Oh, here's another gem by Kevin Beaumont&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1067130326395351040-919" src="https://platform.twitter.com/embed/Tweet.html?id=1067130326395351040"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1067130326395351040-919');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1067130326395351040&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Hallelujah, praise the Lord! Preach! People didn't come up with this meme for no reason:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AxMYsLPXMT02nL83x3Qbp6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AxMYsLPXMT02nL83x3Qbp6w.png" alt="Npm modules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways from this mess:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes we take for granted and don't think what we Npm install/composer require/yarn add&lt;/li&gt;
&lt;li&gt;Developers have become lazy. We have started taking "don't reinvent the wheel too literally", instead of writing a few extra lines we'd rather require a library, sometimes even for the most trivial of tasks (especially in the Javascript World this seems to be the trend)&lt;/li&gt;
&lt;li&gt;You should always put careful thought in what you require as a dependency, more dependencies can sometimes mean more technical debt&lt;/li&gt;
&lt;li&gt;Add a layer of abstraction and design an interface as a bridge/adapter between your domain logic and libraries, so you can swap them more easily if the need arises&lt;/li&gt;
&lt;li&gt;When a library stops being maintained we now own that code and it is our responsibility to fix it as part of our codebase or find a suitable replacement for it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These lessons were once again learned the hard way by many businesses this November.&lt;/p&gt;

&lt;p&gt;Thanks for reading my long rant!&lt;/p&gt;




&lt;h3&gt;
  
  
  Before you go…
&lt;/h3&gt;

&lt;p&gt;If you enjoyed reading this post please share it. You should check out our other publications, you might like them too! We write from time to time about software development, tips and tricks, and how to become a better developer and business person in general. Join us on the journey of constant improvement!&lt;/p&gt;

&lt;p&gt;Follow us on &lt;a href="https://www.facebook.com/jsguruio/" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt;, &lt;a href="https://twitter.com/jsguru_software" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/jsguru" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://medium.com/jsguru" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; or &lt;a href="https://dev.to/jsguru_io"&gt;DEV.to&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://jsguru.io/blog/why-you-should-care-what-you-npm-install" rel="noopener noreferrer"&gt;jsguru.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
      <category>security</category>
    </item>
    <item>
      <title>Object Oriented Programming</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Sat, 15 Dec 2018 10:09:23 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/object-oriented-programming--1oie</link>
      <guid>https://dev.to/blackcat_dev/object-oriented-programming--1oie</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://sasablagojevic.com/object-oriented-programming" rel="noopener noreferrer"&gt;sasablagojevic.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The aim of this article is to break down the major concepts of OOP for newbie developers in a more digestible format and I hope they will have a better understanding of the Object-Oriented Paradigm after reading it.  &lt;/p&gt;




&lt;p&gt;We all know the majority of newbie developers prefer to get their hands dirty than to read so I'll try to cut the bullsh*t to the minimum. When I was a newbie to programming myself and when I was first delving into the world of OOP, learning what a &lt;em&gt;Class&lt;/em&gt; is and what an &lt;em&gt;Object&lt;/em&gt; is was the easy part. Applying them to the real world problems I was trying to solve was the tricky part.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I structure my code?&lt;/li&gt;
&lt;li&gt;What should my &lt;em&gt;Class&lt;/em&gt; be concerned with?&lt;/li&gt;
&lt;li&gt;Should I split this &lt;em&gt;Class&lt;/em&gt; into more?&lt;/li&gt;
&lt;li&gt;How should the public API of my &lt;em&gt;Class&lt;/em&gt; look like?&lt;/li&gt;
&lt;li&gt;How should the methods be named in conjunction with the &lt;em&gt;Classes&lt;/em&gt;' name?&lt;/li&gt;
&lt;li&gt;Should this method be static?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those were all the questions that I asked myself.&lt;/p&gt;

&lt;p&gt;Since I'm a self-taught developer, I lacked some theoretical knowledge, so I decided to read more about OOP and design patterns. Previously I have been doing things more intuitively and it has done me well. I was on the right track, I've advanced in my career and nobody complained about my code, on the contrary, but there comes a time when you need to get a deeper understanding, how things "work under the hood" to take both your knowledge and career to the next step. &lt;/p&gt;

&lt;p&gt;The aim of this article is to break down the major concepts of OOP for newbie developers and I hope they will have a better understanding of the Object-Oriented Paradigm after reading it. It is intended as a cheat sheet they can come back to and freshen up their knowledge and not only them, myself included ;) &lt;/p&gt;

&lt;h2&gt;All Roads Lead to Rome&lt;/h2&gt;

&lt;p&gt;To get a better understanding of OOP and what issues people were trying to solve with it, we will briefly go over some of the different and most common programming paradigms. While most of the modern languages have a multi-paradigm approach at some point in their lifetime they might not have had. It has been an iterative process to come where we are today, it is a long road from Assembler to PHP.&lt;/p&gt;

&lt;h3&gt;Programming paradigms&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Imperative&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt; Procedural&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;


&lt;li&gt;

&lt;strong&gt;Structured &lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Object-oriented&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;


&lt;li&gt;

&lt;strong&gt;Declarative&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Functional&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;


&lt;/ul&gt;

&lt;p&gt;In &lt;strong&gt;imperative programming&lt;/strong&gt;, we give instructions to the computer what to do and in which order to do it. Every time we tell the computer to remember something by storing it in a variable we are using &lt;em&gt;statements&lt;/em&gt; to change the &lt;span&gt;global state&lt;/span&gt; of the program. You can already see how this could get messy in big programs with lots of developers because all of them are directly changing the global state the chance of making bugs and overriding data is high.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Procedural programming&lt;/strong&gt;, although often used as a synonym for imperative programming, is actually an extension of the imperative paradigm. In procedural programming, we group aforementioned instructions into &lt;span&gt;procedures&lt;/span&gt;, also known as &lt;a title="Subroutines" href="https://en.wikipedia.org/wiki/Subroutine" rel="noopener noreferrer"&gt;subroutines&lt;/a&gt; or functions. &lt;span&gt;Procedures&lt;/span&gt; are just a set of instructions, a modular unit, that we can reuse in our program just by calling it without having to rewrite the specific steps all over again. But at this point, you already know this ;) Procedural programming brought us the concepts of &lt;a title="Blocks" href="https://en.wikipedia.org/wiki/Block_(programming)" rel="noopener noreferrer"&gt;blocks&lt;/a&gt; and &lt;a title="Scope" href="https://en.wikipedia.org/wiki/Scope_(computer_science)" rel="noopener noreferrer"&gt;scopes&lt;/a&gt;, which gave us a new type of state, &lt;em&gt;local&lt;/em&gt;. Local state means that is valid only in the context of that specific procedure.&lt;/p&gt;

&lt;p&gt;As we can see the focus of procedural programming is to break down the computer instructions into variables and subroutines/functions, whereas in &lt;strong&gt;object-oriented programming&lt;/strong&gt; it is to break it down into &lt;strong&gt;objects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Objects expose their behaviour through &lt;span&gt;methods&lt;/span&gt; (class/object functions) and have their own internal state in form of &lt;a title="Properties" href="http://php.net/manual/en/language.oop5.properties.php" rel="noopener noreferrer"&gt;members/attributes&lt;/a&gt;. Both the methods and attributes may or may not be accessible to the outside world depending on their &lt;a title="Attribute and Method visibility" href="http://php.net/manual/en/language.oop5.visibility.php" rel="noopener noreferrer"&gt;visibility&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So you see, both &lt;em&gt;procedural&lt;/em&gt; and &lt;em&gt;object-oriented&lt;/em&gt; paradigms were trying to solve the same issues: the issue of mutating the global state and breaking down complex tasks into smaller modular units (subroutines/functions vs. objects), in their own respective ways.&lt;/p&gt;

&lt;p&gt;Object-oriented programming in its core is all about &lt;span&gt;sending messages and responding to them&lt;/span&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In procedural programming, a process is expressed in one place in which a series of instructions are coded in order. Whereas in OO, a process is expressed as a succession of messages across objects. (David Chelimsky in Single Responsibility Applied to Methods)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my opinion, this is best described by the &lt;a title="Tell Don't Ask" href="https://martinfowler.com/bliki/TellDontAsk.html" rel="noopener noreferrer"&gt;&lt;em&gt;Tell don't ask&lt;/em&gt;&lt;/a&gt; principle. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't ask for the information you need to do the work; ask for the object that has information to do the work for you. (Allen Hollub - Hollub on Patterns)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's expand on this a bit in layman's terms. Contrary to procedural and functional paradigms where we would pass data from a function to function, manipulate it and return it, in OOP we want the object that encapsulates that data (has it in its internal state) to do the manipulation for us. We achieve that by sending it a &lt;em&gt;message.&lt;/em&gt; After receiving our message the object will determine based on its internal knowledge and methods what it will give us as a &lt;em&gt;response&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;In even simpler terms, &lt;em&gt;messages&lt;/em&gt; would be our method calls and &lt;em&gt;responses&lt;/em&gt; the data those methods return. Bear in mind that methods can be void, meaning they don't return any data, they just change the internal state of the object, but you get the gist of it.&lt;/p&gt;

&lt;p&gt;So to put that in practical terms it would look something like this. *Disclaimer* This is a highly simplified example just for illustrative purposes.&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;function&lt;/span&gt; &lt;span class="n"&gt;mark_as_read&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;$email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'is_read'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"from"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Marry Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"to"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"subject"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Dear John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"body"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"I\'m leaving you"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;mark_as_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// vs.&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$subject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$isRead&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;__constructor&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;$from&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;$to&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;$subject&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;$body&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;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$from&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;to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$to&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;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$subject&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$body&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;markAsRead&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Email&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;isRead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="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;isRead&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&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;isRead&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&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="nv"&gt;$email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Marry Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Dear, John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"I'm leaving you."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;markAsRead&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a good metaphor by one of the fathers of OOP Allan Kay, he says that &lt;em&gt;objects&lt;/em&gt; are like cells in our bodies, small self-contained units that make up our human being.&lt;/p&gt;

&lt;p&gt;Ok, just because we know now how to cram functions and data in a class does not mean we know OOP, let's make everything a class now is a common newbie pitfall. There are a few more things we need to keep in mind! :D But before talking further let's just briefly go over the last two paradigms.&lt;/p&gt;

&lt;p&gt;In contrast to the imperative paradigm, the &lt;strong&gt;declarative&lt;/strong&gt; paradigm tells the computer what we want, not the steps how to get it. A perfect example of a declarative programming language is &lt;strong&gt;SQL&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functional paradigm&lt;/strong&gt; is a subset of the declarative paradigm and it uses declarations/expressions unlike statements in the imperative family, but like its counterparts, it also tries to solve this issue of manipulating the global state. In functional programming, programs are thought of as a collection of pure functions. &lt;a title="Pure functions" href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;&lt;span&gt;Pure functions&lt;/span&gt;&lt;/a&gt; are functions which take input and always return new values. They never have side effects, they never mutate the state and they are always expected to give the same result given the same input. So in the functional paradigm, the state is &lt;span&gt;immutable&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a title="Programming Across Paradigms" href="https://twitter.com/AnjanaVakil" rel="noopener noreferrer"&gt;@AnjanaVakil&lt;/a&gt; puts it more eloquently in her &lt;a title="WCZG 2017 - Programming Across Paradigms" href="https://2017.webcampzg.org/talks/programming-across-paradigms/" rel="noopener noreferrer"&gt;Programming Across Paradigms keynote at WebcampZG 2017&lt;/a&gt;, I recommend you watch it.&lt;/p&gt;

&lt;h2&gt;Basic OOP Principles&lt;/h2&gt;

&lt;h3&gt;&lt;strong&gt;Single Responsibility&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;span&gt;A class should only be concerned and handle one aspect of a complex problem we are trying to solve&lt;/span&gt;. It doesn't mean that a class should literally have just one responsibility, it's not a function for Pete's sake, it can have multiple but they all need to be a part of &lt;strong&gt;one&lt;/strong&gt; broader task. When we say &lt;em&gt;single responsibility&lt;/em&gt; we are talking from the context of our business/domain logic. For example, let's look at the PHP's built-in &lt;em&gt;SplFileObject&lt;/em&gt;, that class is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reading the file,&lt;/li&gt;
&lt;li&gt;writing to the file,&lt;/li&gt;
&lt;li&gt;checking if the file exists,&lt;/li&gt;
&lt;li&gt;checking if the given path is a file or directory, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But all these actions are under the umbrella of one broader task, &lt;em&gt;interacting with the files&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Abstraction&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Abstraction, in this case, is an umbrella term for &lt;em&gt;Interfaces&lt;/em&gt; and &lt;em&gt;Abstract Classes&lt;/em&gt;. In PHP those are the two main abstraction mechanisms. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a title="PHP - Interfaces" href="http://php.net/manual/en/language.oop5.interfaces.php" rel="noopener noreferrer"&gt;&lt;span&gt;Interfaces&lt;/span&gt;&lt;/a&gt; are contracts for behaviour&lt;/strong&gt;. We use them to define the public API of a class, and ensure that when a message is sent to a class instance (object) which implements that interface, the object will always respond according to the definition otherwise the program will fail. In other words, the interface defines the methods a class needs to implement in order for our program to work otherwise it will break.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interfaces can't be instantiated&lt;/li&gt;
&lt;li&gt;Interfaces can only have method signatures&lt;/li&gt;
&lt;li&gt;Interfaces can't have properties declared on them (although PHP allows them to have constants)&lt;/li&gt;
&lt;li&gt;Interfaces can only have public methods&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a title="PHP - Abstract Classes" href="http://php.net/manual/en/language.oop5.abstract.php" rel="noopener noreferrer"&gt;&lt;span&gt;Abstract Classes&lt;/span&gt;&lt;/a&gt; are also contracts for behaviour, but they are more than that&lt;/strong&gt;. Unlike &lt;em&gt;Interfaces&lt;/em&gt;, &lt;em&gt;Abstract Classes&lt;/em&gt; can also, like any other &lt;em&gt;Class,&lt;/em&gt; have concrete methods and members/attributes (state) defined on them. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstract Classes can't be instantiated&lt;/li&gt;
&lt;li&gt;Abstract Classes must have at least one abstract method&lt;/li&gt;
&lt;li&gt;Abstract Classes can have concrete methods &lt;/li&gt;
&lt;li&gt;Abstract Classes can have members/attributes (properties) &lt;/li&gt;
&lt;li&gt;Abstract Classes can have all visibility levels (public, protected and private)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Program to an interface, not an implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does this mean? In plain words, this means: &lt;a title="Type Hint" href="http://php.net/manual/en/language.oop5.typehinting.php" rel="noopener noreferrer"&gt;Type Hint&lt;/a&gt; your variables/properties to &lt;em&gt;Abstractions&lt;/em&gt;&lt;em&gt; (Interfaces/Abstract Classes)&lt;/em&gt; not concrete&lt;em&gt; Classes.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;By programming to interfaces, you are decoupling your code's design from its implementation. This enables you to replace pieces of your code more easily down the road if a need arises. Yep, your code's maintainability just skyrocketed. This will also make your code more testable because you will be able to mock certain parts of your system just by implementing the interfaces and replacing the "production" behaviour with the "testing" one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Abstractions&lt;/em&gt; shift our focus upwards, from the methods' underlying implementations to their signatures, because in a sense they don't concern us, as long as &lt;em&gt;Abstractions&lt;/em&gt;' method signatures and their definitions (arguments and return values) are being respected everything will work. This allows us for a more robust and flexible codebase. Let's take a look at the following examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good example&lt;/strong&gt; - Since we programmed to an interface and not an implementation, changing the storage method is just a matter of changing the class we provide through the &lt;em&gt;App's&lt;/em&gt; constructor, we are changing just one line of code. &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;// Storable Interface&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Storable&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;store&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Database Storage&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mysql&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Storable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$conn&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;PDO&lt;/span&gt; &lt;span class="nv"&gt;$conn&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$conn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;insert&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;$table&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

         &lt;span class="nv"&gt;$placeholders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"?"&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;str_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;",?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="nv"&gt;$sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO &lt;/span&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="s2"&gt;) VALUES(&lt;/span&gt;&lt;span class="nv"&gt;$placeholders&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

         &lt;span class="nv"&gt;$stmt&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;pdo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&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;$stmt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&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;store&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&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="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'emails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$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="c1"&gt;// File Storage&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Storable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;write&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;$file&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\SplFileObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a+'&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;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'.txt'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

            &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\SplFileObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a+'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&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="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&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;store&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&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="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'emails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$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="c1"&gt;// Client&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;Storable&lt;/span&gt; &lt;span class="nv"&gt;$storable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
             &lt;span class="s1"&gt;'from'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'foo@mail.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'to'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'bar@mail.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'subject'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'World'&lt;/span&gt;
         &lt;span class="p"&gt;];&lt;/span&gt;
         &lt;span class="nv"&gt;$storable&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$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="c1"&gt;// Databse App&lt;/span&gt;
&lt;span class="nv"&gt;$dbApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&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;Mysql&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;Pdo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="c1"&gt;// File Storage App&lt;/span&gt;
&lt;span class="nv"&gt;$fileApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&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;File&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bad example &lt;/strong&gt;- Imagine we wanted to change the storage method in this example, now this would amount to more effort than the previous one.&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;// Database Storage&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mysql&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Storable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$conn&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;PDO&lt;/span&gt; &lt;span class="nv"&gt;$conn&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$conn&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;insert&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;$table&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

         &lt;span class="nv"&gt;$placeholders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"?"&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;str_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;",?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="nv"&gt;$sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO &lt;/span&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="s2"&gt;) VALUES(&lt;/span&gt;&lt;span class="nv"&gt;$placeholders&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

         &lt;span class="nv"&gt;$stmt&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;pdo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sql&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;$stmt&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&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="c1"&gt;// File Storage&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Storable&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;write&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;$file&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;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\SplFileObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'.txt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a+'&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;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'.txt'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

            &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\SplFileObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a+'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&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="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&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="c1"&gt;// Client&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;Mysql&lt;/span&gt; &lt;span class="nv"&gt;$mysql&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
             &lt;span class="s1"&gt;'from'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'foo@mail.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'to'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'bar@mail.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'subject'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Hello'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'World'&lt;/span&gt;
         &lt;span class="p"&gt;];&lt;/span&gt;
         &lt;span class="nv"&gt;$mysql&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'emails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, both of these are trivial examples but imagine if these classes had many more methods that are being called deeper down in the code, it could give you quite a headache.&lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Encapsulation and &lt;em&gt;Tell don't ask principle&lt;/em&gt; go hand in hand. As we already said, objects should manipulate their own state. Allowing other objects to directly change the state of our object should be avoided. Once more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't ask for the information you need to do the work; ask for the object that has information to do the work for you. (Allen Hollub - Hollub on Patterns)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By preserving encapsulation we are writing less bug-prone and more debuggable code because we are being explicit and we only change the objects' state when we send him a message.&lt;/p&gt;

&lt;p&gt;We also use encapsulation to hide the complexities and intricacies of our &lt;em&gt;abstractions&lt;/em&gt; and their implementations, this way we just keep the "simple stuff" available to the outside world, all those gory details are left hidden.&lt;/p&gt;

&lt;p&gt;&lt;a title="Visibility" href="http://php.net/manual/en/language.oop5.visibility.php" rel="noopener noreferrer"&gt;&lt;em&gt;Visibility/Accessors&lt;/em&gt;&lt;/a&gt; are the way we ensure our objects stay encapsulated. There are three levels of visibility in PHP as in many other languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;public&lt;/strong&gt; - methods and properties are accessible from the outside world. When it comes to &lt;em&gt;public methods&lt;/em&gt; they are what make up the public API of our class, those are the methods we want other developers and/or objects to interact with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protected&lt;/strong&gt; - methods and properties are accessible only from within the class and its &lt;em&gt;children&lt;/em&gt; (other classes that extend it)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;private&lt;/strong&gt; - methods and properties are accessible only from within the class in which they are defined&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Getters/Setters &lt;/em&gt;also known as &lt;em&gt;accessors &lt;/em&gt;and &lt;em&gt;mutators&lt;/em&gt; give us the ability to keep our objects encapsulated while at the same time having the ability to access and mutate their state, just instead of accessing it directly we do it through getter/setter methods. &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;// Without getters/setters&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Imagine we wanted to check for equality&lt;/span&gt;
&lt;span class="c1"&gt;// but forgot to add the second '='.&lt;/span&gt;
&lt;span class="c1"&gt;// See, a simple typo could introduce a bug.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something awesome here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// With getters/setters&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;proteceted&lt;/span&gt; &lt;span class="nv"&gt;$slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'foo'&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;getSlug&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;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;slug&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;setSlug&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;$slug&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$slug&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="nv"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Article&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="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getSlug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do something awesome here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a title="Inheritance" href="http://php.net/manual/en/language.oop5.inheritance.php" rel="noopener noreferrer"&gt;Inheritance&lt;/a&gt; is self-explanatory, an object will inherit all of the &lt;em&gt;super&lt;/em&gt; (parent) classes' methods and attributes unless the visibility of the method is &lt;em&gt;private&lt;/em&gt; and we achieve that by extending a class. You might have come across the phrase &lt;em&gt;"Favour Composition over Inheritance" &lt;/em&gt;or some go even further and say that &lt;a title="Inheritance is evil" href="https://codeburst.io/inheritance-is-evil-stop-using-it-6c4f1caf5117" rel="noopener noreferrer"&gt;inheritance is evil&lt;/a&gt;. In my humble opinion &lt;span&gt;inheritance is not bad, bad inheritance is though&lt;/span&gt;. Now how do we distinguish between good and bad inheritance?&lt;/p&gt;

&lt;blockquote data-lang="en"&gt;
&lt;p&gt;Good inheritance is "is a (special case of)". The keyword extends also supports "taxonomy" which objects do better than classes, and "code re-use", which composition is far better for!&lt;/p&gt;
— Pim Elshoff (@Pelshoff) &lt;a href="https://twitter.com/Pelshoff/status/1066973076037005312?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;November 26, 2018&lt;/a&gt;
&lt;/blockquote&gt;



&lt;p&gt;As &lt;a title="Inheritance is a special case of" href="https://twitter.com/Pelshoff/status/1066973076037005312" rel="noopener noreferrer"&gt;@Pelshof&lt;/a&gt; perfectly said in his tweet you should look at inheritance as &lt;em&gt;a special case of&lt;/em&gt;. We should look at a child class as a &lt;span&gt;special case of&lt;/span&gt; its &lt;em&gt;superclass&lt;/em&gt;, it has all the behaviour of its parent and then some. &lt;span&gt;Good inheritance is shallow&lt;/span&gt;, you shouldn't go deeper then one level if you really must not and you should inherit from &lt;em&gt;Abstract&lt;/em&gt; classes except in those cases where extending a concrete class makes sense, e.g. a concrete BaseController of a framework where you want to abstract a bit from the framework or add some common behaviour.&lt;/p&gt;

&lt;p&gt;When you are extending classes you should always have the &lt;em&gt;Single Responsibility Principle&lt;/em&gt; on your mind, use it as a litmus test, if you're breaking it by extending it's time for &lt;em&gt;Composition.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Composition&lt;/strong&gt; &lt;span&gt;in simplest terms is breaking down a complex task into multiple reusable classes&lt;/span&gt;, instead of inheriting multiple levels deep. Composition vs Inheritance is in a sense like &lt;em&gt;horizontal&lt;/em&gt; vs &lt;em&gt;vertical&lt;/em&gt; scaling. With composition, you are breaking down your task horizontally, whereas with inheritance you are doing it vertically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsasablagojevic.com%2Fimg%2Fcontent%2F132%2Finheritance_composition.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsasablagojevic.com%2Fimg%2Fcontent%2F132%2Finheritance_composition.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This illustration makes it more clear, on the left-hand side we have a &lt;em&gt;parent&lt;/em&gt; File Class and its &lt;em&gt;child&lt;/em&gt; and &lt;em&gt;grandchild&lt;/em&gt; Reader and Writer classes respectively. So we broke our example &lt;em&gt;file interaction&lt;/em&gt; task vertically.&lt;/p&gt;

&lt;p&gt;On the right-hand side, we have the File Class and its dependencies*, two independent reusable classes Writer and Reader which we will inject to the File Class through its constructor. In this case, we expanded the responsibilities of the File Class horizontally. &lt;/p&gt;

&lt;h3&gt;&lt;strong&gt;Polymorphism&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Polymorphism in plain English means that &lt;strong&gt;objects which implement the same interface can do different things&lt;/strong&gt; "under the hood", as long as they adhere to the interfaces' definitions, thus the &lt;a title="What does polymorph mean?" href="http://lmgtfy.com/?q=polymorph" rel="noopener noreferrer"&gt;&lt;em&gt;polymorph&lt;/em&gt;&lt;/a&gt; part.&lt;/p&gt;

&lt;p&gt;We already covered this a bit when we talked about the &lt;em&gt;Abstraction principle&lt;/em&gt;, the complexities and intricacies of the method implementations are hidden underneath the &lt;em&gt;Interface&lt;/em&gt; - our one "single" point of entry and exit. We can implement a method in an infinite number of ways as long as we take the defined number of arguments and return what is expected, we're all set.    &lt;/p&gt;

&lt;p&gt;If you jump back to the &lt;em&gt;Good example&lt;/em&gt; in the &lt;em&gt;Abstraction&lt;/em&gt; section you will clearly see that it is also polymorphism at play. We have a&lt;em&gt; Storable&lt;/em&gt; &lt;em&gt;Interface&lt;/em&gt; and two classes which implement it and do two different things. &lt;em&gt;Mysql&lt;/em&gt; stores to a database and the &lt;em&gt;File&lt;/em&gt; writes to a CSV file.&lt;/p&gt;

&lt;h2&gt;Rome&lt;/h2&gt;

&lt;p&gt;I was speaking mainly from the perspective of a PHP developer, but all of these concepts can be applied to any programming language that supports the Object-Oriented paradigm. To prove my point let's compare how we would apply the &lt;strong&gt;Abstraction&lt;/strong&gt; principle in PHP and Swift for a second.&lt;/p&gt;

&lt;p&gt;In PHP we have &lt;em&gt;Interfaces&lt;/em&gt; and in Swift we have &lt;em&gt;Protocols&lt;/em&gt;, they are the same thing just a different keyword, no issue here, but when it comes to Abstract Classes Swift does not support them.&lt;/p&gt;

&lt;p&gt;Although Swift has no notion of Abstract Classes they have a different language construct that allows us to have the same behaviour, namely &lt;em&gt;Protocol Extensions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Protocol Extensions&lt;/span&gt; allow us to extend the protocol and add additional methods and/or properties to it so we can achieve the same behaviour as Abstract Classes in the following way:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;numberOfLegs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;4&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="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"woof"&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="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"woof"&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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// woof&lt;/span&gt;

&lt;span class="n"&gt;dog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;numberOfLegs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See, these concepts are "languageless" ;)&lt;/p&gt;

&lt;p&gt;We should all strive to adhere to these principles, but what these 2.5+ years of working professionally as a developer have taught me is that we should never be too dogmatic and that every rule has an exception. &lt;/p&gt;




&lt;p&gt;* &lt;em&gt;&lt;a title="What are dependencies?" href="https://askubuntu.com/questions/361741/what-are-dependencies" rel="noopener noreferrer"&gt;&lt;strong&gt;Dependency&lt;/strong&gt;&lt;/a&gt; is a broad software engineering term used to refer when a piece of software relies on another one. Coupling (computer programming) In software engineering, coupling or dependency is the degree to which each program module relies on each one of the other modules. Program X uses Library Y. &lt;/em&gt;&lt;/p&gt;

</description>
      <category>oop</category>
      <category>php</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Webcamp Zagreb 2018</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Thu, 04 Oct 2018 17:36:00 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/webcamp-zagreb-2018-l11</link>
      <guid>https://dev.to/blackcat_dev/webcamp-zagreb-2018-l11</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnsicdrmz86bvh5awu341.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnsicdrmz86bvh5awu341.png" alt="Webcamp Zagreb 2018"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is anyone from dev.to besides me going to Webcamp Zagreb tomorrow? :D &lt;/p&gt;

</description>
      <category>wczg</category>
      <category>conference</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>SEO Guide for Websites</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Mon, 01 Oct 2018 13:46:01 +0000</pubDate>
      <link>https://dev.to/jsguru_io/seo-guide-for-websites--2g2e</link>
      <guid>https://dev.to/jsguru_io/seo-guide-for-websites--2g2e</guid>
      <description>&lt;p&gt;This guide will cover a very important topic for every digital business, search engine optimization. SEO can sometimes appear as a black box, there is a lot of magic behind it and it's constantly changing and evolving. In this article, we will try to dispell it by leading you through some of the SEO best practices.&lt;/p&gt;




&lt;p&gt;Besides the &lt;a href="https://seo-hacker.com/google-algorithm-update-july-2018/"&gt;latest Google algorithm updates&lt;/a&gt;, working on our company’s website SEO and trying to battle through the avalanche of information is what prompted me to write this guide, if nothing as a reference for future self.&lt;/p&gt;

&lt;p&gt;This is by no means a comprehensive guide, I will go over the SEO fundamentals you need to cover if you want a shot at appearing on the Google's first page and we all know how it is in practice, if you are not on the first page, it's as if you don't exist, let's be honest, how often do you go to the second or the third page? Yeah, thought so…&lt;/p&gt;

&lt;p&gt;If you are interested in the history of the Google's algorithm and how it changed over the time the guys and gals at Moz have organized it in a nice &lt;a href="https://moz.com/google-algorithm-change"&gt;searchable list&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Let's start from the beginning, what is a search engine?
&lt;/h4&gt;

&lt;p&gt;You know how your website has different pages, and it has a navigation bar that links to every one of them? Well, you can look at Google, or any other search engine for that matter, as the internet's navigation menu. Google "collects" all the websites from the world and indexes them. But how does he collect them?&lt;/p&gt;

&lt;p&gt;Well, there are three ways how Google can discover your website:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;From DNS registries - if you're not familiar with the term DNS, I recommend you read this &lt;a href="https://www.cloudflare.com/learning/dns/what-is-dns/"&gt;article&lt;/a&gt;. While we're at it, did you know that &lt;a href="https://www.theregister.co.uk/2005/02/01/google_domain_seller/"&gt;Google itself is a DNS registrar&lt;/a&gt; although they do not sell domains?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If other websites link to your, Google will follow those links and discover you (unless there is a &lt;a href="https://support.google.com/webmasters/answer/96569?hl=en"&gt;rel="nofollow"&lt;/a&gt; attribute on them). Those links are called inbound links and they are one of the major factors that determine your SEO ranking.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By adding your website and sitemap to the Google Search Console you are basically telling Google "Hi my name is so and so, and this is my address, here you can see my living room, and that is my kitchen, oh I almost forgot about the porch…" ;). &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BuvxV1Br--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://delivery.eusi.cloud/api/v1/f1a4305c-e431-4668-ae4c-02f78c656a41/media/s3/1538239337662_JSGuru-Body-Image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BuvxV1Br--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://delivery.eusi.cloud/api/v1/f1a4305c-e431-4668-ae4c-02f78c656a41/media/s3/1538239337662_JSGuru-Body-Image-1.png" alt="An illustratin depicting a network of devices" width="880" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Google Search Console
&lt;/h1&gt;

&lt;p&gt;This should be your first step on your path to SEO glory. Go to the Google Search Console, add your website and go through the verification process, and now you are at your first crossroads. You have two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can either add both of your website versions, a non-www and www version (e.g. &lt;a href="https://jsguru.io"&gt;https://jsguru.io&lt;/a&gt; and &lt;a href="https://jsguru.io"&gt;https://www.jsguru.io&lt;/a&gt;) and choose a preferred one. In our case, we set the preferred one to be the non-www.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or you can add only one version to the Google Search Console, whichever you prefer, and configure your server to redirect from the other version to your preferred one (e.g. add only &lt;a href="https://jsguru.io"&gt;https://jsguru.io&lt;/a&gt; to Google Search Console, and redirect from &lt;a href="https://jsguru.io"&gt;https://www.jsguru.io&lt;/a&gt; to &lt;a href="https://jsguru.io"&gt;https://jsguru.io&lt;/a&gt;). It must be a permanent redirect so your HTTP Response Code should be 301.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either way, you must handle both of the domain variants, if you just leave them in the wild, without handling them as previously described, there is a high probability Google will treat them as duplicate content, and duplicate content is penalized. &lt;/p&gt;

&lt;p&gt;On the other hand, it would be really bad user experience and detrimental to your brand if you served only one domain variant and your website errored out on the other one.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Sitemaps
&lt;/h1&gt;

&lt;p&gt;Sitemaps are, as the name already says, a map of all your website pages represented in a format Google or any other search engine can easily digest. It is a collection of all your links, usually in an XML document, but it can also be in a different format such as HTML for example. Look at them as a skeleton of your website.&lt;br&gt;
There are a lot of &lt;a href="https://www.xml-sitemaps.com/"&gt;free online tools&lt;/a&gt; that can generate them for you. After you've done that you should &lt;a href="https://support.google.com/webmasters/answer/183668?hl=en"&gt;submit it to Google Search Console&lt;/a&gt; under the Sitemaps section. This will allow Google to index you more easily, but still, be patient, it can take time.&lt;/p&gt;

&lt;p&gt;If you have a publishing website like a news magazine or a blog, it would be best if you could find a way to automatically update them to reflect the changes on your website.&lt;/p&gt;

&lt;p&gt;Since you can submit as many different sitemaps to Google Search Console as you want, a good approach would be to have at least two sitemaps, one for the "static" part of your website that doesn't change that often and another one for the "dynamic" part of your website which is updated frequently, like the blog section for example.&lt;/p&gt;

&lt;p&gt;In our case we have two sitemaps, one that covers our main navigation and contains links to the pages like Home, About Us, What We Do and so on, and another one for our blog where we publish articles every two weeks.&lt;/p&gt;
&lt;h1&gt;
  
  
  3. HTTPS vs HTTP
&lt;/h1&gt;

&lt;p&gt;From July 2018 Google Chrome has started to mark websites without HTTPS as non-secure, which could negatively impact your traffic, users might decide to leave your website because they perceive it as insecure, or they might get worried that it's some kind of a scam, in addition, HTTPS websites are reported to have a slight ranking advantage over HTTP websites.&lt;/p&gt;

&lt;p&gt;In the early days of internet getting an SSL certificate and securing your website with HTTPS was a tedious and expensive process, but thanks to the open source community and Let's Encrypt Foundation it is now both free and easy to set up. &lt;br&gt;
Follow these links for a detailed tutorial on how to add HTTPS to your website:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04"&gt;Apache tutorial&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04"&gt;Ngnix tutorial&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  4. Meta tags
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Yes, meta tags are still a thing!&lt;/em&gt; &lt;br&gt;
The description meta tag allows you to customize the brief description which will be shown in the search results, otherwise, you're leaving it up to Google to determine what's important and what will be shown, which can lead to some nasty and completely unrelated descriptions. Traditionally, the description length was capped at 155 characters, but recently Google started to allow more, so to play it safe your description should be &lt;a href="https://moz.com/blog/how-long-should-your-meta-description-be-2018"&gt;between 50 and 300 characters&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although the keywords meta tag has been obsolete for some time, I still included it, because the SEO tool I use bugged me that it was missing and since I'm a bit OCD I just had to add it.&lt;/p&gt;

&lt;p&gt;The og, not to be confused with original gangsta, meta tags are used by Facebook, LinkedIn, and other social media to determine what content will be shown when someone shares your page. Same goes for the twitter meta tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"JSGuru is a high-quality software development shop where clients come first. We build your desired products and provide excellent, long-term customer support so that you can focus on the core of your business."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"keywords"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"software development, web development, mobile development"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Facebook--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt;                &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt;               &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt;              &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"JSGuru"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt;        &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"JSGuru is a high-quality software development shop where clients come first. We build your desired products and provide excellent, long-term customer support so that you can focus on the core of your business."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt;
      &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/img/jsguru.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Twitter --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:site"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"@jsguru_software"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:creator"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"@jsguru_software"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"JSGuru"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"JSGuru is a high-quality software development shop where clients come first. We build your desired products and provide excellent, long-term customer support so that you can focus on the core of your business."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt;
      &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/img/jsguru.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  5. Canonical Links 
&lt;/h1&gt;

&lt;p&gt;What are canonical links? For all of you who are not familiar with the term, canonical links are HTML tags that you put in the HEAD of your document and their purpose is to point to the original source of the content.&lt;br&gt;
Canonical links can point to a different page/ link from the current page you are on, or they can be self referencing, meaning they can point to the same page you are currently on.&lt;/p&gt;

&lt;p&gt;When Google comes across a canonical link that points to a different page it says to him "Hey don't index this page, the actual source you should index is there.".&lt;/p&gt;

&lt;p&gt;If the canonical link is self-referencing, that signals to Google "Ok this is the definite root of the content". If Google were to come across the same content again on a different website he would definitely know that your content is actually the original.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;JSGuru - What We Do&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you remember how I mentioned earlier that we should handle both the non-www and www version of our domain? Well, be careful not to mix them in your canonical links, choose one preferred version and stick with it!&lt;/p&gt;

&lt;h1&gt;
  
  
  6. Localization - hreflangs 
&lt;/h1&gt;

&lt;p&gt;What if you have a multilingual site and you want different language versions served depending on the country of the visitor? How to go about that?&lt;/p&gt;

&lt;p&gt;A common, but a discouraged approach is to geolocate the user by his IP address. This is usually done by storing the IP tables in your database and comparing them with the user's or using a third party service like &lt;a href="https://ipinfo.io/"&gt;Ipinfo&lt;/a&gt;.&lt;br&gt;
After determining the user's location you would store it in a cookie and serve the appropriate language.&lt;/p&gt;

&lt;p&gt;This seems like a sensible approach, doesn't it? But why is it discouraged? &lt;/p&gt;

&lt;p&gt;Well, firstly the geolocation by IP is not that precise, especially nowadays when people value their online privacy and are using VPN's more and more, additionally, some internet providers themselves use proxies when giving out dynamic IPs.&lt;/p&gt;

&lt;p&gt;Secondly what if the user is a German but he is in England on a business trip? He would get the English version and we don't want that.&lt;/p&gt;

&lt;p&gt;Thirdly you are taking away the possibility to manually choose the language version from the user. &lt;/p&gt;

&lt;p&gt;Last but not the least, you are preventing Google from properly indexing all your website versions because their crawling servers are mainly in the US.&lt;/p&gt;
&lt;h3&gt;
  
  
  Now that we went over what not do, let's go over what you should do!
&lt;/h3&gt;

&lt;p&gt;First and foremost, the pages your hreflang links are pointing to should have the same content just in a different language, they should never have a completely different content, that is a NO NO.&lt;/p&gt;

&lt;p&gt;When it comes to actual linking, you have two options: &lt;/p&gt;
&lt;h4&gt;
  
  
  a) Add hreflang link in the head of the HTML document
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- English (default) language page --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;JSGuru - What We Do&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"x-default"&lt;/span&gt;  
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de-ch"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de-at"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It is important that you add the hreflang links on all pages not just your default language page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- German Language Page --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;JSGuru - Was Wir Tun&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"x-default"&lt;/span&gt;  
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de-ch"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
          &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de-at"&lt;/span&gt; 
          &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful not to combine hreflang tags with canonical links which point to different pages, as well. Hreflang tags can only be combined with self-referencing canonical links.&lt;/p&gt;

&lt;p&gt;In our code example, we included the canonical link only in our English (default) language page, that's because that is the original source of our content, the German page shouldn't include the canonical link because it's the same content just in a different language, if we were to include it we would just confuse the Google crawler.&lt;/p&gt;

&lt;h4&gt;
  
  
  b) Add hreflang link to the sitemap
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;urlset&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:xhtml=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;loc&amp;gt;&lt;/span&gt;https://jsguru.io/what-we-do&lt;span class="nt"&gt;&amp;lt;/loc&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;xhtml:link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; 
                &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"x-default"&lt;/span&gt; 
                &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;xhtml:link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt;
                &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"de"&lt;/span&gt;
                &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/de/was-wir-tun"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;xhtml:link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt;
                &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;
                &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jsguru.io/what-we-do"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;lastmod&amp;gt;&lt;/span&gt;2018-08-28T09:24:19+00:00&lt;span class="nt"&gt;&amp;lt;/lastmod&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;priority&amp;gt;&lt;/span&gt;1.00&lt;span class="nt"&gt;&amp;lt;/priority&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/urlset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IMPORTANT - you should always provide the full link including the protocol (also known as an absolute link) to the canonical or hreflang link tags!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can read more in-depth about localization, hreflang tags and an additional approach to localization I didn't cover &lt;a href="https://support.google.com/webmasters/answer/189077#language-codes"&gt;here&lt;/a&gt;.&lt;br&gt;
Here are some tools which can be helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.aleydasolis.com/english/international-seo-tools/hreflang-tags-generator/"&gt;Hreflang tag generator&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://hreflang.ninja/"&gt;Hreflang tag validation tool&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  7. Images and Videos
&lt;/h1&gt;

&lt;p&gt;When it comes to images you should always add the alt attribute which contains the textual description of the image. The benefits of adding alt attributes are twofold, firstly it will make your website more accessible, the visually impaired people will get the description of the image, and secondly Google will be able to understand the context of your images which will, as a result, increase your visibility in the search results both on the general search and image search.&lt;/p&gt;

&lt;p&gt;Same goes for the videos as well. No matter whether you are adding them directly on your website or on platforms like Youtube/Vimeo you should always provide transcripts. Google can't process images and videos, the only way search engines can discern their content is by textual descriptions.&lt;/p&gt;
&lt;h1&gt;
  
  
  8. Google Structured Data
&lt;/h1&gt;

&lt;p&gt;If you ever thought about SEO being a black box, wait 'till you start with Google Structured Data, that is a black Pandora's box. There's no closing this lid when you open it.&lt;/p&gt;

&lt;p&gt;This is such a vast topic that it deserves a whole new blog post in itself, but I'll try to cover the basics here and provide you with some helpful links.&lt;/p&gt;

&lt;p&gt;Google Structured Data is an implementation of the Schema.org standard for rich data. Google uses this data to fill it's Knowledge Graph, and show you rich search results a.k.a. &lt;a href="https://webmasters.googleblog.com/2016/05/introducing-rich-cards.html"&gt;Google Rich Cards&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's more, you can do everything right and your structured data might still not appear in the search results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using structured data enables a feature to be present, it does not guarantee that it will be present. &lt;br&gt;
The Google algorithm tailors search results to create what it thinks is the best search experience for a user, depending on many variables, including search history, location, and device type. &lt;br&gt;
In some cases, it may determine that one feature is more appropriate than another, or even that a plain blue link is best. - per &lt;a href="https://developers.google.com/search/docs/guides/sd-policies"&gt;Google's Policy&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can provide the structured data in three formats, but Google recommends &lt;a href="https://json-ld.org/"&gt;JSON-LD&lt;/a&gt; so we will concentrate on that format. Here is an example of how it looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="application/ld+json"&amp;gt;
    {
         "@context": "http://schema.org",
         "@type":"LocalBusiness",
         "address": {
             "@type": "PostalAddress",
             "addressLocality": "Manhattan",
             "addressRegion":  "NY",
             "postalCode":"10036",
             "streetAddress": "400 Broadway"
         },
         "description": "This is your business description.",
         "name": "Craig's Car Repair",
         "telephone": "555-111-2345",
         "openingHours": "Mo,Tu,We,Th,Fr 09:00-17:00",
         "geo": {
             "@type": "GeoCoordinates",
             "latitude": "20.75",
             "longitude": "13.98"},
             "sameAs" : [
                 "http://www.facebook.com/example",
                 "http://www.twitter.com/example",
                 "http://plus.google.com/example"
             ]
    }
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have an example of &lt;em&gt;LocalBusiness&lt;/em&gt; entity which is a subset of &lt;em&gt;Organization&lt;/em&gt; entity. You should always try to be as specific as possible with structured data and use the most narrow definition of the entity as in this example. Additionally, you should always try to provide all possible attributes.&lt;/p&gt;

&lt;p&gt;You can find example snippets that have been tried and tested by the community on this &lt;a href="https://jsonld.com/"&gt;link&lt;/a&gt;, just replace the values with your own.&lt;/p&gt;

&lt;p&gt;I also recommend &lt;a href="https://technicalseo.com/seo-tools/schema-markup-generator/"&gt;Merkle structured data generation tool&lt;/a&gt; for starters, and later when you get a better understanding of how everything works you can expand on the generated data with additional properties.&lt;/p&gt;

&lt;p&gt;Another option is to use &lt;a href="https://support.google.com/webmasters/topic/2774098?hl=en&amp;amp;ref_topic=2692946"&gt;Data Highlighter&lt;/a&gt;, it is a tool within Google Search Console under Search Appearance section, but it is currently only visible in the old view! Google is currently rolling out a new Search Console so I'm not sure about the future of this tool, it is to be determined.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where should you put your structured data?
&lt;/h3&gt;

&lt;p&gt;Structured data should go in the head of the HTML document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{...}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one general rule of thumb that you should adhere to, all the data that you've put in the script tag should be actually visible on that page. For more info, you should consult the Google Guidelines.&lt;/p&gt;

&lt;p&gt;Here are some links that could be helpful, as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/search/docs/guides/intro-structured-data"&gt;Intro to structured cards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/search/docs/guides/search-gallery"&gt;Guides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://search.google.com/test/rich-results"&gt;Rich Cards Search Results Testing Tool&lt;/a&gt; &lt;em&gt;(currently in beta and limited to following entities: &lt;a href="https://developers.google.com/search/docs/data-types/job-posting"&gt;Job posting&lt;/a&gt;, &lt;a href="https://developers.google.com/search/docs/data-types/recipe"&gt;Recipe&lt;/a&gt;, &lt;a href="https://developers.google.com/search/docs/data-types/course"&gt;Course&lt;/a&gt;, &lt;a href="https://developers.google.com/search/docs/data-types/media"&gt;TV and Movie&lt;/a&gt;, &lt;a href="https://developers.google.com/search/docs/data-types/event"&gt;Event&lt;/a&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://search.google.com/structured-data/testing-tool"&gt;Google Structured Data Validation Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codelabs.developers.google.com/codelabs/structured-data/#0"&gt;Google's Simple Tutorial on How to Add Rich Cards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  9. Google Local Business
&lt;/h1&gt;

&lt;p&gt;Google Business, among other things, is essentially a more user-friendly way of adding LocalBusiness structured data, and you should definitely do it!&lt;/p&gt;

&lt;p&gt;If your business has multiple locations you should add all of them. It is best to combine this method and adding structured data manually because if Google's Knowledge Graph is populated with your social media pages and B2B platforms like &lt;a href="https://clutch.co/profile/jsguru"&gt;Clutch&lt;/a&gt; it will automatically link them to your business and your reviews will be shown in the rich results.&lt;/p&gt;

&lt;p&gt;There's nothing much to add here, let's move on!&lt;/p&gt;

&lt;h1&gt;
  
  
  10. Blog
&lt;/h1&gt;

&lt;p&gt;Blog is still the &lt;em&gt;Holy Grail&lt;/em&gt; of SEO and Digital Marketing. Despite the over-saturation with articles on many topics, this is still the best organic way to build links and increase traffic to your website.&lt;/p&gt;

&lt;p&gt;You should try to publish regularly, but you shouldn't sacrifice quality over quantity, Google's algorithms have shifted more towards quality vs. quantity in recent years. Not only do they look for quality in the content but the quality of the links that lead to it as well.&lt;/p&gt;

&lt;p&gt;When it comes to the blog the only dilemma you can have is whether to host it on a subdomain e.g. blog.jsguru.io or a subfolder &lt;a href="https://jsguru.io/blog"&gt;jsguru.io/blog&lt;/a&gt;. &lt;br&gt;
Well, actually it's not a dilemma, you should &lt;a href="https://www.smartinsights.com/search-engine-optimisation-seo/internal-linking-strategy/which-is-best-for-blog-seo-subdomain-or-subfolder/"&gt;host it in a subfolder&lt;/a&gt; because subdomains are treated as different domains by Google so they will need to build their own reputation independently of your main domain. There is no value added to you with this approach.&lt;/p&gt;

&lt;p&gt;When it comes down to the implementation of the blog you should still, at least partially stick to the old-school server-side rendered approach because Google indexing is two-pass, the second pass is for JS only websites which is a week after the initial pass, especially if your business model is centred around publishing. This has been confirmed by a Paul Kinlan on Twitter:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wgykguff--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/2736788281/13811f0063041a72d7ea6ede7b89fedd_normal.png" alt="Paul Kinlan profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Paul Kinlan
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/paul_kinlan"&gt;@paul_kinlan&lt;/a&gt;
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/HenrikJoreteg"&gt;@HenrikJoreteg&lt;/a&gt; Indexing is delayed for pure client side sides. Google indexer is two-pass, first run is without js, then week later it's with is (or there abouts)
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      12:26 PM - 12 Sep 2018
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1039852756113080320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1039852756113080320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1039852756113080320" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  11. Google Page Insights
&lt;/h1&gt;

&lt;p&gt;Performance is one of the major factors of your ranking. The lower the load time of your website the higher your ranking will be, especially when it comes to mobile devices.&lt;/p&gt;

&lt;p&gt;One great tool you can leverage when it comes to performance tweaking is &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;Google Page Insights&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some basic and common ways of improving your website performance are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minify your javascript and css files.&lt;/li&gt;
&lt;li&gt;When adding jpg/jpeg images compress them to 80% of the quality, the difference will not be visible in the web environment but their size will significantly decrease.&lt;/li&gt;
&lt;li&gt;If possible use a cookieless (stateless) domain to serve your static assets like images.
Serving different images for different screen sizes. There is no need to load a 1920x1080px image on a 320px wide screen.&lt;/li&gt;
&lt;li&gt;Lazy loading images - loading images only when they enter the viewport of the device.&lt;/li&gt;
&lt;li&gt;Gzip compression and browser caching (images, javascript, css). Here's a nice tutorial for &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-increase-pagespeed-score-by-changing-your-nginx-configuration-on-ubuntu-16-04"&gt;improving your page insight rank for ngnix servers&lt;/a&gt;. If you're using apache you should look up &lt;em&gt;mod_deflate&lt;/em&gt; and &lt;em&gt;mod_expires&lt;/em&gt; extensions.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html"&gt;script defer and async&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  12. Mobile Responsive and Mobile First Indexing
&lt;/h1&gt;

&lt;p&gt;More and more internet users are coming from mobile devices, actually, they have surpassed the desktop users in general, and according to this trend, Google has shifted its focus on mobile devices several years ago. If you remember Google used to show a tag &lt;em&gt;mobile-friendly&lt;/em&gt; in its search results.&lt;/p&gt;

&lt;p&gt;Nowadays there is no need for it, and having a mobile-friendly website that offers a pleasant experience on all screen sizes is a no-brainer. In order to offer a better mobile UX, some people have sacrificed the content in the mobile versions of their websites.&lt;/p&gt;

&lt;p&gt;With the latest changes to Google Algorithm, now they might pay the price for it. Google has started &lt;a href="https://webmasters.googleblog.com/2018/03/rolling-out-mobile-first-indexing.html"&gt;&lt;strong&gt;mobile first indexing&lt;/strong&gt;&lt;/a&gt;, but what does that mean?&lt;/p&gt;

&lt;p&gt;Previously Google would crawl the desktop version of the website for indexing, from now on, the mobile version will be used for indexing. So if you left out content to fit everything nicely in the smaller screens, your SEO  might suffer. &lt;/p&gt;

&lt;h1&gt;
  
  
  13. Summary
&lt;/h1&gt;

&lt;p&gt;If you've come this far I congratulate you, it has been exhausting for me to write all of this, I can only imagine how it is to read it! Yes, you deserve to pat yourself on the shoulder. &lt;br&gt;
If I wanted you to take anything from this article it would be the following.&lt;/p&gt;
&lt;h4&gt;
  
  
  The three most important factors for good SEO are:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;quality content,&lt;/li&gt;
&lt;li&gt;quality traffic and&lt;/li&gt;
&lt;li&gt;quality links.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As with everything in life quality trumps quantity, long gone are the days where you could just pay for links on some obscure websites or churn out shallow articles that barely touch the topic they are supposed to cover.&lt;br&gt;
And lastly, have patience, these things take time, Google has no infinite amount of resources, and indexing new websites is not really on the top of their priority list, so it might take a few weeks or even months, to start having some real results.&lt;/p&gt;

&lt;p&gt;OMG! I almost forgot I highly recommend you watch this Q&amp;amp;A with Riva from &lt;a href="http://digital4startups.com/"&gt;Digital4Startups&lt;/a&gt; we had the privilege of hosting her in our offices. The video quality su*ks but the audio is the important part anyway!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dFi2JBXG4dg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you go…
&lt;/h2&gt;

&lt;p&gt;If you enjoyed reading this post please share it. You should check out our other publications, you might like them too! We write from time to time about software development, tips and tricks, and how to become a better developer and business person in general. Join us on the journey of constant improvement!&lt;/p&gt;

&lt;p&gt;Follow us on &lt;a href="https://www.facebook.com/jsguruio/"&gt;Facebook&lt;/a&gt;, &lt;a href="https://twitter.com/jsguru_software"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/jsguru"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://medium.com/jsguru"&gt;Medium&lt;/a&gt; or here on &lt;strong&gt;DEV.to&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>google</category>
    </item>
    <item>
      <title>Leaving the Old Ways - jQuery vs React</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Thu, 16 Aug 2018 15:21:30 +0000</pubDate>
      <link>https://dev.to/jsguru_io/leaving-the-old-ways---jquery-vs-react-4f69</link>
      <guid>https://dev.to/jsguru_io/leaving-the-old-ways---jquery-vs-react-4f69</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422989797_react-vs-jquery-header.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422989797_react-vs-jquery-header.png" alt="Main Image, React logo on thumbs up"&gt;&lt;/a&gt;&lt;br&gt;
Contrary to popular belief, React’s biggest use cases are not SPAs, it’s the hybrid apps that are most common, and the best fit in my opinion, in this post I will cover how and why I went from a React hater to a React fanboy, and why React is a perfect replacement for jQuery.&lt;/p&gt;



&lt;p&gt;I used to have some kind of an inner resistance when React and Vue first started to gain traction and were becoming the de facto standard for building modern UIs.&lt;/p&gt;

&lt;p&gt;Yes, I’m purposefully leaving Angular out, even though AngularJS was the pioneer of the front end revolution that brought us web 2.0.&lt;/p&gt;

&lt;p&gt;Angular is philosophically on the completely opposite side of the spectrum, it’s a full-blown SPA framework, whereas React is just a view library, and I’m still not convinced SPAs are the right way and personally I prefer the hybrid approach.&lt;/p&gt;

&lt;p&gt;For all of you that are thinking right now  - “And what about Vue?” , Vue would be somewhere in between these two extremes.&lt;/p&gt;

&lt;p&gt;Contrary to popular belief, React’s biggest use cases are not SPAs, it’s the hybrid apps that are most common, and the best fit in my opinion. Don’t believe me? Well look what Facebook’s Dan Abramov had to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s interesting that React became associated so much with SPAs but Facebook isn’t using it for SPAs (except for the Instagram website and some internal tools) - &lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/dan_abramov"&gt;@dan_abramov&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of my major pet peeves was Webpack and all the tooling they brought with themselves.&lt;/p&gt;

&lt;p&gt;I held a strong opinion that they were introducing unnecessary complexity to the front end, yes they made us developers feel like rocket scientists with the amount of tweaking we had to do and the number of levers and gears we had to pull and turn to make them run, but at the end of the day, did they really add value to the business?&lt;/p&gt;

&lt;p&gt;Did they improve the product and the user experience to warrant a higher maintenance and development cost and a higher barrier of entry for new bloods, when we could have done the same with plain ole jQuery, or even better, vanilla JS?&lt;/p&gt;

&lt;p&gt;After I found out React introduced react-cli I decided to give it another go, and boy oh boy was I pleasantly surprised.&lt;/p&gt;

&lt;p&gt;With the introduction of react-cli (and vue-cli) all that nitty-gritty tooling and those build steps that were equivalent of getting a PhD in Computer Science were out of the way for 80–90% of use cases, although you still had to roll up your sleeves and mess around with webpack for some edge cases.&lt;/p&gt;

&lt;p&gt;Sure if you’re building something fairly simple, may it be a contact form with an Ajax submit or something entirely different but that is simple enough, vanilla JS is, in my opinion, a sound approach, there is no need to roll out the big guns. You can even go with jQuery, but there is really no need for it in today’s world, but that’s a completely different topic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep it simple  -  &lt;em&gt;this should always be your mantra&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In that case, if you were to use a framework, 90% of your code would be the frameworks infrastructure and the rest would be your actual logic. That is a major overkill, you are introducing unnecessary boilerplate and increasing your bundle size which directly impacts performance. Bigger bundle means a lot more bytes have to be sent over the INTERNETZ, so you’re actually costing your business, just because you wanted to use that shiny new thing.&lt;/p&gt;

&lt;p&gt;Oh, you think those milliseconds don’t matter much? Well they can quickly add up, especially on high traffic sites, just because today’s machines are powerful doesn’t mean we should be reckless and throw anything at them, we need to be conservative with our resources.&lt;/p&gt;

&lt;p&gt;Look at it like this, it’s as if you are building a foundation for a ten story building only to put a tent on it.&lt;/p&gt;

&lt;p&gt;React, versus the old way, really comes to shine when you are building complex UIs.&lt;/p&gt;

&lt;p&gt;With React the simplicity of development increases with the complexity of the UI you are building, or in other words, the cost of development is inversely proportional to the complexity in comparison with the vanilla JS/jQuery approach.&lt;/p&gt;

&lt;p&gt;Here’s a little graph for all you visual types.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422990085_react-vs-jquery-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422990085_react-vs-jquery-graph.png" alt="Graph representing how the simplicity of implementation increases with the complexity of your UI when using React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Talk is cheap, let’s get our hands dirty with an example from the real world.&lt;/p&gt;

&lt;p&gt;We have an invoice form, aside from the general data like the date of the invoice, the due date of the invoice, subject etc., the user needs to be able to add/remove invoice items.&lt;/p&gt;

&lt;p&gt;Invoice items, on the other hand, have the following:    &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name and/or the description of the product/service you’re invoicing,&lt;/li&gt;
&lt;li&gt;it's quantity,&lt;/li&gt;
&lt;li&gt;price,&lt;/li&gt;
&lt;li&gt;any discount you may give,&lt;/li&gt;
&lt;li&gt;any penalty interest that incurred,&lt;/li&gt;
&lt;li&gt;then we might have VAT tax or sales tax depending on your country’s laws&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and finally, all the calculations that go with the aforementioned.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422989041_react-vs-jquery-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdelivery.eusi.cloud%2Fapi%2Fv1%2Ff1a4305c-e431-4668-ae4c-02f78c656a41%2Fmedia%2Fs3%2F1534422989041_react-vs-jquery-form.png" alt="Image representing a complex form"&gt;&lt;/a&gt;&lt;br&gt;
You see now how a seemingly simple thing can get complicated quickly?&lt;/p&gt;

&lt;p&gt;With the old approach, you would have to have a lot of things on your mind, you would need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add change event handlers on all the different input fields, and some of them would additionally need to cancel each other out so you would need to track when to detach them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Every time an invoice item is added or removed you would need to manipulate the DOM, by either adding or removing child nodes or writing HTML as a string.&lt;/p&gt;

&lt;p&gt;No matter the choice, you’d need to concatenate some HTML and fill it with variables, which can get unruly pretty fast. ECMA 6 string literals do ease this a bit, but still, it can get cumbersome.&lt;/p&gt;

&lt;p&gt;Imagine a designer changes something, on how many places would you need to changes all those bits that you’re glueing together in your vanilla JS code?&lt;/p&gt;

&lt;p&gt;Another thing you would need to keep in your mind is that if you manipulate DOM as a string you’re killing all the event handlers on those particular DOM elements. Yep, another gotcha moment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Calculations  -  every time an invoice item is added or removed you need to calculate its particular values and in addition update the invoice’s subtotal, tax, total, etc. Essentially you would be creating your own state store.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I probably might have missed a thing or two that would pop up while trying to handle this use case the old way, as it usually is, everything sounds simpler on paper until you start to implement it and a whole new spectrum of cases that need to be handled appears.&lt;/p&gt;

&lt;p&gt;Using React requires a slight shift in your mindset, in a nutshell, you only need to be concerned with one thing, the state. This simplifies the logic immensely, you are only concerned about your state, that is the only thing you need to manipulate, and your invoice input fields and invoice items will be re-rendered according to the changes in your state.&lt;/p&gt;

&lt;p&gt;Let’s take a look at our simplified code example, this might give you a clearer picture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prop-types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceItemForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;subtotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;taxRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;invoiceItems&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&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;handleInputChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addItem&lt;/span&gt; &lt;span class="o"&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;addItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeItem&lt;/span&gt; &lt;span class="o"&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;removeItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handleInputChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taxRate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taxRate&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="nf"&gt;setState&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="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;itemInput&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="c1"&gt;// Clear the last input&lt;/span&gt;
          &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taxRate&lt;/span&gt;&lt;span class="dl"&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                  &lt;span class="nl"&gt;default&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                      &lt;span class="k"&gt;break&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;itemInput&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;itemInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&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;items&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rowIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowIndex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&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="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&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;i&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;rowIndex&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="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;items&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;renderCells&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rowIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cells&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;];&lt;/span&gt;

      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;cells&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;removeItem&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Remove Item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&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;cells&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render &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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;quantity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taxRate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taxRate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subtotal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtotal&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tax&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;total&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nx"&gt;itemInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;handleInputChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Item no.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Description&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Price&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Quantity&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Tax Rate&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Subtotal&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Tax&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Total&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;th&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="si"&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="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;(&lt;/span&gt;
                                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                                    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderCells&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="p"&gt;})&lt;/span&gt;
                    &lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    );
  }
}
export default InvoiceItemForm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vuoala, that’s it!&lt;/p&gt;

&lt;p&gt;Hey, do you have a jQuery app you would like to migrate or are you just trying to figure out which framework would be best for your next million dollar idea? Contact us at &lt;a href="mailto:info@jsguru.io"&gt;info@jsguru.io&lt;/a&gt;, and let that be our headache.&lt;/p&gt;




&lt;h4&gt;
  
  
  Before you go…
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this post please share it. You should check out our other publications, you might like them too! We write from time to time about software development, tips and tricks, and how to become a better developer and business person in general. Join us on the journey of constant improvement!&lt;/p&gt;

&lt;p&gt;Follow us on &lt;a href="https://www.facebook.com/jsguruio/" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt;, &lt;a href="https://twitter.com/jsguru_software" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/company/jsguru" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://medium.com/jsguru" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; or &lt;a href="https://dev.to/jsguru_io"&gt;DEV.to&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://jsguru.io" rel="noopener noreferrer"&gt;jsguru.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>jquery</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Online NPM downloads calculator</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Thu, 21 Jun 2018 14:51:35 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/online-npm-downloads-calculator-a87</link>
      <guid>https://dev.to/blackcat_dev/online-npm-downloads-calculator-a87</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq4a6n5pq8a2fz4xhoco5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq4a6n5pq8a2fz4xhoco5.jpeg" alt="Npm package manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hey guys, long time no read!&lt;/p&gt;

&lt;p&gt;Besides being a &lt;a href="https://medium.com/mop-developers/we-need-t-shaped-full-stack-developers-4c62c9d757a0" rel="noopener noreferrer"&gt;T-shaped full stack developer&lt;/a&gt; at JSGuru (a fancy and made up term I identify with now), additionally I work as part of the sales team and I'm also one of the people that manages our &lt;a href="https://github.com/jsguru-io" rel="noopener noreferrer"&gt;open source efforts&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;All these responsibilities mean that I have quite a few meetings over the week and I need to produce numbers so we can track our analytics, and that includes the number of downloads of our open source projects.&lt;/p&gt;

&lt;p&gt;To make my life a bit easier I made an AI bot that &lt;a href="https://sasablagojevic.com/npm-downloads-calculator" rel="noopener noreferrer"&gt;calculates all downloads for a given NPM package and given period&lt;/a&gt;... lol just jokin', it's not AI, it's just a few if statements and a function here and there. ;)&lt;/p&gt;

&lt;p&gt;A really simple tool but it gets the job done.&lt;/p&gt;

&lt;p&gt;Try it out, it might come useful to you as well. I have a few ideas for new features, I'll be adding them from time to time. :)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Javascript needs competition on the front end. Thoughts?</title>
      <dc:creator>Sasha Blagojevic</dc:creator>
      <pubDate>Sat, 02 Jun 2018 14:18:37 +0000</pubDate>
      <link>https://dev.to/blackcat_dev/javascript-needs-competition-on-the-front-end-thoughts-4kc9</link>
      <guid>https://dev.to/blackcat_dev/javascript-needs-competition-on-the-front-end-thoughts-4kc9</guid>
      <description></description>
      <category>javascript</category>
      <category>thoughts</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
