<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Programming on Stefano Chiodino</title>
    <link>https://stefano.chiodino.uk/tags/programming/</link>
    <description>Recent content in Programming on Stefano Chiodino</description>
    <generator>Hugo -- 0.147.7</generator>
    <language>en</language>
    <lastBuildDate>Tue, 10 Feb 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://stefano.chiodino.uk/tags/programming/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>2026 Is The Year Of Serious AI Engineering</title>
      <link>https://stefano.chiodino.uk/posts/2026-02-10-2026-is-the-year-of-serious-ai-engineering/</link>
      <pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/2026-02-10-2026-is-the-year-of-serious-ai-engineering/</guid>
      <description>&lt;h1 id=&#34;llms-wont-replace-engineers&#34;&gt;LLMs won&amp;rsquo;t replace engineers&lt;/h1&gt;
&lt;p&gt;AI is improving at a sustained, impressive pace. During 2025, models went from being a novelty with potential to being a genuinely useful tool that I use daily. The improvement in both models and tooling has been remarkable.&lt;/p&gt;
&lt;p&gt;That said, I&amp;rsquo;m still not convinced that LLMs will replace software engineers. It will just make engineers more productive and reduce the pressure on the workforce of this industry. The day we achieve artificial general intelligence everything will change, then it won&amp;rsquo;t just be the software engineers job that we should be worried about. Until then, what we have is a very capable tool, a leverage that landed quicker than probably any other before it.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="llms-wont-replace-engineers">LLMs won&rsquo;t replace engineers</h1>
<p>AI is improving at a sustained, impressive pace. During 2025, models went from being a novelty with potential to being a genuinely useful tool that I use daily. The improvement in both models and tooling has been remarkable.</p>
<p>That said, I&rsquo;m still not convinced that LLMs will replace software engineers. It will just make engineers more productive and reduce the pressure on the workforce of this industry. The day we achieve artificial general intelligence everything will change, then it won&rsquo;t just be the software engineers job that we should be worried about. Until then, what we have is a very capable tool, a leverage that landed quicker than probably any other before it.</p>
<p>I&rsquo;ve been doing this job for 15 years. It is obviously impossible to tell where the LLM&rsquo;s capabilities will land, however my gut feeling is that there is only so much that we can squeeze out it. Based on my current conversation with Opus 4.6, which I consider to be the best of the best at the moment, it is incredibly capable but it is no senior software engineer. It is like dealing with a smart junior engineer that works at 100 times the speed.</p>
<h1 id="the-easy-part-easier-the-hard-part-harder">The easy part easier, the hard part harder</h1>
<p>There&rsquo;s an excellent article by Blundergoat called <a href="https://www.blundergoat.com/articles/ai-makes-the-easy-part-easier-and-the-hard-part-harder">AI Makes the Easy Part Easier and the Hard Part Harder</a> that I agree with completely.</p>
<p>Writing code was never the hard part. It&rsquo;s writing code well. It is understanding the problem, navigating ambiguity, knowing <em>why</em> a particular approach is the right one, and having the judgment to make architectural decisions.</p>
<p>This is exactly why you should lean into AI for the easy parts and stop fighting it on the hard parts. Use it where it shines, go old school where it doesn&rsquo;t.</p>
<p>There are still plenty of times where even the most capable model, across multiple providers, leads me absolutely nowhere and I have to do things the old-fashioned way. In the previous year, I invested a significant amount of my time into experimenting with the capabilities of AIs and I&rsquo;ve started to understand what it is good at and what it is not good at. And so, being able to speed up my work when I&rsquo;m quite confident that LLM will do well and not waste my time where I am not confident that it will, is what I think is the trick that a lot of people are missing out on.</p>
<h1 id="from-assembly-to-english">From assembly to English</h1>
<p>Here&rsquo;s how I see the current landscape.</p>
<p>Consider the history of programming: machine code was written for computers, by humans who had to think like computers. Then came C, relatively close to the metal, but more readable, more expressive. Then Python built on top of it, abstracting further. Each layer made things easier to read, easier to express, easier to reason about. The human brain is capable of infinite wisdom and capacity of understanding, however, in our day-to-day, this amount is actually very finite. For example, Python allows us for our thoughts to go much further because they are abstracted much more than C and assembly were capable of.</p>
<p>Now we&rsquo;ve added another layer: English.</p>
<p>We&rsquo;ve gone from a language designed for computers, to a compromise between computer and human language (at varying degrees), to the actual native language of the programmer. AI is giving us a similar leap over high-level languages as high-level languages gave us over assembly.</p>
<p>However, here I should also address another concern of mine, and that is that our natural language is actually not as perfect as we usually like to think. When you express a concept to somebody, you may have to go into a certain level of detail that varies depending on shared context and how much you think your interlocutor is going to understand from what you&rsquo;re saying. And so, in real time, you adapt and express more or less, depending on the situation. You will certainly be familiar with how sometimes the thoughts that you have expressed in your native language may have not landed in the way that you thought they should have.</p>
<h1 id="the-real-bottleneck-is-human-willpower">The real bottleneck is human willpower</h1>
<p>I&rsquo;ve been saying this for years: the limiting factor in programming is not the computer or the language. It&rsquo;s the human brain, but in particular, not even necessarily our intelligence. We only have so much willpower to chase down a bug. So much memory to hold a system in our heads. So much patience to set up a test environment, write boilerplate, or untangle someone else&rsquo;s abstractions.</p>
<p>This is why I&rsquo;ve always advocated for keeping code simple, not over-optimising, and making things easier for your future self. If you make things easier for future-you, then future-you will have more willpower to spend on the actual investigation, planning, etc.</p>
<p>The interface between humans and the power of computers has always been the bottleneck. When higher-level languages were introduced, humans suddenly achieved much more — not because they got smarter, but because the interface got better, the friction lower. The exact same thing is happening now with AI.</p>
<h1 id="im-still-doing-the-thinking">I&rsquo;m still doing the thinking</h1>
<p>I&rsquo;ve read people on Hacker News saying they miss &ldquo;doing the thinking&rdquo; now that AI is involved. I disagree. I&rsquo;m still doing the same amount of thinking. Maybe even more, because I can now tackle problems I would have previously shelved as too laborious.</p>
<p>Perhaps those people mean they miss tinkering with lower-level details, which is perfectly valid. I understand the appeal. But I don&rsquo;t feel like AI is doing the thinking for me. It&rsquo;s more like working together: I think, I direct, I review, I decide. The AI helps me execute faster. The thinking is still mine.</p>
<p>The complaint that they miss doing the thinking is the same as saying &ldquo;I miss setting the registries of the CPU manually now that I have a higher level language that doesn&rsquo;t require me to do it&rdquo;. By all means, you can go and set the registries of the CPU manually, but is that really practical? Aren&rsquo;t there other interesting problems that you can tackle with how much brain power you have freed up?</p>
<h1 id="what-ai-has-unlocked-for-me">What AI has unlocked for me</h1>
<p>Now that I feel that I have a good understanding as to where I can leverage AI and the very latest models are generally good, I&rsquo;d say that <strong>in the best cases</strong> I can achieve the mythical 10x programming. Maybe even more. Side projects that I always wanted to do but never had the time or energy for are now feasible. Investigations that used to be laborious are quicker. Things that were annoying to put together now have shortcuts.</p>
<p>I built a few VS Code extensions that I&rsquo;d wanted for years — small tools to navigate code more effectively. I&rsquo;m particularly proud of one that lets you navigate to any line of Python code just by having the stack trace in your clipboard. It&rsquo;s not perfect, but it&rsquo;s something I always wanted and never would have built without AI. Not because I wasn&rsquo;t capable, but because the friction to work in typescript and understand how to write a VScode extension was too high.</p>
<p>I&rsquo;ve built machine learning models to predict delinquency for invoices at Yelp. I trained a model to recognise my black cat compared to other black cats. Small things, silly things, practical things — all of them now within reach.</p>
<p>And I&rsquo;m writing a book. This is something I&rsquo;ve always wanted to do, but it always seemed too much — too many words, too much structure, too much effort on top of a full-time job.</p>
<h1 id="practical-advice">Practical advice</h1>
<h2 id="ai-is-great-for-greenfield-less-so-for-production">AI is great for greenfield, less so for production</h2>
<p>Accept this and work with it. For new projects, AI is extraordinary. For complex, established codebases with years of accumulated decisions, it struggles. That&rsquo;s fine, leverage the strengths and avoid the weaknesses.</p>
<h2 id="plan-ahead-and-explain-well">Plan ahead and explain well</h2>
<p>You reap what you sow. If you express something in as few words as possible and hit enter don&rsquo;t complain if the response isn&rsquo;t what you were hoping for. Then you&rsquo;ll review it, redo it, and start losing patience. You may even think that LLMs are a fad, and you would be better off without it.</p>
<p>Instead: explain things well, once. Link the files you refer to. Do some planning together with the AI before you start. Then execute your plan. The upfront investment pays for itself.</p>
<h2 id="agentsmd-is-the-most-important-thing-you-should-configure">agents.md is the most important thing you should configure</h2>
<p>The file <code>agents.md</code> is probably the single most powerful leverage point you have, and I don&rsquo;t see this being said enough, or strongly enough.</p>
<p>Every single time you open a new chat, it&rsquo;s as if you&rsquo;re talking to a brand new engineer on their first day. There is absolutely no reason not to invest time in writing, optimising, and tuning these files.</p>
<h2 id="use-ai-to-use-ai">Use AI to use AI</h2>
<p>I use AI to help me use AI better. I ask it what prompt would work best, whether syntax and grammar matter when writing prompts, whether the order of instructions makes a difference. If there&rsquo;s a disagreement and I think the AI should have known better, I ask it why it thinks the disagreement originated and how we can prevent it. More often than not, I end up having the AI update my <code>agents.md</code> file to avoid the same issue next time. I review everything, of course.</p>
<h2 id="experiment-more">Experiment more</h2>
<p>Think about all the things you couldn&rsquo;t do before. Just try asking AI to do something, go on, just for the lols. See how far you can push it. You might be surprised.</p>
<p>When making the placeholder website for my book I thought &ldquo;Now that I have made the cover image I wonder if I can make the book in 3D&rdquo;. The result, after several iterations, <a href="https://orchidomania.com/">is quite stunning</a>.</p>
<h2 id="llms-are-cheerful-but-im-grumpy">LLMs are cheerful but I&rsquo;m grumpy</h2>
<p>LLMs are tuned by companies that want to make money. I imagine that those companies have figured out that making LLMs sound cheerful and overconfident makes users happier. As long as the user is sold then the bottom line is subscriptions. A suppose that a fair, balanced and trustworthy LLM wouldn&rsquo;t sell as much. They are accommodating to a fault. They will compliment your awesome ideas. &ldquo;Great catch!&rdquo;. &ldquo;You are absolutely right&rdquo;.</p>
<p>LLMs can&rsquo;t be trusted. I&rsquo;ve addressed this in my own <code>agents.md</code> by asking them to label their own confidence about their statements, to not sound like cheerleaders, and to flag uncertainty explicitly. You should do the same.</p>
<h1 id="case-in-point-this-post">Case in point: this post</h1>
<p>This post you&rsquo;re reading right now is AI-generated. But the difference between a low-quality AI post and a high-quality one is the same as the difference between low-quality and high-quality code. I carefully selected what to say. I let AI help me write it. Then I checked everything, added a little, rewrote some parts, adapted some more. Two passes. I have probably saved some time, and in the meantime I migrated the website from <a href="prose.sh">prose.sh</a> to Hugo on Cloudflare. Why not.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Advice to new software engineers</title>
      <link>https://stefano.chiodino.uk/posts/2022-02-12-advice-to-new-software-engineers/</link>
      <pubDate>Sat, 12 Feb 2022 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/2022-02-12-advice-to-new-software-engineers/</guid>
      <description>&lt;h1 id=&#34;ask-for-more-money&#34;&gt;&lt;strong&gt;Ask for more money&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Have you received a new job offer? Ask for more money. Have you received a pay raise? Ask for more money. If you cringe at the idea of asking for more money, you likely really need to ask for more money.&lt;/p&gt;
&lt;p&gt;Every year you have (hopefully) improved. You are wiser, learned some tech for a whole year, learned the processes, met the people, and therefore are worth more. So ask to be remunerated accordingly. Every time you receive a pay rise, google for the current inflation and discount that percentage from it. Lead the conversation this way during the meeting.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="ask-for-more-money"><strong>Ask for more money</strong></h1>
<p>Have you received a new job offer? Ask for more money. Have you received a pay raise? Ask for more money. If you cringe at the idea of asking for more money, you likely really need to ask for more money.</p>
<p>Every year you have (hopefully) improved. You are wiser, learned some tech for a whole year, learned the processes, met the people, and therefore are worth more. So ask to be remunerated accordingly. Every time you receive a pay rise, google for the current inflation and discount that percentage from it. Lead the conversation this way during the meeting.</p>
<h1 id="never-tell-recruiters-how-much-you-earn-or-want"><strong>Never tell recruiters how much you earn, or want</strong></h1>
<p>There is no way any of this is going to play in your favor. Always decline to say how much you are currently making, or want. On the contrary, always ask for a salary bracket.</p>
<h1 id="ask-why"><strong>Ask why</strong></h1>
<p>Workers know how, gods know why.</p>
<p>Ask why, always. Why should you ask why you say? You learn quickly, I&rsquo;m impressed! People tend to tell you how to solve a problem, rather than what the problem is, and they may not have considered certain things. This is particularly true when talking to non-engineers. Knowing why you are doing something also strengthens your understanding, and allows you to do a better job.</p>
<p>You should also keep this in mind when you are asking for help yourself: don&rsquo;t just say what you need help with, start saying why you are doing it!</p>
<p>If you are new and feel like it would cause friction, just say that you really really want to learn.</p>
<h1 id="doing-vs-learning"><strong>Doing vs. learning</strong></h1>
<p>I&rsquo;m more of a doer, and this had a negative impact over time. The pressure to deliver and prove yourself will push you to try and cut the learning short, and push forward. This is what my friend Lee calls “programming by coincidence”.</p>
<p>So, remember to take it slowly, and research a topic before jumping in and try to fix something you don’t know well. It will pay dividends.</p>
<h1 id="impostor-syndrome"><strong>Impostor syndrome</strong></h1>
<p>It&rsquo;s important for you to understand that you will always feel like you don&rsquo;t know what you are doing. That&rsquo;s because you think most of your job should be &ldquo;doing&rdquo;, but in reality it is to find out how or even what you are doing.</p>
<p><a href="https://knowyourmeme.com/photos/1652030-2meirl4meirl"><img loading="lazy" src="https://i.kym-cdn.com/photos/images/original/001/652/030/c47.png" title="When do I stop pretending?"></a></p>
<p>The more you know, the more you know what you don’t know.</p>
<p><a href="https://xkcd.com/1954/"><img loading="lazy" src="https://imgs.xkcd.com/comics/impostor_syndrome_2x.png" title="XKCD on impostor syndrome"></a></p>
<p>I’m often asked “when will this stop?”. If you do things right, it will never stop.</p>
<p><a href="https://twitter.com/adammgrant/status/1459894544884015113"><img loading="lazy" src="https://pbs.twimg.com/media/FEKWJr6XwAM3dRb?format=jpg&name=orig"></a></p>
<h1 id="career-leverage-points"><strong>Career leverage points</strong></h1>
<p>There are a few things in your career that you can get a lot of leverage out of. Interviewing and your CV are a couple of them.</p>
<p>Invest a lot of time on your CV. Be 100% sure there are no typos. Keep it around 2 pages. Sell yourself without lying.</p>
<p>I revise mine often, mostly adding whatever comes to mind. Afterall, it will come with you for decades to come!</p>
<p>I’ve probably done more than a hundred interviews. I’ve also run dozens of them as an interviewer, which by the way helps (so go on sign up to run interviews for your company now!). This helps me to know what interviewers want, perform better in tech tests, being more confident, etc. It reduces the cognitive load during interviews, allowing time to think at a higher level.</p>
<p>Buy “Cracking the Coding Interview “by Gayle Laakmann McDowell, it’s worth it!</p>
<h1 id="ownership"><strong>Ownership</strong></h1>
<p>Try to make all problems your problems and people will love you for it. In the right company, you’ll also get rewarded for it.</p>
<h1 id="work-life-balance"><strong>Work life balance</strong></h1>
<p>Make the most of your 7/8 hours of work every day, then switch off. If you can&rsquo;t finish something that&rsquo;s too bad, there is always tomorrow. Do you have too much to do and you can&rsquo;t possibly fit it in your working day? That&rsquo;s too bad, but your manager/team-lead should probably have planned things so that they could fit in your working day.</p>
<p>I only have two exceptions to this rule:</p>
<ul>
<li>
<p>If you screwed something up, you need to clean up after yourself.</p>
</li>
<li>
<p>As a one-off, if there is a particular deadline, go-live, or the like, be flexible.</p>
</li>
</ul>
<h1 id="yes-but"><strong>Yes, but</strong></h1>
<p>Whether it&rsquo;s been planned in an agile fashion, or another way, you&rsquo;ll have a certain stream of work. At some point you&rsquo;ll be asked to work on something else. This usually comes in the form of &ldquo;could you just&hellip;&rdquo; or &ldquo;spend 5 minutes on&hellip;&rdquo;. The person you are talking to probably don&rsquo;t realize how complicated things are, hence they think it&rsquo;s a &ldquo;5 minutes&rdquo; job. But there is no such thing.</p>
<p>When you work, your time doesn&rsquo;t belong to you, you are selling it, and if someone asks you to do something the only plausible answer is &ldquo;yes&rdquo;. Yes, but.</p>
<blockquote>
<p>&ldquo;Yes, but unfortunately this is not quite a 5 minutes job. If I do this I won&rsquo;t be able to hit the deadline we set during our sprint planning. But if you are happy with this and you have communicated to the right people I&rsquo;ll be happy to do this&rdquo;.</p></blockquote>
<p>I&rsquo;ve been delivering this line or variations thereof for the best part of a decade. It never fails me.</p>
<h1 id="communication"><strong>Communication</strong></h1>
<p>Invest a lot of time and effort in communication. Nowadays a lot of this happens in emails, chats, etc, and this gives you the chance to be more mindful about it. Read back what you are about to send (it helps if you read it out loud). Make it as short as possible. Rewrite any ambiguities. Don’t show off.</p>
<p>I’ve done a business writing course on Coursera and I’d recommend it to anybody. It’s a great investment.</p>
<h1 id="honesty"><strong>Honesty</strong></h1>
<p>Always try to be honest, people can tell subconsciously even if they don’t catch you. Even if you get away with it, it&rsquo;s only a matter of time. Lack of honesty breaks trust, and we are nothing without it.</p>
<p>If you have a problem, communicate. Do you think you won’t make a deadline? Do you think you are doing something that’s not worth your while? Or is there something else that should be done? Speak up!</p>
<h1 id="people-are-not-computers"><strong>People are not computers</strong></h1>
<p>In the long term, this is a team sport, and “people” is one of the biggest problems to crack. You may be in the business because you like to write software, but to do well in this job you need to deal with people effectively.</p>
<p>Learn how to:</p>
<ul>
<li>Persuade people by not creating friction (e.g. “I’m right and you are wrong, and I’m going to prove it to you”) but rather bringing them on a journey with you.</li>
<li>Build relationships. Gently and tactfully ask personal questions. Ask colleagues to go out. Etc.</li>
<li>Give in a little sometimes.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>What you should know about reviewing code</title>
      <link>https://stefano.chiodino.uk/posts/2021-10-23-what-you-should-know-about-reviewing-code/</link>
      <pubDate>Sat, 23 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/2021-10-23-what-you-should-know-about-reviewing-code/</guid>
      <description>&lt;p&gt;Here are some non obvious thoughts about reviewing code.&lt;/p&gt;
&lt;h1 id=&#34;-it-depends&#34;&gt;&amp;hellip; it depends&lt;/h1&gt;
&lt;p&gt;This has little to do with code reviews, yet it&amp;rsquo;s some of the best advice you&amp;rsquo;ll ever find around: it depends. Don&amp;rsquo;t take this article, or any other articles out there, for gospel.&lt;/p&gt;
&lt;h1 id=&#34;when-you-are-looking-for-a-review&#34;&gt;When you are looking for a review&lt;/h1&gt;
&lt;h2 id=&#34;do-your-homework&#34;&gt;Do your homework&lt;/h2&gt;
&lt;p&gt;Do not submit code for reviewing before you reviewed it yourself. It&amp;rsquo;s annoying. It shouldn&amp;rsquo;t be the reviewer&amp;rsquo;s job to tell you to remove print statements, write tests, etc.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Here are some non obvious thoughts about reviewing code.</p>
<h1 id="-it-depends">&hellip; it depends</h1>
<p>This has little to do with code reviews, yet it&rsquo;s some of the best advice you&rsquo;ll ever find around: it depends. Don&rsquo;t take this article, or any other articles out there, for gospel.</p>
<h1 id="when-you-are-looking-for-a-review">When you are looking for a review</h1>
<h2 id="do-your-homework">Do your homework</h2>
<p>Do not submit code for reviewing before you reviewed it yourself. It&rsquo;s annoying. It shouldn&rsquo;t be the reviewer&rsquo;s job to tell you to remove print statements, write tests, etc.</p>
<p>I usually review the code before every commit, but when I&rsquo;m almost ready to submit my code for a review I give it a once-over to make sure it&rsquo;s ready.</p>
<p>Make sure the tests pass, you didn&rsquo;t leave TODOs, you are even accomplishing what you set out to, etc.</p>
<p>If you aren&rsquo;t sure about your code then don&rsquo;t ask for a code review, ask for an opinion, help, or pair programming. Never submit code you are not sure it&rsquo;s correct.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Swiss_cheese_model">Swiss cheese model</a> refers to a security model, but applies to so much more, including code quality and code review. The less confident you are about your code, the bigger the holes in your slice of cheese.</p>
<h2 id="make-sure-the-reviewer-is-happy-before-progressing">Make sure the reviewer is happy before progressing</h2>
<p>Whatever the process in your company/project/team, make sure the reviewer is happy to proceed before you move forward. Don&rsquo;t go resolving all the issues they raised and click merge.</p>
<h1 id="when-you-are-reviewing">When you are reviewing</h1>
<h2 id="it-takes-time">It takes time</h2>
<p>To review code it takes approximately 1/10 of the time it took to write it. Take your time, it&rsquo;s not a race, and it&rsquo;s important.</p>
<h2 id="tailor-your-review-to-your-audience">Tailor your review to your audience</h2>
<p>When you know your colleagues you&rsquo;ll start to be able to conduct yourself differently, depending on their strengths and weakness. I know a developer who is thorough, writes tests, etc. I reviewed thousands and thousands of lines of their code, and all I ever found was maybe a forgotten print statement. So now, whenever I review their code, I sit back, scroll a bit faster, and maybe even focus on learning from them. When I review some other people&rsquo;s code I know that I need to check every comma, insist good code style is maintained, etc.</p>
<h2 id="you-are-dealing-with-people">You are dealing with people</h2>
<p>There will be times that you&rsquo;ll be technically correct. The best kind of correct.</p>
<p><img alt="You are technically correct. The best kind of correct." loading="lazy" src="https://comb.io/LxbJyb.gif" title="Technically correct"></p>
<p>But how should you express yourself?</p>
<p>Let&rsquo;s be honest, people skills are not rampant in this industry. Computers don&rsquo;t care how you express your thoughts to them, but people do, and software development is a team sport. Whenever you find something that&rsquo;s not quite right, please, try to express your thoughts politely.</p>
<p>&ldquo;This is wrong because&hellip;&rdquo; <code>CTRL+A DEL</code> &ldquo;Have you considered&hellip;&rdquo;. What&rsquo;s the difference between these two? One may upset some people, the other is less likely to do so. One is a critic, the other one a suggestion.</p>
<p>Sometimes niceties run short, and you may have to tell people that what they are doing is not good, but being right is not a good reason for being nasty.</p>
<h2 id="its-not-time-for-debates">It&rsquo;s not time for debates</h2>
<p>Tabs or spaces? Code reviews are not the right venue to establish it! In part because it&rsquo;s obviously spaces, but also because your opinion doesn&rsquo;t matter at code review time.</p>
<p>There should be relatively specific code styles for your company/project/team. Hopefully they are up for debate.</p>
<p>You prefer double quotes to single ones? One for the committee, not for a merge/pull request.</p>
<p>See this <a href="https://www.youtube.com/watch?v=wf-BqAjZb8M">insightful talk</a> from Raymond Hettinger on PEP8, which dictates the style for Python.</p>
<h2 id="start-from-understanding-what-needs-to-be-done">Start from understanding what needs to be done</h2>
<p>One thing is to scan some code to find bugs, but you also need to make sure that the code is achieving the right thing. Start from the ticket, or wherever else the code came from, to make sure it&rsquo;s doing what it should.</p>
<h2 id="perfect-is-the-enemy-of-good">Perfect is the enemy of good</h2>
<p>My friend James is a ninja 🥷 hacker 👨‍💻, yet he&rsquo;s not going to pester you to make your code perfect. Why? Because when work needs to be done, good is good enough.</p>
<p>Be like James.</p>
<p>This is just another area where the <a href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto principle (A.K.A. 80/20 rules)</a> applies. Don&rsquo;t sweat the small stuff.</p>
<h1 id="other-general-advice">Other general advice</h1>
<h2 id="double-tap">Double tap</h2>
<p>Not sure? Ask for more people to review! If either party feels unsure, then it&rsquo;s fair to say you&rsquo;d benefit from having someone else reviewing the same code.</p>
<p>I already mentioned the <a href="https://en.wikipedia.org/wiki/Swiss_cheese_model">Swiss cheese model</a>. Here you are adding more slices to catch more problems.</p>
<h2 id="other-resources">Other resources</h2>
<p><a href="https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/">Smartbear&rsquo;s Best Practices for Code Review</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Change all Github email addresses</title>
      <link>https://stefano.chiodino.uk/posts/2021-01-19-change-all-github-email-addresses/</link>
      <pubDate>Tue, 19 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/2021-01-19-change-all-github-email-addresses/</guid>
      <description>&lt;p&gt;I have found out that recruiters have hunted me down using the email address I have inadvertently used to commit in Github. Unfortunately it&amp;rsquo;s not straightforward to replace this, but here is what I&amp;rsquo;ve done:&lt;/p&gt;
&lt;p&gt;From an &lt;strong&gt;empty folder&lt;/strong&gt; clone all your public repos using github API. Replace &lt;code&gt;YOUR-GITHUB-USERNAME&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;for SSH_URL in $(curl -s https://api.github.com/users/YOUR-GITHUB-USERNAME/repos | grep ssh_url | cut -d&amp;#39;&amp;#34;&amp;#39; -f 4)
do
    git clone $SSH_URL
done
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a good time to &lt;strong&gt;BACKUP THIS ENTIRE FOLDER&lt;/strong&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have found out that recruiters have hunted me down using the email address I have inadvertently used to commit in Github. Unfortunately it&rsquo;s not straightforward to replace this, but here is what I&rsquo;ve done:</p>
<p>From an <strong>empty folder</strong> clone all your public repos using github API. Replace <code>YOUR-GITHUB-USERNAME</code>.</p>
<pre tabindex="0"><code>for SSH_URL in $(curl -s https://api.github.com/users/YOUR-GITHUB-USERNAME/repos | grep ssh_url | cut -d&#39;&#34;&#39; -f 4)
do
    git clone $SSH_URL
done
</code></pre><p>This is a good time to <strong>BACKUP THIS ENTIRE FOLDER</strong>.</p>
<p>For every repo just cloned, run <code>git filter-branch</code> and check the committer and author email (they are two different things).</p>
<p>I had multiple emails, and each needs to be checked for each case. This looks crazy syntactically, but still easier than an <code>in</code> operator in bash&hellip;
You&rsquo;ll need one line to test for each case you may have used like &ldquo;EmailOne&rdquo;, &ldquo;emailone&rdquo;, &ldquo;emailTwo&rdquo;, etc, depending on how you tend to type this.</p>
<p>Force push after this is done. I have commented out this line because you&rsquo;ll probably want to check what happened (use <code>git log</code>).</p>
<pre tabindex="0"><code>for dir in ./*/
do
    cd $dir || exit
    pwd
    FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --commit-filter &#39;
    if [ &#34;$GIT_COMMITTER_EMAIL&#34; = &#34;ONE.OF@YOUR.EMAILS&#34; ] \
      || [ &#34;$GIT_COMMITTER_EMAIL&#34; = &#34;ANOTHER.ONE.OF@YOUR.EMAILS&#34; ] \
      || [ &#34;GIT_AUTHOR_EMAIL&#34; = &#34;ONE.OF@YOUR.EMAILS&#34; ] \
      || [ &#34;GIT_AUTHOR_EMAIL&#34; = &#34;ANOTHER.ONE.OF@YOUR.EMAILS&#34; ];
    then
        GIT_COMMITTER_EMAIL=&#34;i-dont-want@to-be-recuited.thank-you-very-much&#34;;
        GIT_AUTHOR_EMAIL=&#34;i-dont-want@to-be-recuited.thank-you-very-much&#34;;
        git commit-tree &#34;$@&#34;;
    else
         git commit-tree &#34;$@&#34;;
    fi&#39; HEAD
    #git push -f
    cd ..
done
</code></pre><p>If you are trying to dodge recruiters maybe you should check out this project that will allow you to filter their emails in Gmail: <a href="https://github.com/StefanoChiodino/i-dont-want-to-be-recruited-thank-you-very-much">I don&rsquo;t want to be recruited, thank you very much on Github</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Acronyms</title>
      <link>https://stefano.chiodino.uk/posts/2020-07-27-tma-too-many-acronyms/</link>
      <pubDate>Wed, 23 Dec 2020 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/2020-07-27-tma-too-many-acronyms/</guid>
      <description>We need to fight the urge to abbreviate everything!</description>
      <content:encoded><![CDATA[<p>One day Chris, head of devops, gave me a tour of our setup. He proudly pointed out to me how they prefer to write arguments using the long version, like <code>--allow</code> instead of <code>-a</code>. This is to make it easier to understand the system, and thus maintaining it. It made so much sense: decrease the cognitive load, increase productivity.</p>
<p>Then I started working for the NHS, the biggest employer in the UK, and 5th in the world, just after McDonald&rsquo;s. Seems like in such a big company nobody has time to spell things out, and after more than a year I&rsquo;m still struggling to catch up on some acronyms. I often come across acronyms that I never bothered or dared to ask about, and despite having developed a sense for that they represent, I still don&rsquo;t know what they stand for.</p>
<p>When writing code, good sense dictates you should call your variable <code>pageTitle</code>, rather than <code>pt</code>. So why is it ok to abbreviate <code>GPES Data for Pandemic Planning and Research</code> in a nested acronym to GDPPR?</p>
<p>I took a business writing course recently, and one of the key points was that you have to write for your audience. Look, I get it. I review a lot of <code>merge requests</code>, and the temptation to call them <code>MR</code> is strong, but think about your audience. Are you in a group chat with your Product Owner and the New Starter?</p>
<p>Use all the acronyms you are confident your colleagues know, when you are writing to them in private. Maximise understanding everywhere else.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Pragmatic Programmer - Notes</title>
      <link>https://stefano.chiodino.uk/posts/the-pragmatic-programmer-notes/</link>
      <pubDate>Tue, 15 May 2018 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/the-pragmatic-programmer-notes/</guid>
      <description>My notes from the book &amp;#34;The Pragmatic Programmer&amp;#34; by Andrew Hunt and David Thomas</description>
      <content:encoded><![CDATA[<p>Written by Andrew Hunt and David Thomas. Originally published October 1999. 25th printing, 10th Feb version. 320 Pages. ISBN: 978-0-2016-1622-4. Publisher: Addison-Wesley.</p>
<p>The book invites the reader to progress in whatever order, as reading from front to back is not necessary.</p>
<p>Throughout the book you are prompted to visit other parts to expand on an topic. At the end of each section you are sometimes prompted with challenges that make you reflect on what you just read.</p>
<ul>
<li>Programming is a craft. At its simplest, it comes down to getting a computer to do what you want it to do (or what your user wants it to do).</li>
<li>What Makes a Pragmatic Programmer?
<ul>
<li>Early adopter/fast adapter.</li>
<li>Inquisitive.</li>
<li>Critical thinker.</li>
<li>Realistic.</li>
<li>Jack of all trades.</li>
</ul>
</li>
<li>Care About Your Craft</li>
<li>“Kaizen” is a Japanese term that captures the conceptof continuously making many small improvements</li>
</ul>
<h1 id="chapter-1---a-pragmatic-philosophy">CHAPTER 1 - A PRAGMATIC PHILOSOPHY</h1>
<ol>
<li>The Cat Ate My Source Code
<ul>
<li>TIP 3: Provide Options, Don’t Make Lame Excuses</li>
</ul>
</li>
<li>Software Entropy
<ul>
<li>While software development is immune from almost all physical laws,entropy hits us hard</li>
<li>TIP 4: Don’t Live with Broken Windows […] Don’t let entropy win.</li>
<li>Even with a fire to put out, don’t be the first to break a window!</li>
</ul>
</li>
<li>Stone Soup and Boiled Frogs
<ul>
<li>TIP 5: Be a Catalyst for Change</li>
<li>TIP 6: Remember the Big Picture</li>
<li>Challenge: Sometimes deception is needed to catalyse change, so don’t use it to do harm</li>
</ul>
</li>
<li>Good-Enough Software
<ul>
<li>If trade-offs are possible ask for them: how good is this software meant to be?</li>
<li>TIP 7: Make Quality a Requirements Issue</li>
<li>Often great software today is better than perfect software tomorrow. (MVP, agile)</li>
<li>Challenge: Think about the software that you use. Is it perfect? Would you rather wait for the &ldquo;perfect&rdquo; version?</li>
</ul>
</li>
<li>Your Knowledge Portfolio
<ul>
<li>An investment in knowledge always pays the best interest. (Benjamin Franklin)</li>
<li>Knowledge in software is an expiring asset</li>
<li>Knowledge is an asset and can be treated like an investment:
<ul>
<li>Learn regularly</li>
<li>Diversify your knowledge</li>
<li>Learn some new up-and-coming tech</li>
<li>Give up on old tech</li>
</ul>
</li>
<li>Goals:
<ul>
<li>Learn one new language every year (seems a lot). Different languages will force you to think differently. E.g.: Rust forces you not to use nulls and think of return types as Option and Result.</li>
<li>Read a technical book each quarter</li>
<li>Take classes</li>
<li>Participate in local groups</li>
<li>Experiment with different environments</li>
<li>Stay current online and offline</li>
</ul>
</li>
<li>It doesn’t matter what use you are going to make of your new knowledge, the process of learning will expand your thinking.</li>
<li>TIP 9: Critically Analyze What You Read and Hear.</li>
<li>How to ask for knowledge: be specific, frame the question carefully and politely, once your question is written down look one more time for the answer, be patient, give back.</li>
</ul>
</li>
<li>Communicate!
<ul>
<li>&ldquo;A good idea is an orphan without effective communication.&rdquo;</li>
<li>&ldquo;Plan what you want to say. Write an outline&rdquo;</li>
<li>Ask yourself about your audience the WISDOM acrostic (what, interest, sophisticated, detail, own, motivate)</li>
<li>Chose a style (short, long, factual, funny, etc)</li>
<li>Make it look good</li>
<li>if you want people to listen to you listen to them</li>
<li>TIP 10: It’s Both What You Say and the Way You Say It</li>
<li>Emails are forever</li>
</ul>
</li>
</ol>
<h1 id="chapter-2---a-pragmatic-approach">Chapter 2 - A Pragmatic Approach</h1>
<ol start="7">
<li>
<p>The Evils of Duplication</p>
<ul>
<li>TIP 11: DRY—Don’t Repeat Yourself</li>
<li>&ldquo;It isn’t a question of whether you’ll remember: it’s a question of when you’ll forget.&rdquo;</li>
<li>Duplication can be due to developers feeling there is no other way, without realising it, for laziness or because different developers produced by coincidence the same functionality.
<ul>
<li>Imposed duplication can be worked around by using a pre-processor.</li>
<li>Inadverted duplication can be due to unnormalised data.</li>
</ul>
</li>
<li>Comments are knowledge too and take part in duplication.</li>
<li>Performances may tempt developers to duplicate, however this is just a cheap solution (e.g. some calculated data can be stored due to the expense of being produced, however care needs to be taken to update it if any of the inputs changes)</li>
<li>TIP 12: Make It Easy to Reuse</li>
<li>Ease or reusing functionality is a step towards de-duplication.</li>
</ul>
</li>
<li>
<p>Orthogonality</p>
<ul>
<li>Often overlooked but core concept of other methods and techniques.</li>
<li>Refers to the decoupling of things so that moving on one line your position projected on the other doesn’t change.</li>
<li>TIP 13: Eliminate Effects Between Unrelated Things</li>
<li>Productivity gain
<ul>
<li>&ldquo;Changes are localized, so development time and testing time are reduced”</li>
<li>Promote reuse.</li>
<li>It’s easier to combine orthogonal components.</li>
</ul>
</li>
<li>Reduce Risk
<ul>
<li>Compartamentalise problems.</li>
<li>Robustness</li>
<li>Probably better tested as tests are easier to write.</li>
<li>3rd party changes have less effect on your system.</li>
</ul>
</li>
<li>Layering is a powerful way to achieve orthogonality.</li>
<li>Test for orthogonality are easy: ask yourself how many parts of the software would be affected if you had to change any other part. It should be one.</li>
<li>Unit testing and documentation is an easy winner when code is orthogonal.</li>
<li>OOP can provide with tools for more orthogonality, but also more chances for less of it.</li>
</ul>
</li>
<li>
<p>Reversibility</p>
<ul>
<li>&ldquo;Requirements, users, and hardware change faster than we can get the software developed.&rdquo;</li>
<li>TIP 14: There Are No Final Decisions</li>
<li>&ldquo;keep decisions soft and pliable&rdquo;</li>
</ul>
</li>
<li>
<p>Tracer Bullets</p>
<ul>
<li>Tracer bullets are used to correct the aim of fire arms in the dark</li>
<li>TIP 15: Use Tracer Bullets to Find the Target</li>
<li>Like prototyping but keeping the code.</li>
<li>Build skeleton of a system</li>
</ul>
</li>
<li>
<p>Prototypes and Post-it Notes</p>
<ul>
<li>Prototypes don’t need to be on code. Could be on post-its or whiteboard.</li>
<li>TIP 16: Prototype to Learn</li>
<li>You can prototype anything new, risky, experimental, etc.</li>
<li>Prefer high level language, stick with an at least similar language if testing for performances.</li>
<li>Architecture wise prototyping is valuable to check for coupling, responsibilities and collaborations of components, interface definition, possible duplications, data access.</li>
<li>Make very clear to everybody that it’s disposable code.</li>
</ul>
</li>
<li>
<p>Domain Languages</p>
<ul>
<li>TIP 17: Program Close to the Problem Domain.</li>
<li>Come up with high level languages to help define a problem.</li>
<li>Different part of a problem may require their own language.</li>
<li>Define a syntax first with a notation such as BNF.</li>
<li>Tools such as bison and yacc can convert well defined languages to programming languages.</li>
</ul>
</li>
<li>
<p>Estimating</p>
<ul>
<li>Practice estimating to be able to get a feel for order go magnitudes.</li>
<li>TIP 18: Estimate to Avoid Surprises.</li>
<li>The first question when asked for an estimation should be &ldquo;how accurate?”.</li>
<li>The smaller the granularity of the estimations the greater the assumption of degree of accuracy.</li>
</ul>
<table>
  <thead>
      <tr>
          <th>Duration</th>
          <th>Quote estimate in</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1–15 days</td>
          <td>days</td>
      </tr>
      <tr>
          <td>3–8 weeks</td>
          <td>weeks</td>
      </tr>
      <tr>
          <td>8–30 weeks</td>
          <td>months</td>
      </tr>
      <tr>
          <td>30+ weeks</td>
          <td>think hard before giving an estimate</td>
      </tr>
  </tbody>
</table>
<ul>
<li>The easiest way to improve on you estimate is to draw from other peoples experience.</li>
<li>Build a model for the estimate e.g. variants, building blocks.</li>
<li>&ldquo;Your experience will tell you when to stop refining.”</li>
<li>As the estimate becomes more complex you’ll want to hedge your answers.</li>
<li>Take notes of you estimate and the actual values. Investigate when there is a substantial difference.</li>
<li>TIP 19: Iterate the Schedule with the Code</li>
<li>&ldquo;What to Say When Asked for an Estimate? You say &lsquo;I’ll get back to you.’”</li>
</ul>
</li>
</ol>
<h1 id="chapter-3---the-basic-tools">Chapter 3 - The Basic Tools</h1>
<ul>
<li>Start with basic tools then adopt new ones. Go back to to the basics from time to time to sharpen your skills.</li>
</ul>
<ol start="14">
<li>The Power of Plain Text
<ul>
<li>TIP 20: Keep Knowledge in Plain Text</li>
<li>Cons: slower to computer, takes more space.</li>
<li>Pros: easier to remember the meaning of data, flexible, easier to test (e.g.: change data without recompiling).</li>
</ul>
</li>
<li>Shell Games
<ul>
<li>GUI are best for simple operation, shell are more powerful.</li>
<li>TIP 21: Use the Power of Command Shells.</li>
</ul>
</li>
<li>Power Editing
<ul>
<li>TIP 22: Use a Single Editor Well.</li>
<li>Make sure that your editor of choice is available on multiple platforms/OS/shells.</li>
</ul>
</li>
<li>Source Code Control
<ul>
<li>Source Code Control Systems allows for decentralisation, collaboration, backup, statistics, undoing changes, compartmentalisation,</li>
<li>TIP 23: Always Use Source Code Control</li>
<li>Use SCCS for everything, not just code. [This may be a bit anachronistic now that a similar effect can be achieved with Google Docs and the like]</li>
<li>SCCS allows for automated and repeatable builds.</li>
</ul>
</li>
<li>Debugging
<ul>
<li>&ldquo;Embrace the fact that debugging is just problem solving, and attack itas such.”</li>
<li>TIP 24: Fix the Problem, Not the Blame.</li>
<li>TIP 25: Don’t Panic.</li>
<li>Resist the urge to fix just the symptoms you see. […] Always try to discover the root cause of a problem, not just this particular appearance of it.</li>
<li>Bug reporting isn’t an exact science.</li>
<li>Accuracy in bug reports is further diminished when they come through a third party</li>
<li>Isolate the steps to reproduce the bug</li>
<li>In the process of elimination assume you are at fault before a third party. If a third party is at fault you’ll still probably need to isolate the problem as much as possible for a bug report.</li>
<li>TIP 26: “select” Isn’t Broken</li>
<li>TIP 27: Don’t Assume It—Prove It</li>
<li>If it took a long time to fix try to find ways to make it easier for the next time.</li>
<li>If the bug came from one person’s misunderstanding see if anyone else had that misunderstanding.</li>
</ul>
</li>
<li>Text Manipulation
<ul>
<li>TIP 28: Learn a Text Manipulation Language</li>
</ul>
</li>
<li>Code Generators
<ul>
<li>TIP 29: Write Code That Writes Code</li>
<li>Passive code generators produce source code that becomes part of the project. They don’t always have to be totally accurate. [e.g.: templating]</li>
<li>Active code generators helps to comply with the DRY principle and are meant to be used continuously to feed changes from the input files to the output ones [e.g.: asp.net transforms]</li>
</ul>
</li>
</ol>
<h1 id="chapter-4---pragmatic-paranoia">Chapter 4 - Pragmatic Paranoia</h1>
<ul>
<li>TIP 30: You Can’t Write Perfect Software</li>
<li>Be defensive of other peoples code, and of your own.</li>
</ul>
<ol start="21">
<li>Design by Contract
<ul>
<li>&ldquo;Dealing with computer systems is hard. Dealing with people is even harder.”</li>
<li>&ldquo;Bertrand Meyer developed the concept of Design by Contractfor the language Eiffel.”</li>
<li>In DBC there are 3 expectations that needs to be met: preconditions, postconditions and class invariants.</li>
<li>TIP 31: Design with Contracts</li>
<li>“Be strict in what you will accept beforeyou begin, and promise as little as possible in return”</li>
</ul>
</li>
<li>Dead Programs Tell No Lies
<ul>
<li>TIP 32: Crash Early</li>
<li>&ldquo;many times, crashing your program is the bestthing you can do”</li>
</ul>
</li>
<li>Assertive Programming
<ul>
<li>TIP 33: If It Can’t Happen, Use Assertions to Ensure That It Won’t</li>
<li>Most “assert” should be left in the code even in production.</li>
<li>Asserts should have no side effects.</li>
</ul>
</li>
<li>When to Use Exceptions
<ul>
<li>&ldquo;One of the problems with exceptions is knowing when to use them. Webelieve that exceptions should rarely be used as part of a program’snormal flow; exceptions should be reserved for unexpected events”</li>
<li>TIP 34: Use Exceptions for Exceptional Problems.</li>
</ul>
</li>
<li>How to Balance Resources
<ul>
<li>TIP 35: Finish What You Start</li>
<li>Don’t couple code with shared resources</li>
<li>&ldquo;Deallocate resources in the opposite order to that in which you allocate them.”</li>
<li>If a series of resources are allocated in more than one place try to allocate them in the same order to avoid deadlocks.</li>
<li>Is always a good idea to invest in writing code to check the resource balance, like wrappers that tracks resources.</li>
</ul>
</li>
</ol>
<h1 id="chapter-5---bend-or-break">Chapter 5 - Bend, or Break</h1>
<ol start="26">
<li>Decoupling and the Law of Demeter
<ul>
<li>Write ‘shy’ code: don’t reveal yourself to others and don’t interact with too many people.</li>
<li>Organise code in cells and limit their interaction like organisations that value privacy</li>
<li>TIP 36: Minimize Coupling Between Modules</li>
<li>&ldquo;The Law of Demeter for functions states that any method of anobject should call only methods belonging to: itself, any parameters that were passed in to the method, any objects it created and any directly held component objects”</li>
</ul>
</li>
<li>Metaprogramming
<ul>
<li>Get the details out of the code to make it soft and configurable.</li>
<li>Metadata is data about data.</li>
<li>TIP 37: Configure, Don’t Integrate</li>
<li>TIP 38: Put Abstractions in Code, Details in Metadata</li>
<li>Writing configuration out of the code allows for decoupling, abstraction, configuring application more easily and changing the configuration without compilation step</li>
<li>Decide if it’s worth implementing a mechanism to reload the configuration on the fly. Consider how long-running the application will be and how quick and easy restarting it would be.</li>
</ul>
</li>
<li>Temporal Coupling
<ul>
<li>Time is often ignored in software architecture. Time aspects to consider are concurrency and ordering.</li>
<li>Workflow needs to be modelled with UML activity diagram or similar.</li>
<li>TIP 39: Analyze Workflow to Improve Concurrency.</li>
<li>The hungry consumer model consists of workers getting tasks from a queue.</li>
<li>TIP 40: Design Using Services.</li>
<li>TIP 41: Always Design for Concurrency.</li>
<li>Adding concurrency to a system that has not been designed as such is very difficult.</li>
</ul>
</li>
<li>It’s Just a View
<ul>
<li>Use events to decouple.</li>
<li>Dispatching events from a single routine cause more coupling. Use the publish/subscribe pattern.</li>
<li>TIP 42: Separate Views from Models.</li>
<li>Use Model-View-Controller (MVC) to separate the model from both the GUI and the controls.</li>
<li>MVC typically exists in a GUI context, but the same concept on segregation of concerns can be applied to any kind of programming: Model is the data, the view is a way of interpreting the data, and the controller feeds the data to the view</li>
</ul>
</li>
<li>Blackboards
<ul>
<li>A blackboard system is a data storage that allows actors to asynchronously work on shared data.</li>
<li>Blackboard systems became popular in artificial intelligence, where problems are large and complex.</li>
<li>TIP 43: Use Blackboards to Coordinate Workflow.</li>
</ul>
</li>
</ol>
<h1 id="chapter-6---while-you-are-coding">Chapter 6 - While You Are Coding</h1>
<ol start="31">
<li>Programming by Coincidence
<ul>
<li>&ldquo;We should avoid pro-gramming by coincidence—relying on luck and accidental successes—in favor of programming deliberately.”</li>
<li>There are several reasons why not to program by coincidence:
<ol>
<li>May not be really working but only looking like it is.</li>
<li>May be an accidental boundary condition and not work all the times.</li>
<li>Undocumented behaviour subject to change.</li>
<li>Possibly slower.</li>
<li>More error prone.</li>
</ol>
</li>
<li>&ldquo;Assumptions that aren’t based on well-established facts are the bane of all projects.”</li>
<li>TIP 44: Don’t Program by Coincidence</li>
<li>To program deliberately you should:
<ul>
<li>Be aware of what you are doing.</li>
<li>Be aware of what you are going to do.</li>
<li>Proceed from a plan.</li>
<li>Don’t rely on accidents or assumptions. Assume the worse.</li>
<li>Document your assumptions (e.g.: design by contract).</li>
<li>Test your assumptions.</li>
<li>Focus on the important parts.</li>
<li>Don’t let existing code/functionality dictate what you are doing. Refactor if necessary.</li>
</ul>
</li>
</ul>
</li>
<li>Algorithm Speed
<ul>
<li>It’s important to estimate speed of algorithms when not linear.</li>
<li>The O notation determines the upper bounds of algorithms. Because of this it does incur in some precision loss.</li>
<li>The big O notation is also uses to model memory or other resources.</li>
<li>You should keep in mind the big O notation and ask yourself what scale are you working on to understand what the impact will be.</li>
<li>TIP 45: Estimate the Order of Your Algorithms.</li>
<li>If you are unsure on the efficiency of your code then run it a few time with different inputs and plot the results.</li>
<li>TIP 46: Test Your Estimates.</li>
<li>Sometimes is not all about the efficiency: if the inputs are known small it could be better to have easier to write and debug code.</li>
<li>Be wary of premature optimisations.</li>
</ul>
</li>
<li>Refactoring
<ul>
<li>Building software is organic, much more like gardening than building constructions, but business people are much more comfortable with the latter metaphor.</li>
<li>&ldquo;Rewriting, reworking, and re-architecting code is collectively known as refactoring.”</li>
<li>Don’t hesitate to refactor.</li>
<li>Good reasons for refactoring: duplication, non-orthodoganl design, outdated knowledge, performance.</li>
<li>Time pressure is often used as an excuse for not refactoring.</li>
<li>TIP 47: Refactor Early, Refactor Often.</li>
<li>Martin Fowler tips on refactoring: don’t add functionality while refactoring; Make sure you are covered by tests and run them often; Take short, deliberate steps.</li>
</ul>
</li>
<li>Code That’s Easy to Test
<ul>
<li>&ldquo;The term “Software IC” (Integrated Circuit) seems to have been invented in 1986 by Cox and Novobilski in their Objective-C book Object-Oriented Programming” and it refers to the practice of writing modular software that can be tested just like individual chips that are then composed together on a board.</li>
<li>We can test against the contract.</li>
<li>TIP 48: Design to Test</li>
<li>Unit tests provide examples on how to use your code.</li>
<li>Run the tests often.</li>
<li>Use test harnesses (JUnit, xUnit, etc).</li>
<li>Debugging may be necessary in production environment, in this case log files, hot keys sequences or web servers to reveal status messages may be the best option.</li>
<li>Format log files correctly to help with parson and for readability.</li>
<li>&ldquo;Testing is more cultural than technical&rdquo;</li>
<li>TIP 49: Test Your Software, or Your Users Will</li>
</ul>
</li>
<li>Evil Wizards
<ul>
<li>TIP 50: Don’t Use Wizard Code You Don’t Understand</li>
<li>Developers routinely use things that don’t understand, but wizard’s code (boilerplate) is not abstracted away like a library or a processor mechanism, it’s interwoven with the developer code.</li>
</ul>
</li>
</ol>
<h1 id="chapter-7---before-the-project">Chapter 7 - Before the Project</h1>
<ul>
<li>There is a fine line between specifying too much (analysis paralysis) and not enough (not being ready).</li>
</ul>
<ol start="36">
<li>The Requirements Pit
<ul>
<li>&ldquo;Requirements rarely lie on the surface.Normally, they’re buried deep beneath layers of assumptions, miscon-ceptions, and politics.&rdquo;</li>
<li>TIP 51: Don’t Gather Requirements—Dig for Them</li>
<li>“A requirement is a statement of somethingthat needs to be accomplished”</li>
<li>Document policies should be separated from requirements. E.g. only employee’s supervisors may see employee’s records should be defined as the need for access control in the requirements and specify who can access what(the policies/metadata/configuration) in another document.</li>
<li>&ldquo;It’s important to discover the underlying reason why users do a par-ticular thing, rather than just the way they currently do it. At the endof the day, your development has to solve their business problem, notjust meet their stated requirements. Documenting the reasons behind requirements will give your team invaluable information when makingdaily implementation decisions.”</li>
<li>A simple technique to get the requirements right is to do the work of your future users.</li>
<li>TIP 52: Work with a User to Think Like a User</li>
<li>Don’t over-specify. Requirements are needs.</li>
<li>TIP 53: Abstractions Live Longer than Details</li>
<li>TIP 54: Use a Project Glossary</li>
<li>Make the glossary easily available (e.g., web resource).</li>
</ul>
</li>
<li>Solving Impossible Puzzles
<ul>
<li>TIP 55: Don’t Think Outside the Box—Find the Box</li>
<li>Whenever faced with a puzzle that seems impossible ask yourself:
<ul>
<li>&ldquo;Is there an easier way?</li>
<li>&ldquo;Are you trying to solve the right problem, or have you been distracted by a peripheral technicality?&rdquo;</li>
<li>&ldquo;Why is this thing a problem?&rdquo;</li>
<li>&ldquo;What is it that’s making it so hard to solve?Does it have to be done this way?</li>
<li>&ldquo;Does it have to be done at all?&rdquo;</li>
</ul>
</li>
</ul>
</li>
<li>Not Until You’re Ready
<ul>
<li>TIP 56: Listen to Nagging Doubts—Start When You’re Ready</li>
<li>Listen to your instincts</li>
<li>If insure if waiting for the right moment or procrastinating then start a prototype, then you’ll know to start if you fee like you are wasting your time. If prototyping is creating new questions and you encounter snags on the way then you know you weren’t ready.</li>
</ul>
</li>
<li>The Specification Trap
<ul>
<li>&ldquo;Program specification is the process of taking a requirement and reducing it down to the point where a programmer’s skill can take over.&rdquo;</li>
<li>The specification is a record for future developers and an agreements with the user, an implicit contact.</li>
<li>Many designers find it difficult to stop specifying. Is naive to assume that the perfect specification can be achieved, and even if the client signs it off you can’t guarantee that it’s is what they actually need and they won’t want to change it.</li>
<li>TIP 57: Some Things Are Better Done than Described</li>
<li>Having a lose specification allows developers to work their way around certain problems.</li>
<li>&ldquo;spec- ification and implementation are simply different aspects of the same process—an attempt to capture and codify a requirement.&rdquo;</li>
<li>Over-specifying incurs in diminishing or even negative returns.</li>
</ul>
</li>
<li>Circles and Arrows
<ul>
<li>TIP 58: Don’t Be a Slave to Formal Methods</li>
<li>&ldquo;Never underestimate the cost of adopting new tools and methods.&rdquo;</li>
<li>TIP 59: Expensive Tools Do Not Produce Better Designs</li>
</ul>
</li>
</ol>
<h1 id="chapter-8---pragmatic-projects">Chapter 8 - Pragmatic Projects</h1>
<ol start="41">
<li>Pragmatic Teams
<ul>
<li>&ldquo;Teams as a whole should not tolerate broken windows” (see 1.2).</li>
<li>Code quality shouldn’t be delegated to one or some members of the team, it should be everybody’s responsibility.</li>
<li>The boiling frog problem is even more common in teams. The dilution of responsibilities makes it easier for the scope to increase and the time scales to decrease. Maybe appoint a person to be in charge of this.</li>
<li>Communication is important for individuals as much as for teams, which should comunicate as one. It help to generate a branding for teams, to give them identity.</li>
<li>A team member could be appointed as librarian to help with the duplication of documentation.</li>
<li>It’s a mistake to organise teams based on jobs</li>
<li>TIP 60: Organize Around Functionality, Not Job Functions</li>
<li>&ldquo;The project needs at least two “heads”—one technical, the other administrative.&rdquo;</li>
<li>&ldquo;A great way to ensure both consistency and accuracy is to automate everything the team does.&rdquo;</li>
</ul>
</li>
<li>Ubiquitous Automation
<ul>
<li>&ldquo;Manual procedures leave consistency up to chance; repeatabilityisn’t guaranteed, especially if aspects of the procedure are open to interpretation by different people.&rdquo;</li>
<li>TIP 61: Don’t Use Manual Procedures</li>
<li>Compiling the project should be reliable and repeatable.</li>
<li>Automation doesn’t only apply to code, but also administrative tasks and documentation.</li>
</ul>
</li>
<li>Ruthless Testing
<ul>
<li>&ldquo;Most developers hate testing.&rdquo;</li>
<li>TIP 62: Test Early. Test Often. Test Automatically.</li>
<li>TIP 63 Coding Ain’t Done ’Til All the Tests Run</li>
<li>Unit testing ensures the functionality of a self-contained unit of code.</li>
<li>Integration testings verifies the units of code works well together.</li>
<li>Validation and verification tests make sure you are building what the client wants</li>
<li>Resource exhaustion, errors and recovery needs to be tested too. There are several resources that you can test the lack of: screen resolution, network bandwidth, disk bandwidth, system clock precision, etc.</li>
<li>Performance testing include stress testing and load testing. Specialised hardware or software may be necessary.</li>
<li>Usability testing are run by real users in real environments.</li>
<li>Code quality can be partially tested by measuring cyclomatic complexity, inheritance fan-in and fan-out, response set (number of functions directly invokedby methods of the class) and class coupling ratios. Some of these can only be used by comparison to other pieces of code and so standard deviation is often used.</li>
<li>Regression testing compares the outcome of the current test to previous ones or known values. E.g.: making sure bugs don’t resurface.</li>
<li>Test data may be real-world one and be collected by competitors systems, or synthetic one that is generated to obtain a big quantity of it or test boundary conditions.</li>
<li>GUI tests can be complicated to maintain if the interface is being worked on. In this situation having decoupled code help in reducing the scope of the GUI tests.</li>
<li>TIP 64: Use Saboteurs to Test Your Testing</li>
<li>Code coverage can help understand if enough have been tested. However, testing 100% of the code lines doesn’t mean perfect testing.</li>
<li>TIP 65: Test State Coverage, Not Code Coverage</li>
<li>Code should be tested as soon as any production code exists.</li>
<li>Test should be run before checking the code in the source repository.</li>
<li>When bugs are found a test should be written to avoid it resurfacing.</li>
<li>TIP 66: Find Bugs Once</li>
</ul>
</li>
<li>It’s All Writing
<ul>
<li>&ldquo;Pragmatic Programmers embrace documentation as an integral part ofthe overall development process.&rdquo;</li>
<li>TIP 67: Treat English as Just Another Programming Language.</li>
<li>TIP 68: Build Documentation In, Don’t Bolt It On.</li>
<li>&ldquo;Code should have comments,but too many comments can be just as bad as too few.&rdquo;</li>
<li>&ldquo;Even worse than meaningless names are misleading names.&rdquo;</li>
<li>Don’t add to the comments information that can be determined by tools. Like usages, and revision history.</li>
</ul>
</li>
<li>Great Expectations
<ul>
<li>A project is successful if it meets the expectations of the clients.</li>
<li>TIP 69: Gently Exceed Your Users’ Expectations</li>
<li>Surprise the users, in a good way.</li>
</ul>
</li>
<li>Pride and Prejudice
<ul>
<li>TIP 70: Sign Your Work</li>
<li>Take pride in your work but don’t become prejudiced of it in favour of your coworkers.</li>
</ul>
</li>
</ol>
<h1 id="quick-reference-guide">Quick reference guide</h1>
<ol>
<li>Care About Your Craft
<ul>
<li>Why spend your life developing software unless you care about doing it well?</li>
</ul>
</li>
<li>Think! About Your Work
<ul>
<li>Turn off the autopilot and take control. Constantly critique and appraise your work.</li>
</ul>
</li>
<li>Provide Options, Don’t Make Lame Excuses
<ul>
<li>Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done.</li>
</ul>
</li>
<li>Don’t Live with Broken Windows
<ul>
<li>Fix bad designs, wrong decisions, and poor code when you see them.</li>
</ul>
</li>
<li>Be a Catalyst for Change
<ul>
<li>You can’t force change on people. Instead, show them how the future might be and help them participate in creating it.</li>
</ul>
</li>
<li>Remember the Big Picture
<ul>
<li>Don’t get so engrossed in the details that you forget to check what’s happening around you.</li>
</ul>
</li>
<li>Make Quality a Requirements Issue
<ul>
<li>Involve your users in determining the project’s real quality requirements.</li>
</ul>
</li>
<li>Invest Regularly in Your Knowledge Portfolio
<ul>
<li>Make learning a habit.</li>
</ul>
</li>
<li>Critically Analyze What You Read and Hear
<ul>
<li>Don’t be swayed by vendors, media hype, or dogma. Analyze information in terms of you and your project.</li>
</ul>
</li>
<li>It’s Both What You Say and theWay You Say It
<ul>
<li>There’s no point in having great ideas if you don’t communicate them effectively.</li>
</ul>
</li>
<li>DRY—Don’t Repeat Yourself
<ul>
<li>Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.</li>
</ul>
</li>
<li>Make It Easy to Reuse
<ul>
<li>If it’s easy to reuse, people will. Create an environment that supports reuse.</li>
</ul>
</li>
<li>Eliminate Effects Between Unrelated Things
<ul>
<li>Design components that are self-contained, independent, and have a single, well-defined purpose.</li>
</ul>
</li>
<li>There Are No Final Decisions
<ul>
<li>No decision is cast in stone. Instead, consider each as being written in the sand at the beach, and plan for change.</li>
</ul>
</li>
<li>Use Tracer Bullets to Find the Target
<ul>
<li>Tracer bullets let you home in on your target by trying things and seeing how close they land.</li>
</ul>
</li>
<li>Prototype to Learn
<ul>
<li>Prototyping is a learning experience. Its value lies not in the code you produce, but in the lessons you learn.</li>
</ul>
</li>
<li>Program Close to the Problem Domain
<ul>
<li>Design and code in your user’s language.</li>
</ul>
</li>
<li>Estimate to Avoid Surprises
<ul>
<li>Estimate before you start. You’ll spot potential problems up front. 19. Iterate the Schedule with the Code Use experience you gain as you implement to refine the project time scales.</li>
</ul>
</li>
<li>Keep Knowledge in Plain Text
<ul>
<li>Plain text won’t become obsolete. It helps leverage your work and simplifies debugging and testing</li>
</ul>
</li>
<li>Use the Power of Command Shells
<ul>
<li>Use the shell when graphical user interfaces don’t cut it.</li>
</ul>
</li>
<li>Use a Single Editor Well
<ul>
<li>The editor should be an extension of your hand; make sure your editor is configurable, extensible, and programmable.</li>
</ul>
</li>
<li>Always Use Source Code Control
<ul>
<li>Source code control is a time machine for your work—you can go back.</li>
</ul>
</li>
<li>Fix the Problem, Not the Blame
<ul>
<li>It doesn’t really matter whether the bug is your fault or someone else’s—it is still your problem, and it still needs to be fixed.</li>
</ul>
</li>
<li>Don’t Panic When Debugging
<ul>
<li>Take a deep breath and THINK! about what could be causing the bug.</li>
</ul>
</li>
<li>“select” Isn’t Broken
<ul>
<li>It is rare to find a bug in the OS or the compiler, or even a third-party product or library. The bug is most likely in the application.</li>
</ul>
</li>
<li>Don’t Assume It—Prove It
<ul>
<li>Prove your assumptions in the actual environment— with real data and boundary conditions.</li>
</ul>
</li>
<li>Learn a Text Manipulation Language
<ul>
<li>You spend a large part of each day working with text. Why not have the computer do some of it for you?</li>
</ul>
</li>
<li>Write Code That Writes Code
<ul>
<li>Code generators increase your productivity and help avoid duplication.</li>
</ul>
</li>
<li>You Can’t Write Perfect Software
<ul>
<li>Software can’t be perfect. Protect your code and users from the inevitable errors.</li>
</ul>
</li>
<li>Design with Contracts
<ul>
<li>Use contracts to document and verify that code does no more and no less than it claims to do.</li>
</ul>
</li>
<li>Crash Early
<ul>
<li>A dead program normally does a lot less damage than a crippled one.</li>
</ul>
</li>
<li>Use Assertions to Prevent the Impossible
<ul>
<li>Assertions validate your assumptions. Use them to protect your code from an uncertain world.</li>
</ul>
</li>
<li>Use Exceptions for Exceptional Problems
<ul>
<li>Exceptions can suffer from all the readability and maintainability problems of classic spaghetti code. Reserve exceptions for exceptional things.</li>
</ul>
</li>
<li>Finish What You Start
<ul>
<li>Where possible, the routine or object that allocates a resource should be responsible for deallocating it.</li>
</ul>
</li>
<li>Minimize Coupling Between Modules
<ul>
<li>Avoid coupling by writing “shy” code and applying the Law of Demeter.</li>
</ul>
</li>
<li>Configure, Don’t Integrate
<ul>
<li>Implement technology choices for an application as configuration options, not through integration or engineering.</li>
</ul>
</li>
<li>Put Abstractions in Code, Details in Metadata
<ul>
<li>Program for the general case, and put the specifics outside the compiled code base.</li>
</ul>
</li>
<li>Analyze Workflow to Improve Concurrency
<ul>
<li>Exploit concurrency in your user’s workflow.</li>
</ul>
</li>
<li>Design Using Services
<ul>
<li>Design in terms of services—independent, concurrent objects behind well-defined, consistent interfaces.</li>
</ul>
</li>
<li>Always Design for Concurrency
<ul>
<li>Allow for concurrency, and you’ll design cleaner interfaces with fewer assumptions.</li>
</ul>
</li>
<li>Separate Views from Models
<ul>
<li>Gain flexibility at low cost by designing your application in terms of models and views.</li>
</ul>
</li>
<li>Use Blackboards to Coordinate Workflow
<ul>
<li>Use blackboards to coordinate disparate facts and agents, while maintaining independence and isolation among participants.</li>
</ul>
</li>
<li>Don’t Program by Coincidence
<ul>
<li>Rely only on reliable things. Beware of accidental complexity, and don’t confuse a happy coincidence with a purposeful plan.</li>
</ul>
</li>
<li>Estimate the Order of Your Algorithms
<ul>
<li>Get a feel for how long things are likely to take before you write code.</li>
</ul>
</li>
<li>Test Your Estimates
<ul>
<li>Mathematical analysis of algorithms doesn’t tell you everything. Try timing your code in its target environment.</li>
</ul>
</li>
<li>Refactor Early, Refactor Often
<ul>
<li>Just as you might weed and rearrange a garden rewrite, rework, and re-architect code when it needs it. Fix the root of the problem.</li>
</ul>
</li>
<li>Design to Test
<ul>
<li>Start thinking about testing before you write a line of code.</li>
</ul>
</li>
<li>Test Your Software, or Your Users Will
<ul>
<li>Test ruthlessly. Don’t make your users find bugs for you.</li>
</ul>
</li>
<li>Don’t UseWizard Code You Don’t Understand
<ul>
<li>Wizards can generate reams of code. Make sure you understand all of it before you incorporate it into your project.</li>
</ul>
</li>
<li>Don’t Gather Requirements—Dig for Them
<ul>
<li>Requirements rarely lie on the surface. They’re buried deep beneath layers of assumptions, misconceptions, and politics.</li>
</ul>
</li>
<li>Work with a User to Think Like a User
<ul>
<li>It’s the best way to gain insight into how the system will really be used.</li>
</ul>
</li>
<li>Abstractions Live Longer than Details
<ul>
<li>Invest in the abstraction, not the implementation. Abstractions can survive the barrage of changes from different implementations and new technologies.</li>
</ul>
</li>
<li>Use a Project Glossary
<ul>
<li>Create and maintain a single source of all the specific terms and vocabulary for a project.</li>
</ul>
</li>
<li>Don’t Think Outside the Box—Find the Box
<ul>
<li>When faced with an impossible problem, identify the real constraints. Ask yourself: “Does it have to be done this way? Does it have to be done at all?”</li>
</ul>
</li>
<li>Start When You’re Ready
<ul>
<li>You’ve been building experience all your life. Don’t ignore niggling doubts.</li>
</ul>
</li>
<li>Some Things Are Better Done than Described
<ul>
<li>Don’t fall into the specification spiral—at some point you need to start coding.</li>
</ul>
</li>
<li>Don’t Be a Slave to Formal Methods
<ul>
<li>Don’t blindly adopt any technique without putting it into the context of your development practices and capabilities.</li>
</ul>
</li>
<li>Costly Tools Don’t Produce Better Designs
<ul>
<li>Beware of vendor hype, industry dogma, and the aura of the price tag. Judge tools on their merits.</li>
</ul>
</li>
<li>Organize Teams Around Functionality
<ul>
<li>Don’t separate designers from coders, testers from data modelers. Build teams the way you build code.</li>
</ul>
</li>
<li>Don’t Use Manual Procedures
<ul>
<li>A shell script or batch file will execute the same instructions, in the same order, time after time.</li>
</ul>
</li>
<li>Test Early. Test Often. Test Automatically
<ul>
<li>Tests that run with every build are much more effective than test plans that sit on a shelf.</li>
</ul>
</li>
<li>Coding Ain’t Done ’Til All the Tests Run
<ul>
<li>’Nuff said.</li>
</ul>
</li>
<li>Use Saboteurs to Test Your Testing
<ul>
<li>Introduce bugs on purpose in a separate copy of the source to verify that testing will catch them.</li>
</ul>
</li>
<li>Test State Coverage, Not Code Coverage
<ul>
<li>Identify and test significant program states. Just testing lines of code isn’t enough.</li>
</ul>
</li>
<li>Find Bugs Once
<ul>
<li>Once a human tester finds a bug, it should be the last time a human tester finds that bug. Automatic tests should check for it from then on.</li>
</ul>
</li>
<li>English is Just a Programming Language
<ul>
<li>Write documents as you would write code: honor the DRY principle, use metadata, MVC, automatic generation, and so on.</li>
</ul>
</li>
<li>Build Documentation In, Don’t Bolt It On
<ul>
<li>Documentation created separately from code is less likely to be correct and up to date.</li>
</ul>
</li>
<li>Gently Exceed Your Users’ Expectations
<ul>
<li>Come to understand your users’ expectations, then deliver just that little bit more.</li>
</ul>
</li>
<li>Sign Your Work
<ul>
<li>Craftsmen of an earlier age were proud to sign their work. You should be, too.</li>
</ul>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Welcome to the Internet: You Don&#39;t Know Shit, Part 1</title>
      <link>https://stefano.chiodino.uk/posts/welcome-to-the-internet-you-don-t-know-shit-part-1/</link>
      <pubDate>Fri, 25 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/welcome-to-the-internet-you-don-t-know-shit-part-1/</guid>
      <description>What happens if the CSS background-image URL is empty?</description>
      <content:encoded><![CDATA[<p>I was investigating if my controller was handling correctly post requests, when I noticed that it was being called twice.</p>
<p>A quick look at the dev tools network panel showed there were indeed 2 requests, but the response size was different, and the second response preview was empty. According to Chrome the initiator of the request was some javascript at the bottom of the body.</p>
<p>Baffled, I called the front end developer over, but we quickly proved that it wasn&rsquo;t due to any javascript. The request was fired with javascript disabled, but now the initiator was <code>index.html:infinity</code>, infinity being the line of code where that happened. On my simpler example it actually shows the very last line of the html.</p>
<h2 id="when-everything-else-fails-old-style-debugging">When everything else fails: old style debugging</h2>
<p>So&hellip;.we started taking elements off the page, until it stopped.:</p>
<p>Turns out that <code>style=&quot;background-image: url('');&quot;</code> it&rsquo;s interpreted as &ldquo;the URL of the background image is an empty string, relative to the current URL&rdquo;.</p>
<p>You can double check this by opening your tools and going to <a href="/example/empty-background-image-url.html">this example</a>.</p>
<p>Initiator with javascript
<img alt="Initiator with javascript" loading="lazy" src="/images/initiator-with-js.png"></p>
<p>Initiator without javascript
<img alt="Initiator without javascript" loading="lazy" src="/images/initiator-without-js.png"></p>
<p>What happened is that I don&rsquo;t enforce uploading images in the CMS, but if none is selected the URL is just null or empty. Writing <code>style=&quot;background-image: url('@(Model.Image?.Url)');&quot;</code> is incorrect, the rule should not be in the style attribute if the URL is blank.</p>
<p>The solution is to write a variable for the content of the style attribute, something like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c#" data-lang="c#"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">imageUrl</span> <span class="p">=</span> <span class="n">Model</span><span class="p">.</span><span class="n">Image</span><span class="p">?.</span><span class="n">Url</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">style</span> <span class="p">=</span> <span class="n">imageUrl</span> <span class="p">==</span> <span class="kc">null</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span>
</span></span><span class="line"><span class="cl">    <span class="p">?</span> <span class="s">$&#34;background-image: url(&#39;{imageUrl}&#39;);&#34;</span>
</span></span></code></pre></div><h2 id="reference">Reference</h2>
<p><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=473528">https://bugzilla.mozilla.org/show_bug.cgi?id=473528</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Forestry.io</title>
      <link>https://stefano.chiodino.uk/posts/forestry-io/</link>
      <pubDate>Sun, 09 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/forestry-io/</guid>
      <description>A review of Forestry.io for Hugo websites</description>
      <content:encoded><![CDATA[<p>A reader of <a href="/posts/hugo-host-and-deployment/">my post on how I use Hugo</a> pointed out in the comments that it&rsquo;s now possible to write online Hugo posts from <a href="https://forestry.io">Forestry.io</a>. I&rsquo;ve been playing with it and I&rsquo;m currently using it to write this very post.</p>
<p>As far as writing online goes it&rsquo;s a big improvement over scribe.io. I&rsquo;m just not sure that&rsquo;s enough to make me switch to online writing.</p>
<p>I love the preview. Unfortunately, it&rsquo;s not good enough as it doesn&rsquo;t work with all Hugo&rsquo;s shortcodes and custom ones either. What I would suggest instead is to have a test website. Forestry.io uses the development branch - you simply hook a new website under a test domain! Just make sure it&rsquo;s not going to be indexed by search engines.</p>
<p>Forestry.io is not responsive or mobile friendly either, so keep that in mind if you wish to blog from your mobile.</p>
<p>Something I wish was also implemented is to be able to move files between folders. I organise them by year/month/day and it usually takes me more than a day to write a new blog post.</p>
<p>The lach of spel cheking when writin the post is very anoying. Not sure why but both Chrome standard spell checking and Chrome plugin Grammarly don&rsquo;t work when writing the body of the post!</p>
<p>In general, it feels like yet another application designed for Jekyll, that works for Hugo as well.</p>
<p>By the time I finished writing this post I also noticed that it came out of beta! I&rsquo;m very happy to notice that it still has a free version, with community support and for less than 10 users. I was a bit concerned I was being used as a guinea pig and wasting my time here :)</p>
]]></content:encoded>
    </item>
    <item>
      <title>Delete all google stored passwords</title>
      <link>https://stefano.chiodino.uk/posts/delete-all-google-stored-passwords/</link>
      <pubDate>Wed, 27 Jul 2016 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/delete-all-google-stored-passwords/</guid>
      <description>How to delete all the passwords stored in Google passwords https://passwords.google.com</description>
      <content:encoded><![CDATA[<p>I was trying to delete all the passwords stored in google at <a href="https://passwords.google.com">Google passwords</a>, way too many to do manually!</p>
<p>Couldn&rsquo;t find a solution online so here is my easy one:</p>
<ul>
<li>Go to <a href="https://passwords.google.com">Google passwords</a>, sign in to your account.</li>
<li>Open the development tools in your browser, usually with F12. I’ve used Chrome.</li>
<li>Paste the following code in the console.</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// Gets all the elements to be clicked to delete the passwords.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByClassName</span><span class="p">(</span><span class="err">“</span><span class="nx">dga</span><span class="err">”</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Click all the elements.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span><span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">a</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span><span class="nx">a</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">click</span><span class="p">();}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Hugo: write, deploy, host</title>
      <link>https://stefano.chiodino.uk/posts/hugo-host-and-deployment/</link>
      <pubDate>Sat, 21 May 2016 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/hugo-host-and-deployment/</guid>
      <description>How to write content, deploy automatically and host your website</description>
      <content:encoded><![CDATA[<p>In this post I&rsquo;ll show you how I write my posts, deploy them to the server, process them with <a href="https://gohugo.io">Hugo</a> and host them on my <a href="https://m.do.co/c/875cd23a5c97">DigitalOcean</a> server.</p>
<p>I wanted this process to be as easy and quick as possible, with as few extra softwares and services as possible. There are a lot of solutions out there like Wercker but I didn&rsquo;t want more things in my way.</p>
<h1 id="writing">Writing</h1>
<h2 id="local">Local</h2>
<p>I write the posts from IntelliJ IDEA, which is my IDE of choice. Screw Sublime, Atom and all the rest! It&rsquo;s quite heavier but is worth it. You get spell checking, quite good live previews with the Multimarkdown plugin (shame the embedded HTML doesn&rsquo;t render), git integration, and in general a powerful IDE.</p>
<p>Just to be clear I like Sublime and Atom, but every time I use them there is something wrong. Right now the terminal in Atom doesn&rsquo;t work for me. There is an open issue for this but in the meantime you get a blinking unmovable cursor staring at you.</p>
<p>I feel that, since Hugo is quite new, the tools haven&rsquo;t caught up with its popularity yet. Intellij is flexible enough to allow you to have shortcuts <a href="https://www.jetbrains.com/help/idea/2016.1/live-templates.html">live templates</a> for your shortcodes. E.g.:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl">  <span class="nt">&lt;template</span> <span class="na">name=</span><span class="s">&#34;.shortcode&#34;</span> <span class="na">value=</span><span class="s">&#34;{{&amp;lt; $SHORTCODE$ &amp;gt;}}&#34;</span> <span class="na">description=</span><span class="s">&#34;A Hugo shortcode&#34;</span> <span class="na">toReformat=</span><span class="s">&#34;false&#34;</span> <span class="na">toShortenFQNames=</span><span class="s">&#34;true&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;variable</span> <span class="na">name=</span><span class="s">&#34;SHORTCODE&#34;</span> <span class="na">expression=</span><span class="s">&#34;&#34;</span> <span class="na">defaultValue=</span><span class="s">&#34;&#34;</span> <span class="na">alwaysStopAt=</span><span class="s">&#34;true&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;context&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;option</span> <span class="na">name=</span><span class="s">&#34;OTHER&#34;</span> <span class="na">value=</span><span class="s">&#34;true&#34;</span> <span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/context&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/template&gt;</span>
</span></span></code></pre></div><p>This allows me to type <code>.s</code>, press enter (if the live template <code>.shortcode</code> is selected), type the name of the shortcode and its parameters and press enter to keep typing without having to type too many symbols or having to move your cursor.</p>
<p>I keep switching between IntelliJ and the localhost page on my browser, where my hugo server is showing how the end result will be (just launch &ldquo;hugo server&rdquo; from the root folder). If you have the page open you don&rsquo;t even need to refresh it thanks to Hugo&rsquo;s live reload feature (and don&rsquo;t even have to save the file since IntelliJ does it when it loses focus). This is very quick to do, which is particularly nice when you want to make final tweaks to make sure your post will display as you want.</p>
<h2 id="online">Online</h2>
<p>If you are using Github and want to write from your browser, or you are not at home, you can use <a href="https://prose.io">prose.io</a>. It&rsquo;s a software developed for Jekyll, but works just fine with Hugo. You get some nice shortcuts to format your text with markdown in case you are not too familiar with it. It also allows you to upload images which are committed to your repo immediately. I don&rsquo;t find it quite as powerful as IntelliJ but it&rsquo;s a nice option.</p>
<p>You can have a look at <a href="https://github.com/Draga/go-web/blob/master/_prose.yml">my prose configuration</a> to get you started. It&rsquo;s important to know that prose.io can only generate content with yaml metadata. You will have to configure Hugo to do the same by adding <code>MetaDataFormat: yaml</code>.</p>
<p>I&rsquo;ve looked at many more free online content editor:</p>
<ul>
<li><a href="http://sofish.github.io/pen/">sofish</a></li>
<li><a href="http://www.webhook.com/">webhook</a></li>
<li><a href="https://www.contentful.com">contentful</a></li>
<li><a href="https://prismic.io/">prismic</a></li>
<li><a href="https://stackedit.io">stackedit</a></li>
<li><a href="http://dillinger.io/">dillinger</a></li>
</ul>
<p>I found them actually extremely good&hellip;just not very compatible with Hugo.</p>
<p>Unfortunately I couldn&rsquo;t find any online resource to write and preview Hugo content, so editing content locally and preview it with Hugo server is still the best option for me. I reckon you could host a test environment to preview your draft, deploying with a different branch, by adding <code>-buildDrafts</code> to your <code>hugo</code> or <code>hugo server</code> commands.</p>
<p>Hopefully some tool that works perfectly with Hugo will come out soon. Spf13, the creator of Hugo, <a href="https://discuss.gohugo.io/t/web-based-editor/155/41">is thinking about creating one</a>.</p>
<h1 id="deployment">Deployment</h1>
<p>I can deploy my website in 2 ways:</p>
<ul>
<li>Push you branch to the repo on the server.</li>
<li>Push the master branch to the main repo. In my case this is on Github but can work with pretty much anything else.</li>
</ul>
<p>These both trigger a small script which I&rsquo;ve adapted from <a href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-hugo-site-to-production-with-git-hooks-on-ubuntu-14-04">this tutorial on Digitalocean</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1"># Better be specific rather than using $HOME because it wouldn&#39;t work with all users.</span>
</span></span><span class="line"><span class="cl"><span class="nv">GIT_REPO</span><span class="o">=</span>/home/draga/go-web
</span></span><span class="line"><span class="cl"><span class="nv">WORKING_DIRECTORY</span><span class="o">=</span><span class="nv">$GIT_REPO</span>/public
</span></span><span class="line"><span class="cl"><span class="nv">PUBLIC_WWW</span><span class="o">=</span>/home/draga/public_html
</span></span><span class="line"><span class="cl"><span class="nv">BACKUP_WWW</span><span class="o">=</span>/home/draga/backup_html
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -e
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Clean working dir.</span>
</span></span><span class="line"><span class="cl">rm -rf <span class="nv">$WORKING_DIRECTORY</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Backup current website. Use -z if moving across network to save bandwidth.</span>
</span></span><span class="line"><span class="cl">rsync -aq <span class="nv">$PUBLIC_WWW</span>/ <span class="nv">$BACKUP_WWW</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Restore backup if an error occurs from now on.</span>
</span></span><span class="line"><span class="cl"><span class="nb">trap</span> <span class="s2">&#34;echo &#39;A problem occurred.  Reverting to backup.&#39;; rsync -aq --del </span><span class="nv">$BACKUP_WWW</span><span class="s2">/ </span><span class="nv">$PUBLIC_WWW</span><span class="s2">; rm -rf </span><span class="nv">$WORKING_DIRECTORY</span><span class="s2">&#34;</span> EXIT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># fetch repo to make sure it&#39;s up to date if working with remote webhook.</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$GIT_REPO</span>
</span></span><span class="line"><span class="cl">git fetch
</span></span><span class="line"><span class="cl">git checkout origin/master
</span></span><span class="line"><span class="cl"><span class="c1"># Build the website. GO HUGO!</span>
</span></span><span class="line"><span class="cl">/usr/bin/hugo -s <span class="nv">$GIT_REPO</span> -d <span class="nv">$WORKING_DIRECTORY</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Mirror the output of Hugo to the directory where the website is hosted.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Use -c to copy only files that have changed to avoid messing with webhost caches.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Use -z if moving across network to save bandwidth.</span>
</span></span><span class="line"><span class="cl">rsync -aqc --delete <span class="nv">$WORKING_DIRECTORY</span>/ <span class="nv">$PUBLIC_WWW</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Ask Google webmaster tools to parse your sitemap.</span>
</span></span><span class="line"><span class="cl">curl https://google.com/webmasters/sitemaps/ping?sitemap<span class="o">=</span>https://stefano.chiodino.uk/sitemap.xml
</span></span><span class="line"><span class="cl">curl https://www.bing.com/ping?sitemap<span class="o">=</span>https%3A%2F%2Fstefano.chiodino.uk/sitemap.xml
</span></span><span class="line"><span class="cl"><span class="c1"># Disable trap.</span>
</span></span><span class="line"><span class="cl"><span class="nb">trap</span> - EXIT
</span></span></code></pre></div><p>I used the method described in the tutorial above for a while, but it bothered me to push twice since I had to type the password for my ssh key (I&rsquo;ve disabled the password access to the server and can now only be accessed with the key). Also what if I wasn&rsquo;t home or wanted to use prose.io?</p>
<p>Solution: git(hub) webhooks!</p>
<p>Thanks to <a href="https://github.com/adnanh/webhook" target="_blank">github.com/adnanh/webhook</a>, little software written in go, you can have you server listen on a port and execute a script when invoked.</p>
<p>I currently have it connecting in https, with a secret key, and executing the script when the master branch is pushed.</p>
<p>Now I can even use Github itself to edit my posts. Pretty neat!</p>
<h1 id="hosting">Hosting</h1>
<p>Now this was the <del>long</del> fun part. I wanted it all so it took a lot of learning, hence the fun.</p>
<p>I heard of nginx a lot and some research showed that it seems to be the go-to solution. Here are some, more performance related, details of how it performs for me: <a href="/posts/server-load-test/">server load test</a>.</p>
<p>I&rsquo;ve then enabled the pagespeed module which is very complex and heavy, but definitively worth it!
The website now scores <a href="https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Fstefano.chiodino.uk%2F" target="_blank">100/100 in Google PageSpeed</a>, both in mobile and desktop!</p>
<p>I score 99/100 in <a href="https://gtmetrix.com/reports/stefano.chiodino.uk/FsGkxV4j" target="_blank">GTmetrix</a> just because there is a bug in the pagespeed module (<a href="https://github.com/pagespeed/ngx_pagespeed/issues/1064">1064</a>) and the very header is added twice, and for some reason GTmetrix seems to think that is not there&hellip;? Or maybe is because pagespeed seems to add it on subsequent reloads. Another small penalty is for the G analytics code being cached for just 2 hours, it&rsquo;s out of my control and don&rsquo;t think is worth self hosting it.</p>
<p>YSlow seems to be mostly concerned of the lack of CDN.</p>
<p>You can find all the scripts that I&rsquo;ve used to set up my server on <a href="https://github.com/Draga/serverScripts">github</a>. They are ordered in the same way they are in the filesystem, so you should get the idea. There is a script to install nginx with the brotli and pagespeed module, directives to use webhook as a service, the entire nginx configuration, etc.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Server load test</title>
      <link>https://stefano.chiodino.uk/posts/server-load-test/</link>
      <pubDate>Sat, 14 May 2016 00:00:00 +0000</pubDate>
      <guid>https://stefano.chiodino.uk/posts/server-load-test/</guid>
      <description>Load testing a $5 Digitalocean server</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve recently tried <a href="https://m.do.co/c/875cd23a5c97" target="_blank">Digitalocean</a> hosting and decided to host this blog on it. I&rsquo;m running a $5 / month server, or droplet as they call it, with 1 CPU, 512 MB of ram, 20 GB SSD and 1 TB of bandwidth. You even get $10 credit when you sign up, sweet!</p>
<p>You may look down on a $5 machine but I&rsquo;ve found it to be more than enough for my need.</p>
<p>I&rsquo;m serving &ldquo;static&rdquo; content that has been generated by <a href="https://gohugo.io" target="_blank">Hugo</a></p>
<p>I recently ran some load testing at work for a newly launched website so I decided to test this $5 server. I&rsquo;ve been using <a href="https://loader.io" target="_blank">loader.io</a> since its basic usage is free.</p>
<h2 id="the-test">The test</h2>
<p>The server responds to a certain number of clients every second for a full minute.</p>
<p>The majority of the users must receive the page in &lt; 5 secs. Only the html is loaded.</p>
<h2 id="plain-html">Plain HTML</h2>
<p>10.000 requests a second! (that is the maximum that loaded.io goes on a free plan)</p>
<h2 id="enable-strong-https">Enable strong HTTPS</h2>
<p><a href="https://www.ssllabs.com/ssltest/analyze.html?d=https%3A%2F%2Fstefano.chiodino.uk" target="_blank" data-vivaldi-spatnav-clickable="1">How strong you say?</a></p>
<p>As expected enabling https is taking its toll. The server can&rsquo;t accommodate less than half of the requests, &ldquo;just&rdquo; 4.000.</p>
<h2 id="full-on-pagespeed-on-strong-https">Full on PageSpeed on strong HTTPS</h2>
<p>I&rsquo;ve then enabled Google&rsquo;s PageSpeed module for Nginx and enabled every performance related filter!</p>
<p>I&rsquo;ve enabled 27 extra filters on top of the 34 enabled by default, leaving just 7 out that were just for compatibility or counterproductive, hell I&rsquo;ve even enabled the filter to make the G analytics script async when it&rsquo;s already implemented that way.</p>
<p>Result: a quite dramatic 150 clients/sec 😀</p>
<p>Here is the list of filters that I&rsquo;ve enabled:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nginx" data-lang="nginx"><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">responsive_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">outline_css</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">outline_javascript</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">move_css_above_scripts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">move_css_to_head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">rewrite_style_attributes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">prioritize_critical_css</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">make_google_analytics_async</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">canonicalize_javascript_libraries</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">inline_google_font_css</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">local_storage_cache</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">convert_to_webp_animated</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">insert_image_dimensions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">inline_preview_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">resize_mobile_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">remove_comments</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">collapse_whitespace</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">elide_attributes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">extend_cache_pdfs</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">sprite_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">rewrite_domains</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">trim_urls</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">remove_quotes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">defer_javascript</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">dedup_inlined_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">lazyload_images</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">pagespeed</span> <span class="s">EnableFilters</span> <span class="s">insert_dns_prefetch</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="brotli-max-compression">Brotli (max compression)</h2>
<p>Just add Accept-Encoding: br to loader.io request headers and&hellip; 75 clients / sec. Not bad considering that I&rsquo;ve enabled the maximum (11) level of compression!</p>
<p>..and, if you are curious about the compression, my homepage file sizes are (method from <a href="https://hacks.mozilla.org/2015/11/better-than-gzip-compression-with-brotli" target="_blank">Mozilla&rsquo;s brotli post </a>):</p>
<table>
<thead>
<tr>
<th>Algorithm</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr>
<td>none</td>
<td>9508</td>
</tr>
<tr>
<td>gzip</td>
<td>3344</td>
</tr>
<tr>
<td>brotli</td>
<td>2732</td>
</tr>
</tbody>
</table>
]]></content:encoded>
    </item>
  </channel>
</rss>
