<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>windler.dev</title><description>Personal website of Carsten Windler</description><link>https://windler.dev/</link><item><title>10 Things Bikepacking Taught Me About Software Development</title><link>https://windler.dev/blog/10-things-bikepacking-taught-me-about-software-development/</link><guid isPermaLink="true">https://windler.dev/blog/10-things-bikepacking-taught-me-about-software-development/</guid><description>Software development lessons borrowed from bikepacking: pack light, trust your stack, test equipment, and choose quality over cheap shortcuts.</description><pubDate>Tue, 14 Oct 2025 00:00:00 GMT</pubDate><content:encoded>Disclaimer: This article is a bit of an ironic take on the unironic brag posts of “successful” people you’ll find on platforms like LinkedIn. Nevertheless, there are some learnings about software quality that could be helpful. What can riding a bike tell me about writing software? Well, actually, not so much, since I’ve been a professional software developer for far longer than I’ve enjoyed bikepacking. But nevertheless, there are quite some interesting parallels I discovered. Before we start, if you don’t know about bikepacking, it’s like going on vacation, but you carry everything you need on your bike. It is a very minimalist way to travel, but that’s precisely what’s so great about it. Alright, let’s go: Less is more Only carry what you really need. The fewer items you have, the fewer things can break, the further you can travel, and the more fun you have. At some point you learn that you don’t need as many things on the way as you thought. Sometimes I think companies just keep adding new features because they have a Product team they need to keep busy. Or do you really use any other features of Slack than messaging? But bloated software has many negative sides. The complexity makes it error-prone, and it requires more resources to operate it. This is costly and produces plenty of carbon emissions. Your users will also appreciate an app that reacts fast. Fast-loading websites are better for the user experience. An app that doesn’t drain the battery in minutes is much more useful. Same as a light and swift bike. Simplicity Chose standard components over exotic solutions. You don’t want to end up in some remote location where it takes a couple of days to get a replacement part delivered. Likewise, prefer simple solutions for problems rather than over-engineering. You don’t want to end up with a piece of software that can only be understood by the developer who just left the company. Simpler solutions tend to be more robust and less energy-thirsty, too. Know and trust your stack On a long-range trip, your bike is your best companion. The more you know about it, the more problems you can solve on your own. The more you trust it, the more fun you have. Running an app on a production environment that you hardly know is like a lottery. It might go well. But odds are high that something (TM) will happen. When (not if) production issues occur, knowing how your stack works definitely helps to keep downtimes low. And your blood pressure, too. Test your equipment Never take an untested piece of equipment on a trip. Chances are high that it doesn’t work as expected, and then you’re screwed. The same goes for your shiny new library or external service – test it carefully before exposing it to production the first time. You want to know if and how it scales under load, for example. This will avoid unpleasant surprises. Quality is key Cheap equipment is often tempting. What could possibly go wrong? Well, spending a few more bucks can definitely make a difference. The bags for my bike are not from the cheapest brand, but I know that they will last almost forever, and the parts that can break are easily replaceable (as in, easy to buy spare parts and easy to exchange). It saves money eventually and is better for the environment. Writing code that fulfills modern software quality standards is more costly. However, others (and yourself, like after not touching the code base for a few months) will still be able to understand and maintain the code. If you require a service or a commercial tool, don’t just look for its price. I’m often surprised how many managers entirely ignore the working hours it costs to operate a tool that is not the best choice but costs a bit less money per month. Training is essential Don’t expect to master your first overland trip immediately. It will take you some training, but you’ll get there – be it biking or software development, working on your skills and gathering experience is essential. For example, the first time you fixed a flat tire or the chain should not be on a tour, even if you watched a YouTube video about it a couple of days ago. On the tech side, don’t expect to do everything perfectly immediately. It takes time, experience, and learning through failure. To not get surprised by a production outage, for example, conduct disaster recovery exercises. Write down your findings, and create playbooks with easy steps that you can follow when necessary. You will appreciate it in stressful situations for sure. Preparation and requirements You just launched a new feature within the tight deadline but realize you’ve not considered an important case, and it now bites you in the behind? Now you have to roll back, and customers are unhappy. Probably you should have spent some more time on the requirements, even if that means making the management unhappy (they will always be, anyway). Before I go on longer trips, I always check what weather to expect, which shops are nearby, where to get some fresh water, or if there is a train connection available in case my bike breaks down. Having alternatives in mind allows me to quickly react to problems. Cleanup and maintenance A dirty drivetrain reduces your performance and the longevity of important bike components. So you are better off cleaning them regularly. Of course, you should also check the rest of your bike, like screws or tires, now and then to avoid unpleasant surprises. The same should apply to your software. If I got a penny for every time a full disk caused problems (yes, even in the cloud), I still wouldn’t be rich, but I’d have a nice collection of coins. Seriously, bringing out the garbage (cleaning logs, backups, etc), cleaning up your code, checking your monitoring &amp; logging for unusual patterns, updating (and removing) dependencies regularly, and so on, should be part of your routine to keep things going nice and smoothly. You and your customers will benefit from better performance, lower operational costs, and a smaller carbon footprint. Enjoy the ride! Take breaks Bike trips can be exhausting. Just take a break when you need it. Have a coffee and some snacks, and it’ll be easier afterwards. This is similar to what I encountered when working on challenging issues. If you are stuck on a problem, take a break, have a walk around the block, or sleep on it. Often enough, the solution will come easily when you’re back at your desk. Doing it yourself is more fun The feeling of accomplishing a pretty long ride only with my muscle power is unbeatable for me. Taking this minimalist approach feels wholesome. That’s real freedom, which I can’t have on an e-bike or in a car. No extra electricity or fuel is required. Many people are hyped about vibe coding and all that AI stuff. And while I use it too (where it makes sense), I also still enjoy hand-crafting my code. This way, I don’t have to rely on an LLM to accomplish my tasks when it starts writing bulls… hallucinating. Lessons learned And that’s it! Although it started as some kind of fun post, I think there are numerous good practices that software development and bikepacking have in common. Seriously, I had to learn some lessons the hard way for both. Thank you for reading, and stay tuned for my next article, “15 surprising facts doing the chores told me about cloud infrastructure” (kidding) ;-)</content:encoded></item><item><title>A normal day, a normal bug</title><link>https://windler.dev/blog/a-normal-day-a-normal-bug/</link><guid isPermaLink="true">https://windler.dev/blog/a-normal-day-a-normal-bug/</guid><description>Bug reports waste hours when they lack reproduction steps, context, and neutral wording. A call for better-written bug tickets.</description><pubDate>Thu, 14 Jan 2016 00:00:00 GMT</pubDate><content:encoded>After fixing approx. 5 billion bugs (+/- 1 billion) in my life so far, I have a clear picture of how a bug ticket should be written to actually support the developer rather than wasting his time. Maybe this is the reason why I always get a bit mad when I read descriptions like The form validation depends on the gender radiobuttons, which is not normal. Normally So, this raises the good old question: what is normal? Especially, what is normal when there are no requirements for the radiobuttons? Common sense? Whose common sense? Mine? The reporters? By the way, the bug turned out to be a feature. Srsly. When a ticket states that something is &quot;not normal&quot;, &quot;not ok&quot; or &quot;totally wrong&quot;, then it adds some sort of personal judgement. No developer is happy to receive a bug ticket, so they should be written as neutral as possible, as we already have to live with the shame. The Minimum Information Strategy One nasty bug I was once only able to reproduce by clicking a couple of buttons in exact the same order as the Project Manager - of course this was not part of the ticket description, so after trying to reproduce the issue for half an hour (the ticket going back and forth a couple of times meanwhile, and the tone was about to get rougher...), I gave up and asked the PM to share the screen. Aha! After being able to reproduce the bug, it was fixed in 5 minutes. So in total, the PM and I together lost over an hour because the ticket was missing information that could have been added to it in two minutes. Not to mention the bad mood you and others get in. And this sums up over lifetime. Minimum - and I mean it My favorite bug screenshot of all times: I&apos;m not kidding. Someone really made the effort to take a screenshot of the alert, cut it precisely to not contain any valuable information at all (Browser? URL? Any other screen context?) and attached it to a ticket (which was quite a pain with the clumsy ticket system we worked with back then). Sure, the error message itself leaves, erm, room for improvement. However I&apos;m always wondering why bug reporters cut the screenshots. Probably it&apos;s fun. I should try it myself. Common sense So what can we developers do? Give up? No. Resist. Every time you get a bug ticket which is not written well, assign it back and kindly ask for more information. You can&apos;t reproduce the issue? Don&apos;t waste your time, write back and ask for steps to reproduce please. The CSS is messed up, but the ticket only contains a small part of the actual screen and not even a browser version? Don&apos;t let your hair turn grey, assign it back with a smile! When searching the net on how to write bug reports, you&apos;ll find that here there actually is some sort of common sense. Basically, you&apos;ll find more or less the following structure: Bug title The bug description. Simple, concise, to the point. Not as simple as &quot;Application broken&quot;, however. Steps to reproduce Ah, my favorite. This could make life so much easier. I know it&apos;s annoying to write, but often necessary. &quot;Select a product and put it into the cart&quot; is a nice start, but most likely this will not make the bug reproducable. Expected results What results did you expect, and why? Is there a user story, ticket or any other document which could be helpful? Actual results What results did you get? Point out what is happening in contrary to the expected results. Browser Info A classic. Which Browser did you use? Please also add the version number, especially when IE is still to be supported. Screenshots A screenshot is helpful. Just keep it as it is, i.e. don&apos;t cut out anything. Especially the browser URL is very helpful, so just keep it. Dammit. Developers absolutely don&apos;t mind if there is too much information on it. If a lot of stuff is happening on it, consider adding markers (e.g. arrows). Additional info Any error message could be helpful. Do you find an error in the browser console? Please just copy &amp; paste it! Please also see the article &quot;Writing Issue Reports That Work&quot; by Joe Strazzere, the man with the &quot;I got the bug fixed in no time because of your wonderful bug ticket&quot;-smile. Sums it up really nicely. Thanks for reading &amp; happy bug fixing!</content:encoded></item><item><title>Absolute Beginner&apos;s Guide to Node.js</title><link>https://windler.dev/blog/absolute-beginners-guide-to-node-js/</link><guid isPermaLink="true">https://windler.dev/blog/absolute-beginners-guide-to-node-js/</guid><description>A short, beginner-friendly article that explains what Node.js actually is, for developers who keep nodding along but have not grasped it yet.</description><pubDate>Thu, 22 Aug 2013 00:00:00 GMT</pubDate><content:encoded>To be honest, when I first read the NodeJS website I was like &quot;Ok. WTF?&quot;. I didn&apos;t really understand the complete picture, and it seems I wasn&apos;t the only one. An Absolute Beginner&apos;s Guide to Node.js by Brandon Cannaday is ought to bring relief for our poor souls. It&apos;s short and concise, and after reading it you can keep on agreeing on that Node.js is some cool stuff without having that specific itch behind your forehead.</content:encoded></item><item><title>Accessing the ServiceManager from the ViewHelperManager in ZF2</title><link>https://windler.dev/blog/accessing-the-servicemanager-from-the-viewhelpermanager-in-zf2/</link><guid isPermaLink="true">https://windler.dev/blog/accessing-the-servicemanager-from-the-viewhelpermanager-in-zf2/</guid><description>How to access application configuration from a Zend Framework 2 ViewHelper factory by reaching the ServiceManager through the ViewHelperManager.</description><pubDate>Tue, 22 Oct 2013 00:00:00 GMT</pubDate><content:encoded>Sometimes the new ServiceManager(s) in Zend Framework 2 are a bit confusing. We don&apos;t have one, we have several instances. So recently I was writing a factory for a ViewHelper and wanted to access the application configuration from there. As usual, I was attempting it like this It ended up throwing an exception, saying the configuration could not be found. To make it short, after some searching I found this one Intuitive, isn&apos;t it? But it seems to work, so the factory looks like this now:</content:encoded></item><item><title>Appearance on the Lets Talk Leadership Podcast</title><link>https://windler.dev/blog/appearance-on-the-lets-talk-leadership-podcast/</link><guid isPermaLink="true">https://windler.dev/blog/appearance-on-the-lets-talk-leadership-podcast/</guid><description>Interview on the Lets Talk Leadership podcast about onboarding during a pandemic, leadership challenges, and why job titles are not everything.</description><pubDate>Wed, 02 Dec 2020 00:00:00 GMT</pubDate><content:encoded>What a year. You all know, no need to explain. And it&apos;s not over yet. Still I found the time to get interviewed by the two lovely hosts Elly Greany and Sandra Patel-Stewart from Transition Partners on their great &quot;Lets Talk Leadership&quot; Podcast. We had a relaxed conversation about challenges, onboarding during a global pandemic, why titles are not everything and so much more. Check it out: https://www.youtube.com/watch?v=Sik3G9KJhO8 You&apos;ll find the episode on these channels as well: Spotify: https://open.spotify.com/episode/2zkQfEzQ5yqVGBJRA7j77D Apple music: https://podcasts.apple.com/gb/podcast/lets-talk-leadership-podcast/id1507964938 Google Podcasts: http://shorturl.at/tBDO3 BuzzSprout: https://www.buzzsprout.com/991036/episodes/6575011-carsten-windler-head-of-development-at-kw-commerce-lets-talk-leadership</content:encoded></item><item><title>Automated bad practice</title><link>https://windler.dev/blog/automated-bad-practice/</link><guid isPermaLink="true">https://windler.dev/blog/automated-bad-practice/</guid><description>Laravel automatic facades make static-style access too tempting, bind code to the framework, and slow tests — a critique of an anti-pattern.</description><pubDate>Thu, 19 Jan 2017 00:00:00 GMT</pubDate><content:encoded>One new feature of Laravel 5.4 are so-called &quot;Automatic Facades&quot;. My colleague was expecting my reaction when he sends me the link to the blog entry announcing this feature (I&apos;m not linking it intentionally) with a thievish smile. As Laravel&apos;s documentation puts it, &quot;Facades provide a static interface to classes that are available in the application’s service container&quot;. In other words, you can access any class almost everywhere without hassling about nasty things like dependency injection. Hm? Do I hear Singleton somewhere? So far it was required to add Facade classes in order to make this work. It seems even this little barrier has fallen now. Laravel&apos;s Facade, in my opinion, is one of the worst features a PHP framework offers nowadays. After times of Zend Framework 1 and the infamous Registry (I abused it too), when IoC finally arrived in the PHP world, it somehow seemed to me as quite a setback when Laravel became more and more popular with its Facade feature (it&apos;s not even the Facade design pattern anyway). Here&apos;s why. 1\. It&apos;s tempting Making classes available in the code everywhere is tempting inexperienced (and experienced) developers to use the facade everywhere, without thinking if this might be a good idea or not. I&apos;ve seen things! I even found Facade in configuration files. IN CONFIG FILES WTF!!1 If you don&apos;t pay close attention, your classes soon will violate the single responsibility principle, simply because you don&apos;t really notice how many dependencies you suddenly use. 2\. It binds your code In my opinion, code should be bound as less to the underlying framework as possible. I totally get the advantages of ORMs and such, I&apos;m not opting against packages etc., but binding your code too close to a framework can cause problems if you want to use your business logic over longer terms. But well, I guess if you are willing to use non-namespaced helper functions everywhere in your code (another Laravel feature I &quot;deeply adore&quot;), you don&apos;t really care about this either. 3\. It requires more overhead to test &quot;But Facades are more testable than traditional static methods!&quot; I hear the Artisans yell. Yeah, sure, that is true. What a benefit! It just requires bootstrapping of Laravel for every test, making unit tests significantly slower. Your tests will become more complex and thus require more maintenance, as you will need to mock more dependencies which are all required to make one test work. 4\. It&apos;s actually not that convenient Any modern IDE provides Code completion, so I can see in a second which methods a class offers. With Facade, I need an additional package that parses the Facades and generates documentation files that the IDE can parse for the Code completion. How convenient! When stepping through the code during debugging it annoys me pretty much to go through the facade over and over again. It&apos;s just so unnecessary... Probably both IDE and Debuggers are not so commonly used amongst Artisans? 5\. It&apos;s not more expressive I really don&apos;t get why is more &quot;expressive&quot; than Somebody needs to explain! Fair enough To be fair, even the official Laravel documentation states that Facade should not be used when building a third-party package, and that it bears some of the above mentioned risks. So Taylor is aware of it. But then why is this feature enforced in the first place anyway? I think it&apos;s because Laravel claims to be so &quot;expressive&quot; and &quot;beautiful&quot; in it&apos;s syntax that everybody accepts the downsides. Decide for yourself if it is worth it. Probably I&apos;m just missing the point here? Why do you think Laravel&apos;s Facade should be used rather than Dependency Injection?</content:encoded></item><item><title>Babette</title><link>https://windler.dev/blog/babette/</link><guid isPermaLink="true">https://windler.dev/blog/babette/</guid><description>A short tragicomic story about a dev team and their new blade server that never made it past probation thanks to an unresponsive admin team.</description><pubDate>Wed, 01 Jul 2015 00:00:00 GMT</pubDate><content:encoded>&quot;Look at her! Isn&apos;t she beautiful? Ahhh, that smell.&quot; Carsten’s fingers were running gently across the black case of their new colleague, a Blade Server with dozens of cores and hundreds of Gigabyte of storage, inspecting all those little details here and there. &quot;I think I&apos;ll call her Babette!&quot; &quot;Well, finally we got it.&quot; Mike completely ignored Carsten’s gibberish. It has &quot;only&quot; been three month since their Virtual Servers have been &quot;accidently&quot; canceled by &quot;the Admins&quot; in &quot;the HQ&quot;, leaving half of the Software Development department without a reasonable development environment all of a sudden. Good for &quot;the Admins&quot; that HQ was about 800km from their office. Too far away for a spontaneous visit or, let&apos;s say, a Team Building Exercise. After that incident it was decided to place a server right in the office, so that the Development Team could set up Virtual Hosts as needed and without going the long route via &quot;the Admins&quot;. Everybody was quite excited, yes, even - happy! A way of happiness only developers can understand. &quot;So, when will the server be configured?&quot; Stephen asked. A good question. &quot;The Admins told us this will be done next week.&quot; Mike replied. Just one month later, and after a couple of friendly reminders, they received an email from &quot;the Admins&quot;. The server is now ready to be tested, please let us know if you need anything, et cetera, blabla. The Devs responded quickly: &quot;Guys, we can&apos;t even access the server with the credentials you gave us. Please tell us what we are doing wrong!&quot;. Although they were no &quot;Admins&quot;, the Devs were a bit skilled with that stuff from their everyday work, but still there was a chance that the error was on their side. Needless to say that the admins reply came promptly after another week, and yes, after some not-so-friendly-anymore reminders. &quot;Oh well, the server has crashed somehow, but we fixed that now&quot;. &quot;Buckle up guys, we&apos;re almost there. I can access the server now!&quot; Carsten shouted through the office. Surely some useful stuff was missing, but at least the basic setup was ok. So everyone inspected it, writing down what would be needed for a standard development environment, which would then act as image for the Virtual Hosts later. &quot;All right, the email is out. It can now only be a matter of days until we can start working on it.&quot; said Mike, still trying to be optimistic, but with a noticeable amount of skepticism. Too many lessons they learned the hard way. Days passed. &quot;What do they mean, we are not allowed to setup the Virtual Hosts by ourselves?? I thought this is our development server, it is not even reachable from outside of the companies VLAN, why should we ask THEM all the time?!&quot;. Dang. Situation got critical. More days passed. Then they got another email… &quot;So it seems our new colleague hasn&apos;t made it through the probation phase&quot;. Mike sighed as he pulled the power. The only noise in the silence was the sound of the fans getting slower and slower. The Dev Team has been informed that currently there are no spare resources to take care of the development server, and they shouldn&apos;t expect it to be available within the next 6 months. The fans finally stopped spinning. Good bye, Babette.</content:encoded></item><item><title>Green IT - Sustainable Software Engineering</title><link>https://windler.dev/blog/cgreen-it-sustainable-software-engineering/</link><guid isPermaLink="true">https://windler.dev/blog/cgreen-it-sustainable-software-engineering/</guid><description>Podcast conversation (in German) with Maxie Duda on how software engineers can reduce greenhouse gas emissions through sustainable software engineering.</description><pubDate>Sat, 04 Sep 2021 00:00:00 GMT</pubDate><content:encoded>Recently, I spoke with Maxie Duda on The Evolution Exchange Podcast about how Software Engineers could do their part on reducing greenhouse gas emissions. Green IT, and Sustainable Software Engineering in particular, is a highly fascinating field, and I have just started exploring the possibilities. Although actually being a serious topic, it was still a lot of fun, thanks to Maxie&apos;s cheerful and kindly manner. Time flew, and it turned out that 45 minutes was by far not enough time to talk about all the stuff I wanted to mention. If you are interested in it, you&apos;ll find the links below (the talk was in German, though). ?Soundcloud https://soundcloud.com/evolution-marketing/evo-33-green-it-sustainable-software-engineering ?Spotify https://open.spotify.com/episode/7mScCmx5AATDMOmzofNeAt ?Apple Podcast https://podcasts.apple.com/us/podcast/evo-33-green-it-sustainable-software-engineering/id1572442514?i=1000532962241</content:encoded></item><item><title>Checkout the massage!</title><link>https://windler.dev/blog/checkout-the-massage/</link><guid isPermaLink="true">https://windler.dev/blog/checkout-the-massage/</guid><description>A Codeception test asserts the presence of #checkout-successful-massage — a typo that quietly passed because the matching element did exist.</description><pubDate>Fri, 04 Sep 2015 00:00:00 GMT</pubDate><content:encoded>What a nice typo. I wonder what the colleague was thinking about in that moment: And yes, the test did pass. Wonderful :-)</content:encoded></item><item><title>Clean Code Days 2016 - Opening Keynote</title><link>https://windler.dev/blog/clean-code-days-2016-opening-keynote/</link><guid isPermaLink="true">https://windler.dev/blog/clean-code-days-2016-opening-keynote/</guid><description>Opening keynote at Clean Code Days 2016 on why you cannot establish clean code alone, with tips to convince managers and refactor legacy projects.</description><pubDate>Mon, 15 Aug 2016 00:00:00 GMT</pubDate><content:encoded>] End of June this year I had the honor to hold the Opening Keynote at the Clean Code Days 2016 in Munich. Actually my first talk on a Conference ever, I called it &quot;The Lone Stranger, or: Why you can&apos;t establish Clean Code on your own&quot;. It covers the wide range from how to convince Managers and Co-Developers to start clean coding, over to tips and tools on how to change a legacy project from sloppy code into better and one day maybe even &quot;Clean Code&quot;. Opening Keynote on Youtube Slides I wasn&apos;t able to watch it in full yet (boy, my voice sucks ;-), but I hope you like it!</content:encoded></item><item><title>Clean Code in PHP - My first book</title><link>https://windler.dev/blog/clean-code-in-php/</link><guid isPermaLink="true">https://windler.dev/blog/clean-code-in-php/</guid><description>My first book, Clean Code in PHP, co-authored with Alexandre Daubois, helps early-career PHP developers write maintainable, human-friendly code.</description><pubDate>Sun, 27 Nov 2022 00:00:00 GMT</pubDate><content:encoded>After many months in the making, my first book - Clean Code in PHP: Expert tips and best practices to write beautiful, human-friendly, and maintainable PHP - has finally been published end of October this year. Together with Alexandre Daubois from SensioLabs, the company that created the Symfony PHP framework, I teamed up to write down my experience as a PHP developer and team lead to help other PHP developers to write clean and maintainable PHP code. This book is for early-career PHP developers who wish to avoid writing messy code by learning how to write understandable and maintainable code that sets them apart from rest. The book assumes familiarity with PHP coding and principles, but no knowledge of advanced principles will be necessary. Find out more what the book is about: What is Clean Code and Why Should You Care Who Gets to Decide What &quot;Good Practices&quot; Are? Code, Don&apos;t Do Stunts It&apos;s about More Than Just Code Optimizing Your Time and Separating Responsibilities PHP is Evolving- Deprecations, Evolutions, and PSR Code Quality Tools Code Quality Metrics Organizing PHP Quality Tools Automated Testing Continuous Integration Working in a Team Creating Effective Documentation You can buy it at Amazon or directly at Packt Publishing.</content:encoded></item><item><title>Coding against climate change // code.talks 2022</title><link>https://windler.dev/blog/coding-against-climate-change-code-talks-2022/</link><guid isPermaLink="true">https://windler.dev/blog/coding-against-climate-change-code-talks-2022/</guid><description>Talk recording from code.talks 2022 in Hamburg on coding against climate change, the revamped German edition of the sustainability session.</description><pubDate>Sun, 16 Oct 2022 00:00:00 GMT</pubDate><content:encoded>On the 15th of September this year, I had the pleasure to give the latest, almost completely revamped edition of my talk Coding against climate change on the code.talks 2022 in Hamburg. It was a great experience to speak in the CinemaxX Dammtor. From the amount of positive feedback I received afterwards, I can tell that this topic is getting more and more important. The talk, which by the way was the first German talk I ever did, is available on Youtube now: https://www.youtube.com/watch?v=spPflIHmxz8. Photos by Volker Renner ©: volkerrenner.de</content:encoded></item><item><title>How to write Coding Guidelines in PHP</title><link>https://windler.dev/blog/coding-guidelines/</link><guid isPermaLink="true">https://windler.dev/blog/coding-guidelines/</guid><description>Coding guidelines for PHP teams: naming conventions, structure, and shared standards that ease onboarding and remove arguments during code review.</description><pubDate>Sat, 10 Dec 2022 00:00:00 GMT</pubDate><content:encoded>Writing PHP applications in a team requires clear guidelines and a lot of alignment. In my book, Clean Code in PHP, I dedicated a full chapter, Working in a team, on how to write PHP software together with other developers. Coding Guidelines are easy to introduce yet still compelling, so it makes them a perfect tool to introduce to early. Together with your team, you agree on standards to write your software. This is not only important for onboarding new colleagues, which surely will be happy to see how the new team they will be part of writes the code. It is also useful during Code Reviews—once agreed on a rule, you don&apos;t need to argue about in anymore. The following article is supposed to give you some inspiration for your team&apos;s guidelines. Please don&apos;t consider them as the single truth or set in stone: every software team is different, and what works for one team, might not work for the other. Naming Conventions Services, Repositories, and Models Written in UpperCamelCase. Use the type as suffix. Examples: Events Written in UpperCamelCase. Use the correct tense to indicate if the event is fired before or after the actual event. Examples: is the event before the deletion is the actual event is the event after the deletion Properties, Variables, and Methods Written in lowerCamelCase. Examples: Tests Written in lowerCamelCase. Use the word as a prefix. Examples: Traits Written in UpperCamelCase. Use the adjective to describe what the Trait is used for. Examples: Interfaces Written in UpperCamelCase. Use the word as suffix. Examples: General PHP conventions Comments and DocBlocks Since PHP 8, most information in DocBlocks can be reused by native PHP features, particularly type hints. Redundant or even useless DocBlocks simply waste time of the developers, while wrong DocBlocks can cause confusion and bugs. Ternary Operators Every part should be written in a single line to increase readability. Exceptions can be made for very short statements. Do not use nested ternary operators, as they are hard to read and debug. Constructor Use Constructor Property Promotion for shorter classes, if working with PHP 8+. Arrays Always use the short array notation and keep the comma after the last entry. Control structures Always use brackets, even for one-liners. Avoid else statements and return early, as this is easier to read and reduces the complexity of your code. Exception Handling Empty catch blocks should be avoided, as they silently swallow error messages and thus can make it difficult to find bugs. Instead, log the error message or at least write a comment which explains why the exception can be ignored. Architectural patterns Coding Guidelines are not limited on how to format code or name elements. They can also help you to control how the code is written in an architectural sense. Fat models, skinny controllers If the Model View Controller (MVC) pattern is used, the business logic should be located inside models or similar classes, like services or repositories. Controllers should only contain as little code as possible which is required to receive or transfer data between the views and the models. Framework-agnostic code In the context of the fat models, skinny controllers approach, you will probably come across the term framework-agnostic business logic. It means that the code that contains your business rules should use features of the underlying framework as few as possible. This makes framework updates or even migrations to other frameworks much easier. Single responsibility principle Classes and methods should only have one responsibility, as stated by the Single Responsibility Principle. Framework guidelines How to access the database? How to configure routes? How to register new services? How is Authentication handled within your project? How should errors or other debug information be logged? How to create and organize view files? How to handle translations? Since the answers to these questions highly depend on the used framework, we cannot give you recommendations here. You will need to set them up together with your team. In the next section, we will give you some ideas on how to do that.</content:encoded></item><item><title>Continuous Testing and Beyond - Software Quality in Web Projects</title><link>https://windler.dev/blog/continuous-testing-and-beyond-software-quality-in-web-projects/</link><guid isPermaLink="true">https://windler.dev/blog/continuous-testing-and-beyond-software-quality-in-web-projects/</guid><description>Talk slides from the 121 Test Automation Day Berlin on continuous testing and software quality in web projects, with feedback from the audience.</description><pubDate>Mon, 23 Apr 2018 00:00:00 GMT</pubDate><content:encoded>Two weeks ago I was invited to speak on the 121 Test Automation Day Conference Berlin about one of my most favourite topics - Software Quality in Web Projects. It really was a nice audience and I received very good feedback on it. The slides can be found here: https://slides.com/carstenwindler/continuous-testing-and-beyond#/. Looking forward to my next talk, wherever that will be :-)</content:encoded></item><item><title>Create your own PHP extension (on Windows)</title><link>https://windler.dev/blog/create-your-own-php-extension-on-windows/</link><guid isPermaLink="true">https://windler.dev/blog/create-your-own-php-extension-on-windows/</guid><description>How to build a custom PHP extension on Windows with Visual C, including locating php5ts.lib and working around a socklen_t redefinition error.</description><pubDate>Wed, 07 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Have you ever thought about writing your own PHP extension? There are surely a few pro&apos;s and con&apos;s about creating PHP extensions to solve problems, rather than write PHP libraries. But this is not the question here. I was curious. So come on Internet, let&apos;s see what you got for me... http://www.dreamincode.net/forums/topic/244215-introduction-to-creating-a-php-extension-for-windows/ http://blog.slickedit.com/2007/09/creating-a-php-5-extension-with-visual-c-2005/comment-page-2/ Looks a bit outdated, but that&apos;s not the problem here for me. As a matter of fact, I&apos;m currently still using PHP 5.3.5 on my dev for a list of reasons. And I&apos;m using Windows and I don&apos;t complain (I know my colleagues think I&apos;m weird). Luckily both tutorials cover the topic on how to create the extension on Windows for PHP 5.3.5. So much win! And the best: it really works! Basically both tutorials provide you with everything you need. I had to get over two pitfalls though: php5ts.lib is not in the source code directory I just extracted, but in my WAMP stack already - in my case I located it in C:\\xampp\\php\\dev error C2371: &apos;socklen\_t&apos; : redefinition; different basic types \- I really have no idea why this error came up during compilation. However I was able to &quot;solve&quot; \cough\ the problem by commenting out lines 149 to 151 in the php.h: Surely not the ideal solution, but as I just wanted to try it out I don&apos;t mind at the moment.</content:encoded></item><item><title>cwenvbanner 0.1.0 released</title><link>https://windler.dev/blog/cwenvbanner-0-1-0-released/</link><guid isPermaLink="true">https://windler.dev/blog/cwenvbanner-0-1-0-released/</guid><description>cwenvbanner 0.1.0 released for TYPO3, adding predefined banner styles for easier setup of environment indicators in frontend and backend.</description><pubDate>Sun, 24 Aug 2014 00:00:00 GMT</pubDate><content:encoded>The latest release of cwenvbanner features predefined Banner styles for even easier setup. Please see the readme.md for more details!</content:encoded></item><item><title>cwenvbanner released</title><link>https://windler.dev/blog/cwenvbanner-released/</link><guid isPermaLink="true">https://windler.dev/blog/cwenvbanner-released/</guid><description>cwenvbanner, a TYPO3 extension that adds small banners to the frontend and backend so you stop mixing up environments across browser windows.</description><pubDate>Tue, 01 Jul 2014 00:00:00 GMT</pubDate><content:encoded>Now working with Typo3 again (Love .. Hate ... Love ... ), I thought it would be nice to finally publish my old cwenvbanner Extension. In short, it adds small banners to the Frontend and Backend of your Typo3 environments, so you don&apos;t mix up the browser windows anymore so often.</content:encoded></item><item><title>cwmobileredirect and cwenvbanner for Typo3 7 LTS</title><link>https://windler.dev/blog/cwmobileredirect-and-cwenvbanner-finally-available-for-typo3-7-lts/</link><guid isPermaLink="true">https://windler.dev/blog/cwmobileredirect-and-cwenvbanner-finally-available-for-typo3-7-lts/</guid><description>cwmobileredirect and cwenvbanner are now available in the TYPO3 extension repository for TYPO3 7 LTS, with Composer support and Travis CI setup.</description><pubDate>Tue, 06 Sep 2016 00:00:00 GMT</pubDate><content:encoded>Well, actually the Typo3 7 LTS versions were available for a couple of months through my Github repositories of cwmobileredirect and cwenvbanner already, however I never found the time to upload them to TER. Finally I found some time to upload it, so here you go: cwmobileredirect on TER cwenvbanner on TER The new versions do not include any new features, I did some cleanup though, so Typo3 4.x is no longer supported. Please just stick with the old versions of the extensions in case you are still using one of these ancient Typo3 installations. Besides Typo3 7 compatibility and cleanup I spend some time on making them work with a Composer based Typo3 installation (the outcome can be found on Github as well) and Travis CI. Since I only work on these extensions occasionally, this will surely help me in with the Typo3 8 LTS versions (which I hope to get done a bit earlier this time :-)).</content:encoded></item><item><title>cwmobileredirect now ready for Typo3 6.2</title><link>https://windler.dev/blog/cwmobileredirect-now-ready-for-typo3-6-2/</link><guid isPermaLink="true">https://windler.dev/blog/cwmobileredirect-now-ready-for-typo3-6-2/</guid><description>cwmobileredirect 1.4.4 is released with official TYPO3 6.2 support. No other new features or bugfixes, so only update if you run 6.2.</description><pubDate>Wed, 01 Oct 2014 00:00:00 GMT</pubDate><content:encoded>Version 1.4.4 of cwmobileredirect has just been released. It now officially supports Typo3 6.2. There are no other new features or bugfixes, so if you don&apos;t want to use it with 6.2, you don&apos;t need to update. By the way: cwmobileredirect has now been downloaded over 4.000 times - thanks :-)</content:encoded></item><item><title>cwmobileredirect v1.4.3 released</title><link>https://windler.dev/blog/cwmobileredirect-v1-4-3-released/</link><guid isPermaLink="true">https://windler.dev/blog/cwmobileredirect-v1-4-3-released/</guid><description>cwmobileredirect v1.4.3 for TYPO3 returns after two years, prepared for TYPO3 6.x with bugfixes and a handy update script for easier upgrades.</description><pubDate>Tue, 07 Jan 2014 00:00:00 GMT</pubDate><content:encoded>After more than two years of no active development on my Typo3-Extension cwmobileredirect I decided to release a new version, because it is still in use by quite some people. I&apos;m really glad it was helpful for others so far! Amongst small bugfixes and changes it is now prepared for Typo3 6.x and comes with a handy update script which will allow easier updates in the future. For those of you who have not yet heard of this cwmobileredirect (there might be one or two people still out there): this little extension, that was developed in the Pre-Responsive-Web-Era, detects mobile devices and redirects the user appropriately. Actually it does a little more, so if you&apos;re interested you can read more in the official Typo3 Repository (TER): http://typo3.org/extensions/repository/view/cwmobileredirect.</content:encoded></item><item><title>Debug shell scripts (well, kind of)</title><link>https://windler.dev/blog/debug-shell-scripts-well-kind-of/</link><guid isPermaLink="true">https://windler.dev/blog/debug-shell-scripts-well-kind-of/</guid><description>Debug shell scripts by adding set -x to print a trace of each command with variables expanded, so you can follow what is actually executed.</description><pubDate>Wed, 14 May 2014 00:00:00 GMT</pubDate><content:encoded>I have to look up this one frequently, because it is really helpful. If you want to see what lines of a shell script are actually executed, place this line in your code: \shell\set -x \/shell\ I usually do that after the funny thing called Shebang (#!/bin/bash - I can also never remember this one correctly), but surely you can place it right before the section where you expect the problem. If you have an idea where the problem might be, that is. If not, just start from the beginning. Cool thing: the variables are replaced in the output, or as the man page puts it: Print a trace of simple commands and their arguments after they are expanded and before they are executed</content:encoded></item><item><title>Debug Unit Tests using the PhpStorm built-in test runner</title><link>https://windler.dev/blog/debug-unit-tests-using-the-phpstorm-built-in-test-runner/</link><guid isPermaLink="true">https://windler.dev/blog/debug-unit-tests-using-the-phpstorm-built-in-test-runner/</guid><description>How to debug unit tests in PhpStorm built-in test runner by passing XDEBUG_CONFIG and PHP_IDE_CONFIG environment variables to the Run/Debug config.</description><pubDate>Wed, 04 May 2016 00:00:00 GMT</pubDate><content:encoded>PhpStorm comes with a handy phpunit test runner, which lets you execute your tests with just one click. Even better: if a test fails, you can just run that test also with just one click. That&apos;s how I like it. However I often use the debugger to debug failed tests. This is easy with phpunit and via the command line (see e.g. Remote CLI debugging). But since PhpStorm is obviously not using the command line, we have to pass the information necessary for Xdebug and PhpStorm to initiate the debug session using the Test Runners configuration. Needless to mention that the above values need to fit your setup. Most likely your server name will be different, and make sure to check the ide key. But where to put it? Assuming you already setup your Run/Debug configuration, just open the configuration dialog and put the above environment variables into the &quot;Environment variables&quot; input field. You don&apos;t need to add &quot;export&quot; or anything. Well, just have a look: Now just place your breakpoints as you need them and start the Run/Debug configuration.</content:encoded></item><item><title>Debug your Codeception tests with Xdebug and PhpStorm</title><link>https://windler.dev/blog/debug-your-codeception-tests-with-xdebug-and-phpstorm/</link><guid isPermaLink="true">https://windler.dev/blog/debug-your-codeception-tests-with-xdebug-and-phpstorm/</guid><description>How to debug Codeception acceptance and unit tests with Xdebug and PhpStorm by setting the XDEBUG_SESSION cookie via Cest, PhpBrowser, or remote-debug.</description><pubDate>Mon, 07 Mar 2016 00:00:00 GMT</pubDate><content:encoded>I use Xdebug not only to hunt bugs, but also for every day development work. Of course I also want to use it when I write my Tests. I one of my current projects we use Codeception for both Unit- and Acceptance tests. Debugging Codeception Unit tests is as easy as for phpUnit, you just have to make sure that the XDEBUG\SESSION is set as described in my post about CLI debugging with Xdebug. What to test The Acceptance tests I want to debug are basically just testing a REST API, so it&apos;s usually firing HTTP GET/POST requests against various endpoints: In order to debug the actual &quot;dostuff&quot; endpoint, I have to take care of two things: the debug session Cookie and the PhpStorm debug configuration. Set the XDEBUG\SESSION cookie The usual way for me to start a PhpStorm session for non-CLI scripts is to enable the &quot;Start Listening for PHP Debug Connections&quot; in PhpStorm and initiate a request with the XDEBUG\SESSION cookie set. I&apos;m assuming you have PhpStorm and Xdebug set up neat and nicely, as there are enough tutorials about it out there. This works nicely when I start a debug session using the browser, but now we don&apos;t use a browser and send the requests via HTTP directly (Codeception uses Guzzle for that), so we have to set the Cookie somehow. There are (at least) three ways to do that with Codeception: Set the cookie manually in the Cest (Codeception acceptance test class) Configure Guzzle to send the Cookie via the codeception.yml This is described Codeception manual on the PhpBrowser module Use the codeception/remote-debug extension Codeception-Remotedebug on Github This is my preferred way, it&apos;s actually pretty easy to set up, and this way I just send the Cookie all the time. Since the Cookie value (PHPSTORM) might be different for other developers, these settings should not be under Version control. Codeception allows several ways to achieve this, in our project we use a environment-specific setup, which is not under version control and allows use to extend or overwrite settings on the project-wide, version controlled codeception.yml_. Learn more about it in the Codeception manual on Environments. ## Increase PhpStorms Max. connections This might cause some headache if you forget about it. When I tried to all of the above ways to set the Cookie, the debug session was always getting stuck, i.e. PhpStorm was not stopping at the breakpoints and rather did - nothing! 1.png) By default, PhpStorm is configured to handle 1 debug session at a time. However in my case, I need to handle 2 debug sessions in parallel now - one debug session for the actual Acceptance test, and one for the API. And that&apos;s it. I hope this will be useful for other Codeception users as well!</content:encoded></item><item><title>Debugging Flow3 – ain’t got time for that!?</title><link>https://windler.dev/blog/debugging-flow3-aint-got-time-for-that/</link><guid isPermaLink="true">https://windler.dev/blog/debugging-flow3-aint-got-time-for-that/</guid><description>Xdebug slows Flow3 cache rebuilds to a crawl because of AOP class compilation. A small shell script enables Xdebug on demand only when actually debugging.</description><pubDate>Tue, 09 Dec 2014 00:00:00 GMT</pubDate><content:encoded>It is known that XDebug has a negative impact on performance, but what happens when you try to debug a Flow3 application can be something between absolutely surprising and totally annoying. But one after another. XDebug is my every day tool. I use it not only for debugging, but for regular development as well. I simply enjoy the benefit to always know which variables are available in the current scope (Typo3 globals, anyone?), I don&apos;t need to recall nested array structures, I can evaluate my code on the fly and so on. So naturally, on my dev XDebug is always enabled and listening, both for PHP SAPI or Webserver. Working on my first Flow3 project, I suddenly found myself waiting over 30 minutes for the Cache to rebuild after flushing it manually. Running the application on a different machine worked ok, so it was obvious that the issue was somewhere in my setup. Wtf? So I did what a normal XDebug user would do - let&apos;s profile that damn thing! I realized the core problem as I found dozends of sometimes quite huge Cachegrind files in my output directory. What the heck, there must be really some serious action going on (and it does - see box below)! So I disabled XDebug for the moment, and voilà - the Cache was rebuild within seconds. If you have not worked with Flow3 before you have to know that Flow3 actually requires cached class files because of the use of Aspect-oriented programming (AOP). In short, Flow3 scans the code files of the packages whether certain rules (the so called Aspects, defined via Annotations) apply, and changes the code in the classes according to the Aspect. Doing this for every request would be obviously insane, so the results are cached. We suddenly find our good old PHP scripts in some way being compiled. There is a nice article about Flow3 and AOP to be found here which describes it more in detail. Flow3 luckily has some advanced file monitoring which, when you work in Development context, makes it unnecessary to clear the whole cache manually every time you change a class, and rebuilding the cache for one class only will work within a reasonable amount of time even with XDebug turned on. Nevertheless sometimes you will need to flush the whole cache, and then you&apos;re doomed. En-/Disabling XDebug in the php.ini manually would be too cumbersome (for me). So there has to be a more convenient solution. How to debug Flow3 applications and stay sane Here&apos;s with what I ended up: I disabled XDebug for PHP via CLI by default, and enable it only when I need it using the &quot;php -d&quot; switch: Not a very easy one to remember, but we&apos;re getting close. Why not put this into a separate shell script? Yes, why not. I called it &quot;flowdebug&quot;, and it is located in the project root (where the original flow command is located). As you can see I also put the environment variables needed to start the debugging session in that script. So from now on, when I want to debug my Flow3 application, I simply use</content:encoded></item><item><title>DI container and IDE integration</title><link>https://windler.dev/blog/di-container-and-ide-integration/</link><guid isPermaLink="true">https://windler.dev/blog/di-container-and-ide-integration/</guid><description>How to get PhpStorm autocompletion for objects from a DI container without docblocks, using the PHP-DI plugin that resolves container-&gt;get() calls.</description><pubDate>Tue, 25 Oct 2016 00:00:00 GMT</pubDate><content:encoded>Say we use a DI container directly, i.e. via functions like get() or make(), how do we achieve proper IDE support? For example I create a class instance the usual way and I want to know what methods my Server class provides I could use docblocks This works fine in many IDE like PhpStorm: however the docblock is somehow annoying to me. The IDE \should\ really know what class instance the variable $server is, since everything it needs to know is in the class name constant I provided as parameter for the get() function. There might be a way using the hardly known .phpstorm.meta.php file for PhpStorm, but that one is currently some sort of under construction - at least I couldn&apos;t get it working properly. Hopefully the PhpStorm guys will extend the documentation soon! Once again, the PHP community provides the solution: the small but pretty cool PhpStorm PHP-DI plugin does exactly what we need! Now PhpStorm knows that $server is an instance of the Server class without me needing to do any further work: Class name constants should be used wherever possible nowadays, however it also works with the Fully-qualified class name as string: But really, you shouldn&apos;t do that. Please. Better just forget what I said. Forget it. Begone! Awesome! Although actually written for the PHP-DI container, it also supports container-interop and even that crapp... I mean lovely but omnipresent Laravel App Facade sort of jun... container... thing. I&apos;d recommend to use DI containers directly only in very few places like Application bootstrapping or factories. But imagine you have to deal with a legacy Laravel 4.2 application which uses that awful App::make() basically EVERYWHERE, you are happy about any help.</content:encoded></item><item><title>Display content of blob column as plain text</title><link>https://windler.dev/blog/display-content-of-blob-column-as-plain-text/</link><guid isPermaLink="true">https://windler.dev/blog/display-content-of-blob-column-as-plain-text/</guid><description>A small MySQL trick to display blob column content as plain text using CONVERT(column USING utf8) in your SELECT statements.</description><pubDate>Wed, 23 Apr 2014 00:00:00 GMT</pubDate><content:encoded>Sometimes it can be useful to have the content of MySQL blob columns displayed as plain text. There&apos;s a pretty easy way to do this: \sql\SELECT CONVERT(my\blob\column USING utf8) AS plain\text\from\blob FROM my\table; \/sql\ Yes, these little tricks you need once in a lifetime ...</content:encoded></item><item><title>Enable xdebug on demand in your local docker environment</title><link>https://windler.dev/blog/enable-xdebug-on-demand-in-your-local-docker-environment/</link><guid isPermaLink="true">https://windler.dev/blog/enable-xdebug-on-demand-in-your-local-docker-environment/</guid><description>A shell script to enable or disable Xdebug on demand in a local PHP docker environment by moving docker-php-ext-xdebug.ini in and out of the conf.d folder.</description><pubDate>Mon, 16 Mar 2020 00:00:00 GMT</pubDate><content:encoded>Xdebug is an essential tool for me when I develop PHP applications (kudos to Derick Rethans for his dedication over the many years). Yet it admittedly slows down code execution. It gets worse when you run docker on a Mac. You are screwed if you run a really complex application like Typo3 in this setup (got a bit of a dejavu here). Wouldn&apos;t it be cool then to only enable xdebug on demand in your local docker environment? For example, I was working on a Typo3 project with lots of content in up to 10 languages. Without xdebug, one huge page (the dreaded ID 6) loads in 1.2 minutes, which is already really bad. But with xdebug enabled it jumps up to 6.5 minutes! You simply can&apos;t work like that. Surely this is an extreme example, but also on smaller pages it felt really slow with xdebug enabled. I kept it enabled though because I was too lazy to always rebuild my docker container... Xdebug toggle script So what I need is an easy way to enable (and disable) xdebug in my local docker setup easily. Finally, I figured out a solution that works very well for me: https://gist.github.com/carstenwindler/b330028c41c453c905cbe0801470afd2 This little script allows you to enable or disable xdebug in seconds using your command line: to disable it and, well you probably guessed it, to enable it again. Absolutely no rocket science here. Under the hood, the script simply moves the into a directory outside of . Upon restart of the app container, PHP loads completely without xdebug. To enable it again, the file is copied back. Some things to keep in mind: It is written for the official PHP docker image on Docker Hub (using the - yet this can be adapted to your needs quickly) It expects the PHP service to be called &quot;app&quot; in . This is easily adaptable to your needs as well. I&apos;m not an experienced bash programmer, so there is surely room for improvement. I&apos;m happy about suggestions to improve it!</content:encoded></item><item><title>Entwickler Summit 2026 - Review</title><link>https://windler.dev/blog/entwickler-summit-2026-berlin-review/</link><guid isPermaLink="true">https://windler.dev/blog/entwickler-summit-2026-berlin-review/</guid><description>Review of the Entwickler Summit 2026 in Berlin: hands-on insights from the AI-focused talks.</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate><content:encoded>I had the pleasure to visit this year&apos;s Entwickler Summit 2026 in Berlin. It&apos;s held by the German-speaking, well, let&apos;s call it &quot;software developer learning platform&quot; entwickler.de (and yes, Entwickler basically means &quot;developer,&quot; so you get the idea). Consequently, most talks were in German, although many slides were in English. I am not sure if we should really focus on only the German speakers in our community, but on the other hand, it was refreshing to listen to the talks in your own language. It took place in a cinema, the Colluseum, and which is a great place for such an event. Just the wifi was lousy, and the lunch was out before I could grab some. Bummer. But who needs food when there is AI? Because not surprisingly, most of the talks and topics contained AI either partially or fully. The talks I visited went from criticism over pure pragmatism to curiosity and pure excitement. Pretty much the mixture I experience among fellow developers today. Plus maybe even some doomerism. Local LLMs Starting the day with a good mug of filter coffee served from big thermos cans (a continuous delivery pipeline that just works!) and the talk Lokale LLMs: Sind sie den Aufwand wert? (Local LLMs: Are they worth the effort?) by Rainer Hahnekamp (Soverius AI). Highlighting the benefits (sovereignty and cost control) over the drawbacks (investment), I found this talk highly entertaining, since Rainer managed to convey his content with nicely animated slides and the ability to put complex concepts (like quantization) into simple words. Great! And yes, starting with 5k to run decent LLMs locally is something most of us can&apos;t afford as individuals, but organizations should definitely do the math for themselves. As technology progresses, we can expect more capable models to run on existing hardware, hopefully, and Rainer draws the comparison to how video compression algorithms improved over time. I missed the fact that using local LLMs decouples you from the big AI datacenters, which are often pure greenhouse gas-spitting monsters. It&apos;s all been there Alistair Cockburn (where the &quot;ck&quot; in the name is silent, which is good to know; otherwise, it could be embarrassing to announce him wrongly) gave the first keynote, Simplifying Software Design: The Genius of Bureaucracies. Did you ever wonder how bureaucracy helps in software engineering? Me neither, but it all makes a lot of sense! By saying &quot;Not my job&quot; and &quot;No need to know&quot;, it helps improve your architecture in terms of separation, encapsulation, and so on ... and works extremely well with, of course, LLMs (because AI has to be in every talk, doesn&apos;t it?). Mr. Cockburn spat out the fanciest slides (I mean, look at that monster on the right!) of the whole day, often holding far too much information to even read, let alone process, before proceeding to the next. Nevertheless, a very informative talk from an absolute software engineering legend. Jobs change Markus Andrezak (überproduct) gave a talk from the Product Managers perspective: When Code Becomes Free: The Organizational Bottleneck of the AI Age. Setting the stage with comparing AI-driven development with the idea of continuous deployments back then, when people were skeptical or even repellent. And although using AI in development decreases the amount of time needed, he pointed out that code actually never was the bottleneck. Yes, we heard that before, but it&apos;s not less true. Bottlenecks now are, for example, too much code, PRs by humans, useless features being released, or the slow feedback loop, which tells us eventually if a feature is a success. Or did you know that only one out of three features being released is actually beneficial to the user? That is also why, in his opinion, the job of a PM changes: less gatekeeping, less ticket prioritization, and rather testing a feature in 5 different AI-generated versions before deciding which one to build properly. Finally, Markus stated that management decisions that are relevant for software development should be written down and stored in the repository on GitHub so that AI can take it into account when building stuff. Otherwise it&apos;s just &quot;building more rubbish in a shorter time&quot;, which is not the only time I heard that quote that day. APIs and AI Next up: APIs für die AI Nutzung: Wie geht das? (APIs for AI Use: How Does It Work?) by Erick Wilde (OpenAPI Initiative) and Thilo Frotscher, where it was pointed out that LLMs will benefit from well-documented, well-versioned APIs. So if you haven&apos;t, better document your API in some useful format like OpenAPI. Next steps in the API AI evolution could be to improve the definitions through backward-compatible changes (no customer impact), set up an entirely new API (customer impact), or, the cherry on top, add an orchestration layer, where multiple API calls are hidden behind a wrapper. Humans and AI Menschen und KI im Feedback-Loop der Softwareentwicklung (People and AI in the Feedback Loop of Software Development) from Eberhard Wolff (SWAGLab) came to a similar conclusion as Markus before - without clearer guardrails, we&apos;re just building slop faster. While AI will speed up the development loop (build, deploy, test, code), it currently won&apos;t help with getting faster customer feedback. Furthermore, companies also struggle with unclear business values, excessive planning, long times for decisions, and so on. So eventually, although Big Tech is currently firing people to finance their hunger for data centers, software development will always be a team effort. Developers are wise to become domain experts and work on their soft skills (which, as he acknowledges, can be challenging for some of us who chose computers for a reason...). We are all doomed After that somewhat uplifting talk, Dirk Specht&apos;s keynote Die Zukunft lesen - ohne sie zu verpassen (Predicting the Future—Without Missing It), was like a slap in the face. Humans are particularly bad at grasping the concept of exponential growth and thus underestimating the colossal shift we are about to experience. As an illustrative example, he showed the share of electric vehicles over the last decades, which, after going slow for many years, is now starting to grow fast. And whilst in Germany politicians – and, surprisingly, some business leaders too – are trying to cling on to their beloved internal combustion engines, even though these are already technically and economically inferior, they will soon be phased out. The same applies, in Dirk&apos;s opinion, to people who deny AI as the technology of the future. In times of disruption, it is important to not stay with &quot;boundary value optimization,&quot; e.gm trying to speed up the software delivery pipeline by a few percent rather than unlocking the full potential. Humanoid robots vs. highly specialized robots are another example here: You can still improve the machines to a certain degree, but humanoids will unlock whole new opportunities. AI might even be capable of skipping programming languages entirely and writing assembler code directly. No word on how this exponential growth can be handled from a social perspective, like, how do we compensate people who lose their jobs because of AI? And where the energy should come from, not to mention the environmental impact of building massive data centers. What the bottle-heck Code no longer is the bottleneck is a quote you probably often hear these days. I would like to refine it a bit: Shipping meaningful code is still the bottleneck Everyone can blast out lines of code like nothing these days. Shooting features at customers like a shot gun might lead to feature fatigue very soon. I think we will only learn in a few years what that approach will cost us eventually. Currently, many people even seem to be in some sort of AI psychosis, or, like Markus coined it, &quot;it&apos;s like a drug&quot;. What I missed completely among the topics that have been discussed: sustainability. The price humanity pays for AI is already very high, and I can&apos;t imagine how it will hit us if Dirk is right with the exponential growth. Yet, most professionals don&apos;t seem to care how many new gas turbines have to be built to create features that no customer will probably ever see. At least some critical thoughts about sovereignty or ethical problems, like the Huggingface hack, were discussed during the panel discussions that took place on this day, too. Of course I couldn&apos;t see all the talks, so I might have missed these thoughts elsewhere. All in all, this was a fantastic event, which left me with plenty of thoughts and inspirations. That&apos;s what makes these conferences so unique and important to me.</content:encoded></item><item><title>Expand your Windows Taskbar: Dual Monitor Taskbar</title><link>https://windler.dev/blog/expand-your-windows-taskbar-dual-monitor-taskbar/</link><guid isPermaLink="true">https://windler.dev/blog/expand-your-windows-taskbar-dual-monitor-taskbar/</guid><description>Dual Monitor Taskbar is a free Windows tool that spreads the taskbar across multiple monitors and shows windows only on the screen they belong to.</description><pubDate>Tue, 25 Mar 2014 00:00:00 GMT</pubDate><content:encoded>If you use multiple monitors with Windows, and ever wanted to have the $%#§! taskbar spread across all monitors, here&apos;s your cure: http://sourceforge.net/projects/dualmonitortb/ It can also be set up to let the Windows only appear on the taskbar of the actual screen. This is very handy. It&apos;s free, but it hasn&apos;t been updated for a while. Better get your copy now.</content:encoded></item><item><title>Fighting fear – beat your anxiety one step at a time</title><link>https://windler.dev/blog/fighting-fear-beat-your-anxiety-one-step-at-a-time/</link><guid isPermaLink="true">https://windler.dev/blog/fighting-fear-beat-your-anxiety-one-step-at-a-time/</guid><description>Self-managed exposure therapy for fear of heights: small steps, accepting the adrenaline, trusted companions, and the realization you will not die of fear.</description><pubDate>Thu, 30 Oct 2025 00:00:00 GMT</pubDate><content:encoded>Let’s talk about anxiety today. Or more precisely, the anxiety of heights. Roughly ten years ago, after a sudden panic attack that struck me out of nowhere (which is, I guess, what they always do), I became afraid of heights. It was never so bad that I couldn’t even step up a ladder, but it made it impossible to cross a grid floor bridge over a small gorge anymore or step outside on a balcony of a high building. Not to mention boarding a plane. Needless to say, this often leaves you in an uncomfortable situation. If that bridge is necessary to cross on a hike, and an alternative route will take hours, you better plan some time in advance. It made it impossible for me to fly to conferences or on business trips, too. That’s why I never applied to speak at conferences that I couldn’t reach well by train, for example. Obviously, I didn’t want to endure this for too long. In times of the climate crisis, flying is not really an option for me anyway, so that didn’t really matter to me. And surely, avoiding hikes with bridges and mountains is possible, but especially those routes in the mountains are among the most beautiful. I was missing out on activities I enjoyed the most, so I had to change something. Self-therapy Please note: I am by no means a psychologist! I just tell you my experience and what worked for me. Seeking help from professionals is no sign of weakness or anything else. Not that I had many options. Fighting my anxiety with alcohol? Getting completely smashed on a business trip or in the mountains is not really a good idea, so I skipped that. Also, I get cuddly when I’m drunk. How about therapy, you might wonder? Yeah, I considered it but wasn’t able to find sufficient information about good therapists to begin with. I read about hypnosis, but I probably watched too many bad movies about it (aka being confidently ignorant) to consider it for myself, but I would definitely be open to hearing the experiences of people who tried it. Another type of therapy I learned about in that context is called “exposure therapy“. You basically expose yourself to what causes your fears in small doses. That sounded doable, so I started treating myself. On countless hikes, I tried to get higher each time. Cross higher bridges, taller observation towers, or mountain hikes with more elevation. Sometimes, I just stood minutes in front of the obstacle but wasn’t able to overcome it. However, although every time I couldn’t make it felt like a failure, after a while there was a clear trend that it’s getting better. Little steps. The worst part here is what I would call the “fear of fear”: What will happen if I freak out in a plane, 10,000 meters above the ground, or on a narrow bridge? The wildest thoughts come through my mind. Will I try to open the aircraft door, screaming like a maniac? Will I lie down, sobbing, paralyzed in the fetal position? Or will I even get a heart attack? You can’t argue with rationality when your fear is irrational. My learnings Spoiler: You will, most certainly, not die of fear (but please don’t complain to me in case you do). Seriously, realizing that was a major point for me. Some more points that helped me: Accept that fear is nothing bad per se. It helps you avoid accidents. The adrenaline will eventually stop being produced after approximately 30 minutes. If the fear strikes, sit down, get used to it, and wait until the worst is over. Do it with people who you trust, who know about your fears, and who are not too mad (but mad enough to make it an issue) if they have to abort the climb. By the way, if you are one of the people who accompany someone with a fear of heights, comments like “But it’s not that high” will not help. No, they won’t. Avoid additional stress triggers, like heat, noise, overly crowded paths, etc. Sleep hygiene: I think my panic attack was also caused by sleep deprivation. For many years I did not sleep much longer than 5-6 hours, which is definitely not healthy. Next try Equipped with a solid experience of enduring fear and some sense of achievement, I was visiting a southern part of Germany. The town of Garmisch-Partenkirchen is close to Germany’s highest peak, the Zugspitze (approx. 2900 m). Just stepping out of the train and seeing the massive mountainside with my own eyes for the first time was absolutely stunning. What a beauty! Surely, climbing it was not an option. There is another mountain nearby, though: the Wank (yes, I know, but that’s what it is called). With its 1780 m, it rises about 1000 m above the town. It sounded doable, and it didn’t look that high from the ground, so I was willing to give it a try. The climb itself was nice. Basically 1000 m uphill, which took me roughly 3 1/2 hours with some breaks. If 1000 m doesn’t sound that high to you, I like to compare it with walking up the stairs to the top of one of those ridiculously high skyscrapers, like the Burj Khalifa. Just to give you an idea of what it does to my brain, and where the anxiety comes from. As I was already used to a bit of height, the first few hundred meters were no problem. Around 600 m above the ground, it started getting interesting – I felt the fear slowly creeping in. Oh gosh, not again. I kept going, mostly focusing on the next few steps before me, repeating the above learnings in my mind. Also, I didn’t constantly check my maps app to see at what elevation I had already reached, as I would usually do. I just kept going, but I made enough breaks to get used to the situation and let the adrenaline go away. Going further up, I realized that, above a certain altitude, it doesn’t really make any difference whether you are, e.g., at 500 m or 800 m. I guess it’s a matter of perspective; the feeling of height didn’t get worse. That was a nice surprise! Eventually, I reached the cable car station on the summit. The soup I enjoyed as treatment never tasted better. As a plus, I even dared to take the cable car downhill again – something I’ve also not done for over a decade! Down on the ground I’m writing this down since this trip was a huge success for me – another important milestone in fighting my anxiety. There were a few places where it went really deep, and I was scared. Yet, in hindsight, I think I was more afraid of getting another panic attack than actually having a real fear of heights (which is also called “anticipatory anxiety,” as I later learned). I hope I can conserve this thought for the next tour. I don’t consider myself to be “healed” at this point, as some situations are still difficult. But I am confident that I would be able to board a plane again in the near future; I’m not sure if I want that, though, for the reason mentioned above. A far-fetched milestone would be climbing up the dreaded Zugspitze. Nothing that can be done within the next few years, though, but it’s something to aim for! Hopefully, this little story can encourage others who suffer from the same problem to keep trying. If I can do it, you can do it too.</content:encoded></item><item><title>File uploads not working with PhantomJS</title><link>https://windler.dev/blog/file-uploads-not-working-with-phantomjs/</link><guid isPermaLink="true">https://windler.dev/blog/file-uploads-not-working-with-phantomjs/</guid><description>Two PhantomJS workarounds for file upload acceptance tests: make hidden file inputs visible via JS, and remove the multiple attribute before attaching the file.</description><pubDate>Mon, 10 Apr 2017 00:00:00 GMT</pubDate><content:encoded>Just a quick one today: when you struggle with writing Acceptance Tests for file uploads using PhantomJS (will version 2.5 ever come out? \sigh\), here are two possible solutions for you. File inputs are ugly, let&apos;s just not show them The first issue might be that the input field is hidden for obvious reasons. Luckily we can solve this issue without making your designer cry (and we don&apos;t want to do this, don&apos;t we?) by just tweaking the CSS using JavaScript. In my case, the input field was hidden by using a very low opacity value, so I set it to 1 just before attaching the actual file: If this solves your problem - great! If not, I got one more. Don&apos;t rush - one at a time While the first issue is somewhat understandable ... well, maybe ..., anyway, I found the second one just by good old trial-and-error: PhantomJS doesn&apos;t like multiple uploads! Now we don&apos;t want to remove the possibility to upload multiple files just to please PhantomJS, so let&apos;s do another tweak: Of course we can&apos;t test multiple uploads that way, which is a bit sad, but right now I&apos;m afraid we have to live with that. Did it blend? If you found these two little tips helpful, or if you have another nasty PhantomJS workaround at hand, please drop a comment below!</content:encoded></item><item><title>Filesystem abstraction in PHP, and why it sometimes is useful!</title><link>https://windler.dev/blog/filesystem-abstraction-in-php-and-why-it-sometimes-is-useful/</link><guid isPermaLink="true">https://windler.dev/blog/filesystem-abstraction-in-php-and-why-it-sometimes-is-useful/</guid><description>Flysystem filesystem abstraction in PHP makes FTP downloads and local storage unit-testable, swapping adapters instead of touching real filesystems in tests.</description><pubDate>Mon, 23 Nov 2015 00:00:00 GMT</pubDate><content:encoded>Phase 1: Ignorance and Bias Recently I came across Flysystem, which is a Filesystem abstraction layer for PHP. Now if you haven&apos;t worked with a Filesystem abstraction layer before (like me), you may ask yourself: Why on earth should I add even more overhead for something basic as the file system? Let me explain why it will be extremely useful. Say we have to build a small app in PHP which should download files from an FTP server, process them in some way, and store the result on the servers filesystem. No doubt, this can be done with PHPs build-in functions without a problem, you might say. Sure, but don&apos;t forget the Unit Tes... dang! See? Phase 2: Skepticism and Curiosity The solution for our problem once more is: Abstraction. Abstract the process from any file system. Just use the same set of operations on some sort of adapter, no matter where or how the files are stored, and let the Abstraction Layer do the rest. You guessed it already, this is where Flysystem comes into play! Let&apos;s start with a simple file download: Is that it?? Aww yeah, that&apos;s it. When it&apos;s with Flysystem, we only need a few lines of code, because it&apos;s so intense! To make the code it more clear, I called the filesystems $localFileSystem and $remoteFileSystem, but of course both filesystems could be remote ones, e.g. FTP and Amazon S3. This means that by using Flysystem, you completely decouple your code from the filesystem, so you&apos;re prepared when the Business suddenly decides to &quot;implement some totally easy changes&quot;. Of course our example is not 100%ly done, since we still have to create the Filesystem adapters we pass upon instantiation. But that&apos;s ok, we need to do the configuration somewhere anyway. Below function is part of another class, which makes use of our Downloader class: This is what I also like about using Flysystem: within the Downloader class we don&apos;t have to deal with any path settings or such. It is completely done within the code which instantiates the Downloader, i.e. in the domain where it belongs. Phase 3: Awesomeness and Why-didn&apos;t-I-use-it-before-ness I assume most of you didn&apos;t even read until here, since you&apos;ve been totally blown away and immediately started refactoring your code, giggling slightly insane. But wait, we&apos;re not even fully through yet. Remember the question about Unit Tests? With Flysystem, it&apos;s a breeze: Flysystem even provides an adapter for vfsStream, a stream wrapper for PHP which helps greatly when you have to test filesystem-related functionality. In simple terms, it simulates a file system in memory, which many (but not all) PHP functions can use. Check it out here if you don&apos;t know it yet: vfsStream on Github So here we are: we just wrote a test for the FTP download in 5 minutes - without having to change a single line in the Downloader, without relying on a real FTP server. We could exchange the remote filesystem with Dropbox or even your Grandma&apos;s closet within two minutes. Awesome. Now get a coffee and head over to your co-worker, who&apos;s still struggling with the Downloader class and PHPs lovely native FTP support.</content:encoded></item><item><title>Frameworkless-Article released in PHP magazin</title><link>https://windler.dev/blog/frameworkless-article-released/</link><guid isPermaLink="true">https://windler.dev/blog/frameworkless-article-released/</guid><description>My first article in PHP Magazin explores frameworkless PHP development, weighing pros and cons of frameworks and building maintainable apps without them.</description><pubDate>Sat, 04 Sep 2021 00:00:00 GMT</pubDate><content:encoded>I&apos;m delighted to share that I published my very first article &quot;Frameworkless - Weniger ist manchmal mehr&quot; (Frameworkless - Sometimes less is more) in the August/September digital issue of the renowned German &quot;PHP Magazin&quot;! It&apos;s based on my previous talk &quot;Frameworkless&quot; which I gave at the International PHP Conference earlier this year. It really makes me happy to see my own words in a magazine which I was reading myself for many years. It played an important role in my career as a developer. Over the past 15 years, I saw projects struggling because of the underlying frameworks. That&apos;s why, in this article, I&apos;ll explain my view on the pros and cons of frameworks. I show how to utilize the PHP ecosystem to create modern, maintainable applications without them. The code samples can be found in my frameworkless Github repository.</content:encoded></item><item><title>Free! JavaScript! Literature!</title><link>https://windler.dev/blog/free-javascript-literature/</link><guid isPermaLink="true">https://windler.dev/blog/free-javascript-literature/</guid><description>The You Don&apos;t Know JS book series is available to read for free on GitHub, with paid e-book and print versions for those who prefer to support the author.</description><pubDate>Sun, 17 Aug 2014 00:00:00 GMT</pubDate><content:encoded>Back in the days, one of my profs at the University always had some cool quotes at hand. One of his favourites was &quot;There is no such thing as a free lunch&quot;. While I basically agree (at least what food is concerned), you often find free gems in the internet, like a series of JavaScript related books: https://github.com/getify/You-Dont-Know-JS They are available for free on github, however the author also sells them as e-book or even printed versions. I&apos;m not sure if I would pay $17 for a 98 pages e-book which I can read for free, though... that sounds a bit too expensive in my opinion.</content:encoded></item><item><title>Getting dead pages from Google Cache</title><link>https://windler.dev/blog/getting-dead-pages-from-google-cache/</link><guid isPermaLink="true">https://windler.dev/blog/getting-dead-pages-from-google-cache/</guid><description>Recover dead or temporarily unavailable pages by fetching a cached copy from Google using the cache: prefix in front of the URL in your search.</description><pubDate>Sun, 18 Oct 2015 00:00:00 GMT</pubDate><content:encoded>It happens from time to time that URLs don&apos;t work, be it temporarily or permanently, for whatever reason. Since Google soaks up the internet like a sponge, you can try to fetch a copy from the Google Cache by putting &quot;cache:&quot; in front of the URL and search for it: Try it out!</content:encoded></item><item><title>Getting the subclass name in the parent class</title><link>https://windler.dev/blog/getting-the-subclass-name-in-the-parent-class/</link><guid isPermaLink="true">https://windler.dev/blog/getting-the-subclass-name-in-the-parent-class/</guid><description>In PHP, get_class($this) inside a parent class method returns the subclass name, while __CLASS__ and get_class() return the parent class.</description><pubDate>Wed, 14 Aug 2013 00:00:00 GMT</pubDate><content:encoded>A mistake that I keep making - I have a class that extends another class, and I need to know the class name of that subclass. However the function where I need the name is in the parent class. In this case the magic constant \\CLASS\\ won&apos;t work, as it will return the name of the class where it is found. get\class()_ won&apos;t work, too. Not without an important difference: This will result in The first function call returns the (in my case) incorrect name of the parent class, while the 2nd function works as I need it.</content:encoded></item><item><title>Green PHP - Nachhaltigere Software mit PHP</title><link>https://windler.dev/blog/green-php-nachhaltigere-software-mit-php/</link><guid isPermaLink="true">https://windler.dev/blog/green-php-nachhaltigere-software-mit-php/</guid><description>Two-part article in PHP Magazin on sustainable software with PHP: performance optimization first, then carbon-aware software and the power grid.</description><pubDate>Fri, 04 Aug 2023 00:00:00 GMT</pubDate><content:encoded>My two-part article, &quot;Sustainable Software with PHP&quot; (&quot;Nachhaltigere Software mit PHP&quot;) was recently published in the German PHP Magazin. Optimising the performance of PHP applications not only reduces carbon emissions, but often also saves money - be it through reduced use of cloud services or increased customer satisfaction. That&apos;s why I&apos;m focusing on performance issues in the first part. The second part takes a more in-depth look at other ways to reduce the emissions caused by our software, such as incorporating information from the power grid, aka carbon-aware software. Part 1: https://entwickler.de/php/performance-optimieren-green-php ?? Part 2: https://entwickler.de/php/zeit-zum-umdenken ??</content:encoded></item><item><title>Helpful MySQL shell tricks</title><link>https://windler.dev/blog/helpful-mysql-shell-tricks/</link><guid isPermaLink="true">https://windler.dev/blog/helpful-mysql-shell-tricks/</guid><description>Helpful MySQL shell tricks: pipe mysqldump straight into gzip to compress on the fly, and stream a dump from one server directly to another over ssh.</description><pubDate>Wed, 18 Sep 2013 00:00:00 GMT</pubDate><content:encoded>Although I&apos;m Windows user most of the time, I have to take care of some projects on Linux boxes, so it&apos;s good to have at least a little knowledge of what you&apos;re doing there. The pipe really is a helpful little tool, which allows to do a mysqldump and directly gzip the result: This surely saves some time during late night deploys! You can even do a mysqldump from one server to another:</content:encoded></item><item><title>Hofstadter&apos;s Law</title><link>https://windler.dev/blog/hofstadters-law/</link><guid isPermaLink="true">https://windler.dev/blog/hofstadters-law/</guid><description>Hofstadter&apos;s Law: it always takes longer than you expect, even when you take it into account. Required reading for IT project managers.</description><pubDate>Tue, 26 May 2015 00:00:00 GMT</pubDate><content:encoded>Heh. Never heard of that Hofstadter guy before. However I immediately liked Hofstadter&apos;s law: It always takes longer than you expect, even when you take into account Hofstadter’s Law. So much wisdom in only a few words! It should be printed on a T-Shirt, or a Poster, or be the first chapter of every &quot;IT Project Management in 10 easy lessons&quot; handbook.</content:encoded></item><item><title>How to check if a class constant exists?</title><link>https://windler.dev/blog/how-to-check-if-a-class-constant-exists/</link><guid isPermaLink="true">https://windler.dev/blog/how-to-check-if-a-class-constant-exists/</guid><description>A quick PHP tip to check whether a class constant exists by using defined() with the Class::CONSTANT notation instead of reflection or property_exists.</description><pubDate>Sun, 05 Jan 2014 00:00:00 GMT</pubDate><content:encoded>Sometimes it&apos;s useful to know whether a certain class constant exists or not. This is a very quick and painless way to find that out:</content:encoded></item><item><title>http-helper and config packages reached stable state</title><link>https://windler.dev/blog/http-helper-and-config-packages-reached-stable-state/</link><guid isPermaLink="true">https://windler.dev/blog/http-helper-and-config-packages-reached-stable-state/</guid><description>Two PHP composer packages, http-helper for debugging HTTP requests and config for simple configuration handling, have reached stable state and are ready to use.</description><pubDate>Sun, 16 Sep 2018 00:00:00 GMT</pubDate><content:encoded>http-helper and config, two recent PHP composer packages of mine, have just reached stable state a few days ago. http-helper is there to help you debugging http requests and responses. It is purely for development purposes and served me well already in the past few months, so I published it as a package, hopefully being helpful for others as well. config (I really suck at naming things) is a quite simple but handy configuration service. It too already proven helpful to me, so maybe you might want to have a look if you are searching for some easy configuration handling.</content:encoded></item><item><title>Fixing Locale issues on Debian</title><link>https://windler.dev/blog/if-you-cant-set-your-locale-right/</link><guid isPermaLink="true">https://windler.dev/blog/if-you-cant-set-your-locale-right/</guid><description>Fix missing locale errors on Debian when PHP setlocale() returns false by running dpkg-reconfigure locales, then restart your webserver.</description><pubDate>Tue, 26 May 2015 00:00:00 GMT</pubDate><content:encoded>Business as usual. New feature developed, tested, packed and ready to go. Let me just deploy it to production, smoke test aaaand .... damn! What happened to the currency symbols!? In my particular case, PHP&apos;s setlocale() returned false - so obviously those darned locales stroke again. SearchEngineOfYourChoice(TM) to the rescue! Luckily even I was ably to fix this problem quickly without needing to contact the Admins (who wouldn&apos;t have been in the office anyway): Aha! It was missing almost all locales. However adding them is quite easy: The dialog that appears after running this command shouldn&apos;t be a problem at all, so I don&apos;t mention it further here. Just select the locales you need there and go for it. Afterwards check the results by again doing That&apos;s already it. Don&apos;t forget to restart your webserver!</content:encoded></item><item><title>New articles about Green IT</title><link>https://windler.dev/blog/index/</link><guid isPermaLink="true">https://windler.dev/blog/index/</guid><description>New articles on sustainable software engineering in German magazines, plus a PHP expert check, all about Green IT and coding against climate change.</description><pubDate>Wed, 02 Mar 2022 00:00:00 GMT</pubDate><content:encoded>Recently, I released two articles about Sustainable Software Engineering: &quot;Green IT - nachhaltig Software entwickeln&quot; (Green IT - develop software sustainably) is featured in the print issue 3/2022 of the German &quot;windows .developer&quot; magazine. You can read the article online on entwickler.de. Another similar article &quot;Coden gegen den Klimawandel&quot; (Coding against climate change) is available on the German online magazin &quot;informatik-aktuell&quot;. Both articles cover the same topic as my recent talk &quot;Coding against climate change&quot; which I held at the International PHP Conference Munich 2021. Finally, I participated in the &quot;PHP expert check&quot; which was done by the German &quot;php magazin&quot; and can be read online on the pages of the International PHP Conference as well. More is here to come :-)</content:encoded></item><item><title>International PHP Conference 2021 - Frameworkless</title><link>https://windler.dev/blog/international-php-conference-2021-frameworkless/</link><guid isPermaLink="true">https://windler.dev/blog/international-php-conference-2021-frameworkless/</guid><description>First talk at the International PHP Conference 2021 on building PHP applications without a framework, including mild criticism of Laravel and the online format.</description><pubDate>Fri, 11 Jun 2021 00:00:00 GMT</pubDate><content:encoded>I&apos;m really proud to announce that in June 2021 I had my first talk, Frameworkless, on the International PHP Conference. Although it still being an Online Conference, I was finally able to check this off my bucket list. Let&apos;s face it - an Online Conference is only half as cool. I would have loved to discuss the topic of writing PHP applications without using a framework after the talk in more detail. Especially my mild criticism on Laravel, the biggest PHP Framework out there, is surely worth a discussion :-) Plus, it still feels weird to talk to the camera instead of a crowd, since I was getting no visual feedback at all during my talk. Anyways, the Conference Team made the best out of the current situation. I&apos;m looking forward to seeing you people &quot;in real&quot; again soon on one of the next International PHP Conferences!</content:encoded></item><item><title>International PHP Conference Munich 2021</title><link>https://windler.dev/blog/international-php-conference-munich-2021/</link><guid isPermaLink="true">https://windler.dev/blog/international-php-conference-munich-2021/</guid><description>Two talks at IPC Munich 2021: the keynote &quot;Coding against climate change&quot; and an extended &quot;Reduce boilerplate code with PHP 8&quot; live coding session.</description><pubDate>Thu, 02 Dec 2021 00:00:00 GMT</pubDate><content:encoded>In October this year, I gave two talks at the International PHP Conference in Munich. I&apos;m pleased that my talk &quot;Coding against climate change&quot; was picked as the keynote on Wednesday. This is a very important topic for me, and according to the positive feedback, I&apos;m not alone with this. The recording is also available on Youtube. My other talk, &quot;Reduce boilerplate code with PHP 8&quot;, was an extended version of my blog post Reduce boilerplate code with PHP 8, spiced up with a short live coding session. It was the first time I did that, luckily it went well :-) It was a lot of fun to attend a real conference and interact with the other people there. A big “thank you” to the great crew of S&amp;S Media, who did a fantastic job. Hopefully, we&apos;ll see each other at the IPC in Berlin next year! https://www.youtube.com/watch?v=aAdGNw2JMZw</content:encoded></item><item><title>the_coding_love();</title><link>https://windler.dev/blog/issettheresti/the-coding-love/</link><guid isPermaLink="true">https://windler.dev/blog/issettheresti/the-coding-love/</guid><description>A short nod to thecodinglove.com, the geek humor site with GIFs that only developers will truly understand and laugh-cry over.</description><pubDate>Sun, 06 Jul 2014 00:00:00 GMT</pubDate><content:encoded>You cried with laughing, and others go like ... then welcome to Geek humor. Welcome to the\coding\love();</content:encoded></item><item><title>Keynote on the DATEV Coding Festival 2023</title><link>https://windler.dev/blog/keynote-on-datev-coding-festival-2023/</link><guid isPermaLink="true">https://windler.dev/blog/keynote-on-datev-coding-festival-2023/</guid><description>Remote keynote at the DATEV Coding Festival 2023 on why Green IT matters now, arguing the big picture makes sustainability urgent for a major software provider.</description><pubDate>Sun, 16 Jul 2023 00:00:00 GMT</pubDate><content:encoded>It&apos;s an honor for me to got invited as Keynote speaker on the DATEV Coding Festival 2023. The DATEV eG is the third-largest provider of business software in Germany and one of the largest European IT service providers. I&apos;m thrilled that such a big player in the market decided to push Green IT and dedicate a whole Coding Festival to that topic! In my remote talk, &quot;It&apos;s all about the big picture - why Green IT is so important now&quot;, I emphasized why this is urgently needed.</content:encoded></item><item><title>Local composer package development</title><link>https://windler.dev/blog/local-composer-package-development/</link><guid isPermaLink="true">https://windler.dev/blog/local-composer-package-development/</guid><description>Composer path repositories let you develop a local package in a sibling folder and symlink it into your project vendor directory, so changes apply immediately.</description><pubDate>Tue, 29 Sep 2015 00:00:00 GMT</pubDate><content:encoded>A new feature on composer which I really appreciate is the &quot;Path&quot; repository type. Imagine you are working on your super-cool-project, and one task requires new functionality where there is no composer package existing yet - yeah, this probably is a bit hard to imagine. Now you want to create your own super-awesome-package, because we all like it nice and separated and such. So far, I would have developed the super-awesome-package directly inside the vendor folder of my super-cool-project - which somehow did not feel right. Obviously others felt the same, so now we can use the &quot;path&quot; resource type for packages which you develop right at the moment! Instead of using VCS as package source, you simply specify the directory (relative or absolute path both work) where your super-cool-package is located on your machine. In my case, I just refer to the shoppingcart folder, where the package is currently developed. Composer will then add a symlink in the vendor folder upon running composer update, so all your changes on that package can immediately be used in your super-cool-project. Now that&apos;s what I call convenient!</content:encoded></item><item><title>Microformats - control your Google search result snippet</title><link>https://windler.dev/blog/microformats-control-what-google-shows-on-the-search-results-page/</link><guid isPermaLink="true">https://windler.dev/blog/microformats-control-what-google-shows-on-the-search-results-page/</guid><description>Microformats let you influence what Google shows on the search results page, giving backend developers a reason to care about SEO beyond the usual meta tags.</description><pubDate>Tue, 06 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Yesterday I learned about &quot;Microformats&quot;. Microwhat? Sounds suspicious! Well, at least that was my reaction. I&apos;ve to admit that I don&apos;t care much about SEO and Google and so on (I&apos;m a PHP backend developer, Goddamit!), but this is really interesting topic one should at least have heard of. In short, it allows you to have influence on what is displayed on the Google results page. Worth its weight in Gold, I guess. Some of the ancients amongst us might remember the good old Metatags. It&apos;s not the same, though. So here&apos;s a link that explains Microformats pretty well: http://www.dotcult.com/seo-guide-to-microformats</content:encoded></item><item><title>Microsoft drops support for ancient IE versions (finally)</title><link>https://windler.dev/blog/microsoft-drops-support-for-ancient-ie-versions-finally/</link><guid isPermaLink="true">https://windler.dev/blog/microsoft-drops-support-for-ancient-ie-versions-finally/</guid><description>Microsoft finally drops support for ancient Internet Explorer versions, leaving only IE 11 on Windows 7 and IE 9 on Vista, to the relief of web workers.</description><pubDate>Fri, 15 Aug 2014 00:00:00 GMT</pubDate><content:encoded>I was very pleased, happy, yes - almost euphoric when I read that Microsoft plans to drop support for older IE versions: http://blogs.msdn.com/b/ie/archive/2014/08/07/stay-up-to-date-with-internet-explorer.aspx While Windows Vista users will still get support for IE 9 (are there any Vista users out there anyway?), on Windows 7 only IE 11 will be supported. Aren&apos;t that good news? After wasting billions of hours of webworkers precious livetime all over the world, Microsoft finally understood. A bit. I guess.</content:encoded></item><item><title>Mocking magic methods with PHPUnit</title><link>https://windler.dev/blog/mocking-magic-methods-with-phpunit/</link><guid isPermaLink="true">https://windler.dev/blog/mocking-magic-methods-with-phpunit/</guid><description>Mocking magic methods with PHPUnit works best via setMethods() or addMethods(), since PHPUnit forces you to mock __call() rather than the dynamic method name.</description><pubDate>Tue, 07 Apr 2015 00:00:00 GMT</pubDate><content:encoded>Updated: as pointed out in the comments below, using setMethods() or, since this function is deprecated lately, addMethods(), is the much better way for the mocking of magic methods with PHPUnit! Original post: If you want to test a method of an object which is supplied using the magic method \\call(), you can&apos;t simply mock the desired method. You have to go the longer way via \\call(). So e.g. if your magic method you want to mock is called &quot;myMagicFunction&quot;, you could be tempted to write since, after all, it is a mock, right? So why wasting time? Obviously PHPUnit (Version 4.5.0 at the time of writing) is doing some sort of internal checks, preventing our laziness and forcing us to mock the \\call() method instead. I can only guess the reason here, any comments with more insight on this topic are highly appreciated! Of course, mocking the \\call() method instead is not much more work However PHPUnit will not throw any Exceptions if you use the first approach, instead it will only return NULL instead the expected &apos;myResult&apos;. This can be a bit frustrating :-)</content:encoded></item><item><title>Modern PHP</title><link>https://windler.dev/blog/modern-php/</link><guid isPermaLink="true">https://windler.dev/blog/modern-php/</guid><description>Book recommendation: Modern PHP by Josh Lockart (O&apos;Reilly) covers best practices and modern tools in 270 pages, ideal for confirming you are up to date.</description><pubDate>Wed, 30 Mar 2016 00:00:00 GMT</pubDate><content:encoded>Not many useful PHP books have been published recently (or I haven&apos;t yet discovered them), so I really want to recommend &quot;Modern PHP&quot; by Josh Lockart, another quality product by O&apos;Reilly. Having only 270 pages, it&apos;s easy and quick to read, and includes a lot of best practices, tips and state-of-the-art tools for writing cool PHP applications. Some topics are covered a bit briefly like e.g. Testing, but the book points you towards the right direction and gives you useful references to read further, if you are interested. The experienced PHP developer should actually be familiar with most of the topics, so you would probably not learn too much new stuff. Still it gives the good feeling of confirming that you are somewhat up-to-date :-) I&apos;m not payed for this at all, however I think that this book is really valuable for the PHP community and therefor I&apos;d like to promote it.</content:encoded></item><item><title>Multiple test databases in Bitbucket Pipelines</title><link>https://windler.dev/blog/multiple-test-databases-in-bitbucket-pipelines/</link><guid isPermaLink="true">https://windler.dev/blog/multiple-test-databases-in-bitbucket-pipelines/</guid><description>How to run functional tests needing multiple databases on Bitbucket Pipelines by granting broad permissions to the test user during the build.</description><pubDate>Tue, 24 Mar 2020 00:00:00 GMT</pubDate><content:encoded>With Bitbucket Pipelines you can ramp up Continuous Integration for your project quite fast. At least for the usual setup. But if you need multiple databases on bitbucket pipelines for your tests, you have to be creative. Why would you need to have multiple test databases on bitbucket pipelines in the first place? Well, in my case I wanted to write functional tests for Typo3. &quot;Shouldn&apos;t be too hard&quot;, I thought, until I found out that the testing framework requires the possibility to create a database for each functional test class (yes, for each class). I found out that this is not possible on Bitbucket. One MySQL service, one database. Now surely you could add more MySQL services, but it would lead to configuration hell (e.g. one port for each), and you would run out of services very soon since the amount of services is limited. Even worse, you can&apos;t configure the testing framework to use different ports per test class, so why bother at all :-) Ok, so how about out using multiple databases on one MySQL service? This would require managing the permissions on a database level, which is also not possible with the existing configuration options. There seems to be no way to use the docker-entrypoint-initdb, or to just drop a command in the service definition like you would do with docker-compose. The only option I found was to drop a GRANT statement during build times to change the permissions. Here is how it looks: The most important part here is the command. We simply grant all permissions to all users on all databases - this service is only used during build time for our CI, so no security risk here. Wait, wait - just to go sure: you wouldn&apos;t do this on production, would you? Alright, great. Also worth noting is the . The Docker Hub PHP image doesn’t have the mysql client installed. I&apos;m using MariaDB here since I couldn’t find a MySQL package for this distribution. Conclusion The testing framework now can generate as many databases as it wants, and still we only use on MySQL service. No further configuration needed if we add more test cases. Sweet.</content:encoded></item><item><title>My talk on PHP Developer Day 2023</title><link>https://windler.dev/blog/my-talk-on-php-developer-day-2023/</link><guid isPermaLink="true">https://windler.dev/blog/my-talk-on-php-developer-day-2023/</guid><description>Talk &quot;Speed up your code for the planet&quot; at PHP Developer Day 2023 in Dresden, showing how optimizing PHP code reduces carbon emissions and energy use.</description><pubDate>Sun, 24 Sep 2023 00:00:00 GMT</pubDate><content:encoded>What a great day - on the 22nd of September 2023, I spoke on the PHP Developer Day 2023 in Dresden, Germany. My talk, &quot;Speed up your code for the planet&quot;, where I showed how to reduce emissions by optimizing PHP code, received quite some positive feedback. The event was organized by the PHP Usergroup Dresden e.V., which did a flawless job. A big shoutout to the team! More infos on the talk can be found here.</content:encoded></item><item><title>Neor Profile SQL</title><link>https://windler.dev/blog/neor-profile-sql/</link><guid isPermaLink="true">https://windler.dev/blog/neor-profile-sql/</guid><description>Neor Profile SQL is a free SQL profiler for Windows, Mac, and Linux that runs as a proxy between your application and MySQL on port 4040.</description><pubDate>Wed, 21 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Recently I discovered a free and easy to use SQL Profiler for Windows, Mac and Linux: www.profilesql.com It works as proxy between the Application and MySQL itself, so basically all you need to do is configuring your Application to use it by simply adding the port number 4040 to the host (and configure the Proxy to connect to MySQL, of course). As inherent to the functional principle of a Proxy, the Profiler has to be running - so don&apos;t forget to remove the port from the host when you don&apos;t need it.</content:encoded></item><item><title>New Green IT articles published</title><link>https://windler.dev/blog/new-green-it-articles-published/</link><guid isPermaLink="true">https://windler.dev/blog/new-green-it-articles-published/</guid><description>Two new articles on the Plan A Academy cover how Green IT reduces company emissions and how sustainable software engineering decarbonises IT and cloud.</description><pubDate>Sun, 18 May 2025 00:00:00 GMT</pubDate><content:encoded>Already some month earlier this year, two new articles of mine have been published on the Plan A Academy, the public sustainability knowledge base of my employer, Plan A. How can green IT be leveraged to reduce your company’s emissions?: Learn how Green IT can help your company to reduce emissions Decarbonise your IT with sustainable software engineering: Focusing on Software Development and Cloud computing, this article gives in depths advice on how to cut the carbon emissions from your software – and save money! Find out more about my published articles on the Articles page.</content:encoded></item><item><title>New LinkedIn Learning Courses</title><link>https://windler.dev/blog/new-linkedin-learning-courses/</link><guid isPermaLink="true">https://windler.dev/blog/new-linkedin-learning-courses/</guid><description>Two LinkedIn Learning courses in German: improving PHP code quality with maintainable code tips, and Green Coding basics for more sustainable software.</description><pubDate>Mon, 23 Sep 2024 00:00:00 GMT</pubDate><content:encoded>Although they are already online for a bit, I never announced it: I now have two online courses available on LinkedIn Learning! Both are available in German only so far: Improve code quality in PHP - tips &amp; tricks on how to write maintainable PHP code Green Coding - Basics - Learn how to write more sustainable software More information can be found on the Courses page of my website.</content:encoded></item><item><title>npm &amp; Windows</title><link>https://windler.dev/blog/npm-windows/</link><guid isPermaLink="true">https://windler.dev/blog/npm-windows/</guid><description>npm on Windows fails with EPERM errors when deeply nested node_modules exceed the 260-character path limit. Upgrading to npm 3 with flat dependencies fixes it.</description><pubDate>Thu, 12 Nov 2015 00:00:00 GMT</pubDate><content:encoded>Again, Windows can cause problems you would not have expected. In npm versions prior to 3, npm stores dependencies in deeply nested folder structures, causing errors on running &apos;npm install&apos; such as Obviously, this is a ridiculously long path and exceeds 260 characters - and Windows can&apos;t handle that. Not sure why &quot;they&quot; (you know ... MS...) came up with that idea, and why this is still not fixed in a modern OS like Windows 7 (I did not try versions above that). I guess it is just the pure essence of evil, the same diabolic power which brought the Internet Explorer amongst us. Let them burn, let them suffer, and let even pay money for it! Even when you run npm on Linux in a VM on Windows with a Shared folder, you will still suffer from that. Oh, you beasts from the abyss, how ... ok I&apos;ll stop. Luckily, npm3 supports flat dependencies, i.e. all dependencies are written into the top level of the node\modules folder. So if you run into the above problem, try If this still says 2.x, consider updating to npm3: Delete your node\modules folder (not sure if this is really needed, but better go sure), then run and all dependencies get installed without errors. Yay! If you dare, you can have a look into the node\_modules folder now. You&apos;ll find loads of folders - the beauty of flat dependencies.</content:encoded></item><item><title>Of Typo3, Site Crawlers and Compression</title><link>https://windler.dev/blog/of-typo3-site-crawlers-and-compression/</link><guid isPermaLink="true">https://windler.dev/blog/of-typo3-site-crawlers-and-compression/</guid><description>TYPO3 sitecrawler omits Accept-Encoding, so cached pages reference non-gzipped CSS/JS. Two RewriteRules redirect cached requests to the gzip files.</description><pubDate>Tue, 10 Feb 2015 00:00:00 GMT</pubDate><content:encoded>A Typo3-Installation I currently maintain uses the sitecrawler extension to heat up the page cache every morning before the users are visiting our site. We encountered the problem that all pages that were cached didn&apos;t use gzipped CSS &amp; JavaScript-Files, only the non gzipped versions. Typo3 first generates both the gzipped and non-gzipped versions of the CSS &amp; JS files, and then checks the HTTP\ACCEPT\ENCODING setting whether gzip is supported and decides which of both versions is referenced in the HTML. Since the Crawler is not sending the HTTP\ACCEPT\ENCODING flag when crawling the pages, Typo3 thus renders the Page HTML referencing the non-gzipped files. I tried to add the “Accept Encoding” to the crawlers requestUrl()-Function, but of course Typo3 now returned the HTML as gzip, which totally broke the crawlers logic … Since as said Typo3 generates both versions of the files, eventually we came up with these two redirects: In case the page is cached without referencing to the gzipped versions (which is the default state every morning), we just redirect all request to the gzipped versions.</content:encoded></item><item><title>ownCloud sync client 1.4.0 released</title><link>https://windler.dev/blog/owncloud-sync-client-1-4-0-released/</link><guid isPermaLink="true">https://windler.dev/blog/owncloud-sync-client-1-4-0-released/</guid><description>ownCloud sync client 1.4.0 is released, finally adding a progress bar that shows the file in transfer and its upload progress, useful for large files.</description><pubDate>Wed, 04 Sep 2013 00:00:00 GMT</pubDate><content:encoded>Release 1.4.0 of ownCloud&apos;s sync clients finally introduce a feature I really missed, especially during transfers of large files: it now has a progress bar, which shows you the file in transfer and it&apos;s upload progress. Thanks to the ownCloud community for the brilliant work!</content:encoded></item><item><title>PhantomJS is discontinued</title><link>https://windler.dev/blog/phantomjs-is-discontinued/</link><guid isPermaLink="true">https://windler.dev/blog/phantomjs-is-discontinued/</guid><description>PhantomJS is discontinued after maintainer Vitaly Slobodin steps down, with Headless Chrome in Chrome 59 becoming the new standard for headless testing.</description><pubDate>Sun, 18 Jun 2017 00:00:00 GMT</pubDate><content:encoded>The waiting for PhantomJS 2.5 seems to have come to an end - unfortunately, it will most likely never be released. According to a statement of Vitaly Slobodin, the current maintainer of PhantomJS, the further development has been stopped. This is particular sad as version 2.5 beta has been released already and a lot of effort has been put into this release. But why? As reason, Vitaly states the release of Headless Chrome with Google Chrome 59. Fair enough, a few developers can&apos;t compete with Google at all. As a matter of fact, PhantomJS was pretty unique for quite some time. An amazing project which established headless browser testing on wide areas, so it has been a fundamental contribution to the testing world. I think the actual, long anticipated release of Headless Chrome was just the final the straw that broke the camels back. Since the infamous ticket 546953 it was totally clear that it was worked on it, also conference talks of the developers talking about the technical background came up, so it was just a matter of time since it would show up. It was not really a surprise. So why not stop development of PhantomJS even earlier? It pretty much feels to me that one of the main potential drawbacks of the Open Source Software movement was the main reason: only a few developers have to deal with the many bug reports and feature request of thousands of users which are all happy to use the tool day by day, but are not willing to contribute or even pay for it. If you can&apos;t make a living from your Open Source project, there will be that one day when it is simply enough. Even the biggest enthusiasts have to pay their bills. To be honest, over the past years I have been in some sort of Love / Hate relationship with PhantomJS. The many bugs (which are totally normal to happen) combined with the very slow release cycles (which were absolutely annoying, but again understandable) ended up in many, many hours or even days of looking for reasons why that particular test failed only in PhantomJS (e.g. my previous blog post File uploads not working with PhantomJS). On the other hand, I can only express my deepest respect and thankfulness to the developers involved. And yes, I am also one of the thousands of users who used PhantomJS without any contribution. Look ahead! What will Chrome Headless bring us? I think chances are pretty good that it will be the new standard for Headless testing soon, and this is by no means an offense to the PhantomJS project. There will be a new ecosystem around it, which will make integration of Chrome Headless as easy as for PhantomJS. On the other hand, we will loose an independent player on the field, and once again Google will gain more power. However, being responsible for the future wellbeing of the projects I maintain as it is my profession, I will have to adapt to this change. I will have to change the project stacks in order to replace PhantomJS with Headless Chrome very soon. At least not taking it into consideration would be a huge mistake. Still the ecosystem around Chrome Headless as to evolve, but I actually have no doubt it will. Luckily PhantomJS implemented the Remote WebDriver Wire protocol since version 1.8 (speaking of GhostDriver here, another project from the PhantomJS ecosystem which I didn&apos;t even mention yet), so those projects which were not relying on the PhantomJS API will be lucky. Just recently, ChromeDriver 2.30 which officially supports Chrome 59 has been released - one concern less! So far no new maintainer of PhantomJS has been found. The burden might be too heavy.</content:encoded></item><item><title>PHP mail() on Windows</title><link>https://windler.dev/blog/php-mail-on-windows/</link><guid isPermaLink="true">https://windler.dev/blog/php-mail-on-windows/</guid><description>How to use PHP mail() on Windows without a local mail server, by configuring sendmail.exe to forward emails to an external SMTP server.</description><pubDate>Sun, 11 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Setting up an email server on Windows can be a real pain. Hardly worth the effort when all I want to do is using PHP&apos;s mail() function. I found a nice workaround when I updated my XAMPP installation: http://glob.com.au/sendmail/. All you need is an SMTP server somewhere that you can use, because sendmail.exe will just forward the emails to it. You still need to configure it though: Configure your SMTP in the sendmail.ini (located usually under C:\\xampp\\sendmail) In the php.ini, ensure you have the following set up That&apos;s it. Now you can quickly test it (below script more or less stolen from php.net): If everything is set up correctly, you should notice that the execution of the script takes a moment. If it runs through fast, something did not work - or you have a really fast machine &amp; connection. Note: although I had some config errors the first time the error.log in the sendmail directory was not populated with any messages. I don&apos;t know when this file will actually be used.</content:encoded></item><item><title>Pitfall: php_admin_flag vs. php_flag</title><link>https://windler.dev/blog/pitfall-php_admin_flag-vs-php_flag/</link><guid isPermaLink="true">https://windler.dev/blog/pitfall-php_admin_flag-vs-php_flag/</guid><description>Pitfall: php_admin_flag in Apache vhosts sets PHP ini values permanently, so ini_set() silently fails. Use php_flag to keep values overridable.</description><pubDate>Tue, 15 Oct 2013 00:00:00 GMT</pubDate><content:encoded>Today I was almost going crazy about the PHP ini setting &quot;display\errors&quot;, which just couldn&apos;t be convinced to be &quot;On&quot;. After some searching on the Internet without a result (&quot;Must be an undiscovered bug ... dammit&quot;) I was about to give up. Hey, what do we have an error log for? But then good-old intuition stroke again - how about the vhost configuration? Bingo: Who the f...? Well, me of course! I copied a bunch of these statements when taking another vhost configuration file as template, without having a closer look. &quot;php\admin\flag&quot; is surely nice for hosters etc., because it sets the PHP ini value once and for all. That&apos;s probably tricky, because ini\set() will simply return false, with no more information. Note to myself: if setting ini values via vhost is really needed, better use &quot;php\_flag&quot; instead. This way the value can still be overwritten.</content:encoded></item><item><title>PyCmd &amp; Console2 - Windows command prompt reloaded</title><link>https://windler.dev/blog/pycmd-console2-windows-command-prompt-reloaded/</link><guid isPermaLink="true">https://windler.dev/blog/pycmd-console2-windows-command-prompt-reloaded/</guid><description>PyCmd and Console2 turn the Windows command prompt into something usable, with searchable command history, tabs, and a sane way to copy and paste text.</description><pubDate>Mon, 26 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Finally! A command prompt for Windows that doesn&apos;t suck! Now the Linux guys have no reason to smile at (the) Windows (console) anymore. http://sourceforge.net/projects/pycmd It offers you a searchable(!) command history(!) and surely some other cool stuff, but I stopped reading at this point and directly installed it right away. It integrates nicely with http://sourceforge.net/projects/console/ which amongst other kick ass features allows multi tabs(!) and a not-totally-weird-and-counter-intuitive way to Copy &amp; Paste text. Nice. Just go to Settings &gt; Console and select the PyCmd executable for &quot;Shell&quot;. If you want to define different tabs go to Settings &gt; Tabs. This way you can also integrate MINGW32, the Linux bash emulator for Windows that comes shipped with Git for Windows. Ultimate command prompt power unleashed. Sort of.</content:encoded></item><item><title>Reduce boilerplate code with PHP 8</title><link>https://windler.dev/blog/reduce-boilerplate-code-with-php-8/</link><guid isPermaLink="true">https://windler.dev/blog/reduce-boilerplate-code-with-php-8/</guid><description>How PHP 8 features like constructor property promotion, readonly properties, and named arguments cut boilerplate in DTOs versus old getters and docblocks.</description><pubDate>Sun, 10 Jan 2021 00:00:00 GMT</pubDate><content:encoded>I&apos;ve come a long way with PHP and using of Getters, Setters and DocBlocks was a no-brainer for me for many years. They somehow belonged to PHP as if they were built-in features. Often enough, they were (and still are) simply part of the frameworks we used. Yet with PHP 8 released, it&apos;s time to rethink some good old habits and reduce boilerplate code with PHP 8. Looking back The below code sample shows how I most likely would have programmed a simple DTO (Data Transfer Object) with two properties in the times of PHP 5. Wow, that&apos;s quite a bit of code for a simple DTO! Why was all of that stuff necessary? Mostly because of PHP&apos;s Dynamic Typing (or Type Juggeling, as it is called on the official php.net website). PHP 5 did not offer any useful type hinting functionality. If we wanted to ensure that properties were initialized properly, using Setter-Methods with some checks was a common and good practice to overcome the shortcomings of PHP when it comes to type safety. Even with dynamic typing, knowing which type a variable was supposed to have helped a lot during development. Since PHP didn&apos;t support this, we had to add it ourselves - DocBlocks were conceived and soon, although never been an official language construct, accepted and supported widely among the IDEs. The lack of type hinting required a lot of code just to ensure that attributes were used correctly. Surely, it was possible to write PHP code without caring about this kind of things at all, but just because something is possible, it doesn&apos;t mean it&apos;s a good idea to do so. Less is more Looking again at the example above, you can see that a lot of lines are used up by the DocBlocks already. As mentioned above, they had their good reasons to exist. They helped us overcome the problems of dynamic typing. With native Type Hinting support, is there any reason left to still use them? Is there a way to reduce some boilerplate code? Interestingly, this question is still worth a little debate here and there, were developers defend the usage of DocBlocks like this: Often auto-generated by the IDE, this little fella does not serve any practical use, as it does not add any valuable information. It&apos;s a waste of space and unnecessarily increases the cognitive load of the developers. The only thing worse than unnecessary DocBlocks are wrong DocBlocks: At some point, the &quot;type&quot; (or let&apos;s say the purpose) of has been changed, yet we forgot to update the DocBlocks of the set function. Not a big deal? Well, the next developer who comes across this code now needs to dig deeper into to find out what type should actually be off. Or we just ignore it right away. Avoid DocBlocks, if you can In my opinion, comments should be avoided if possible (and I&apos;m not the only one). Comments are not part of the executed code. Mistakes made in comments will not cause things to blow up. That&apos;s why often enough comments are not updated during refactoring and, in the end, are causing more harm than benefits. DocBlocks still have valid use cases though. You can use it for declaring the type of items in an array. Marking methods as deprecated is pretty handy as well. Also, some ORMs require parsing the DocBlocks for annotations to work. In this case, though, mistakes made in the annotations would cause noticeable effects aka as bugs and are hopefully caught by automated tests. Only add DocBlocks if they add information to your code which can not be made available otherwise. Skip the redundant parts. If they don&apos;t add value, remove them completely. An example of a useful DocBlock is The types of the function parameter or the return value require no further documentation. Yet the information that the function is deprecated is of great use, so we can add a DocBlock with only that information, and leave out the unnecessary stuff. Finally: PHP 8 attributes I am aware that many PHP frameworks still require annotations in DocBlocks, but that should not be the benchmark. Even the most popular framework in PHP makes heavy use of anti-patterns, so that should not keep us from challenging them. If your framework (or ORM or whatever package) is relying on DocBlocks to work, there is still hope: with PHP 8, attributes were introduced. Although I admit it will take a bit until I get used to the syntax, attributes will greatly help us get rid of DocBlocks and thus reduce boilerplate code. And it seems it already started: as the highly respected Tomas Vostruba noted in one of his recent posts, Symfony 5.2 introduced the attribute to replace the annotations: So finally, the valuable information will no longer be stored in comments, but in native PHP code. That&apos;s the way to go! More cleanup Another nice benefit of type hinting is that PHP 7 throws errors if the wrong type was used. That&apos;s why we can remove manual type checking in the Setter methods completely, which reduces the amount of boilerplate code even more: That&apos;s much shorter already! At this point, you can surely argue if it is necessary to allow the initialization of the properties via the constructor. If you don&apos;t need it, it will save you some lines as well. Much more space is eaten up by the Getter and Setter methods though. With PHP 7.4, we have property type hinting, so what do we actually still need them for? They don&apos;t serve any real, additional purpose anymore. Ok then, wait for a second - what if we just declare these properties as public in the first place then? It took me a while to overcome my habits, so the answer actually kind of surprised me as well: We don&apos;t need Getters and Setters for public properties anymore. Please don&apos;t get me wrong at this point: I don&apos;t say we don&apos;t need Getters and Setters anymore at all. Same as for the DocBlocks, we just should use them only if they are really necessary. In my example, I used a DTO. These are simple objects which only serve the purpose of moving data around. We can actually do this: Now THAT&apos;S a bit crazy, isn&apos;t it? Well, actually not! We still ensure type safety. I see no benefit of using Getters and Setters here at all. It just feels strange to me, but I can&apos;t help it: Again: it&apos;s all about ways to reduce boilerplate code. If we don&apos;t get any benefits from, why use it? Introducing PHP 8 It gets even cooler: with PHP 8, we can now use Constructor property promotion to reduce the code even more. The next example is, in my opinion, reduced as much as possible, without losing anything: Behold the result for a moment: we reduced the number of lines necessary for this DTO from 75 to 9! And we did not sacrifice anything! In fact, our code is more robust than before, since we now only use native PHP features and nothing else. Please note though: I&apos;m not opting for making all properties public! Private and protected properties are still necessary. An example could be a Repository which gets the database connection object injected via the constructor, and making it impossible to change it afterwards: This example is pretty made up, but I&apos;m sure you&apos;ll get the idea! However: If you have a private property and add Getter and Setter methods for it, there is no objection against making it public in the first place anymore. Contra Below I added some contra-arguments which I encountered recently. 1\. Casting and formatting of properties A common use case for Getters is to receive data differently than it is stored in the object, e.g., formatting dates or strings in a certain way. This is not what Getters should be used for, in my opinion. Getters should return the data unmodified. Add dedicated methods like or or whatever you like if you need it. 2\. Immutable Objects You probably came across Immutable Object already. The PSR-7 HTTP message interface is a common example of it: once created, you can&apos;t alter an instance. The only way is to create a modified copy out of it. Since there is no native support for this in PHP yet, achieving this goal requires some more manual work. Decide for yourself if it is worth the effort. I personally think it is not, at least for the average PHP script which is stateless between the requests. With native support, however, I think it would be a beneficial addition. In yet another brilliant article from Larry Garfield, he explores the topic of Object properties and immutability in great depth. I wouldn&apos;t be surprised if this would, in some way, become part of PHP soon. Update: readonly properties introduced with PHP 8.1 With PHP 8.1, we now get readonly properties as well: These properties can only be written once during object creation, and afterwards only be read accessed. Conclusion PHP has come a long way. It&apos;s still changing a lot, and so should we, the developers. Just because we used certain patterns for years, even if they served us well, it doesn&apos;t mean we shouldn&apos;t let them go one day. In my earlier years as a developer, I always fought hard for adding DocBlocks and using Getters and Setters everywhere. At that time I think it made sense. With the latest changes of PHP though, I&apos;m now convinced that we can improve our code a lot by getting rid of them. PHP matures, so should we. DocBlocks still can add valuable information to our code, yet we should only add them where we can&apos;t add this information with language features. The same is true for Getters and Setters. There might be use cases for still using them together with Constructor injection, but I want to challenge you to double think about it. With PHP 8, we can reduce boilerplate code by a lot. This will make our lives much easier. What&apos;s your view on this? Is it time to ditch Getters, Setters and DocBlocks, or are there good reasons that I did not consider?</content:encoded></item><item><title>Remote CLI debugging with XDebug</title><link>https://windler.dev/blog/remote-cli-debugging-with-xdebug/</link><guid isPermaLink="true">https://windler.dev/blog/remote-cli-debugging-with-xdebug/</guid><description>Remote CLI debugging with Xdebug and PhpStorm needs just two environment variables: PHP_IDE_CONFIG for the server name and XDEBUG_CONFIG for the idekey.</description><pubDate>Mon, 17 Nov 2014 00:00:00 GMT</pubDate><content:encoded>There are quite some tutorials out there on how to use XDebug to debug PHP CLI code, which where more confusing than helpful (to me). I found out that, once you have a running XDebug configuration, it is very easy to debug on the console, particularly with phpStorm. Simply run the following line once (after customizing it to your needs, of course), set your breakpoints and run the script. That&apos;s already it. You can also put this into your .bashrc file.</content:encoded></item><item><title>Second chance - Old notebook refurbished</title><link>https://windler.dev/blog/second-chance-old-notebook-refurbished/</link><guid isPermaLink="true">https://windler.dev/blog/second-chance-old-notebook-refurbished/</guid><description>Refurbishing an old HP Compaq 6910p with a new hard drive, Windows 7, and a cheap battery for about 100 euros, giving the notebook a second, greener life.</description><pubDate>Sun, 11 Aug 2013 00:00:00 GMT</pubDate><content:encoded>My 5 or 6 year HP Compaq 6910p still is in good shape. Back in the days it was a very decent business machine and served me well many years. Surely it is not comparable to a top notch notebook anymore, but totally ok for easy development or browsing. However the Windows XP installation wasn&apos;t bearable anymore, took ages to load and as we all know it won&apos;t be supported from next year on. The hard drive was very slow and already made strange noises sometimes. So I decided to give my old pal a second chance and ordered Windows 7 Pro for 30 € (erm ... not sure if this is really legal ... a DVD with a worn license sticker labeled with &quot;Dell&quot; from eBay) A new hard drive for 40 € A new battery pack (Cheap China copy) 25 € Pressure air for cleaning the fan 6 € The new hard drive performs way better (at least that&apos;s my impression, I didn&apos;t benchmark it), and the fresh Windows 7 installation loads really fast again! The new battery doesn&apos;t even run half the time the old used to do, but I don&apos;t expect long train rides in the next months. So as a roundup: Investment: 101 € Fun factor: As much fun as installing dozens of tools can be Environmental aspect: I guess one Notebook minus a hard drive and a battery pack Result: totally worth it!</content:encoded></item><item><title>T3CON14</title><link>https://windler.dev/blog/t3con14/</link><guid isPermaLink="true">https://windler.dev/blog/t3con14/</guid><description>Impressions from T3CON14 in Berlin: great atmosphere, inspiring sessions, and a memorable speech by TYPO3 founder Kaspar Skårhøj.</description><pubDate>Thu, 09 Oct 2014 00:00:00 GMT</pubDate><content:encoded>Currently I&apos;m attending the 10th International Typo3 Conference (or in cool: T3CON14) in Berlin, and although it is not over yet I really liked it so far. Not only because of the great location in one of the hippest parts of Berlin, or the tasty food, or that I was able to carry home a 3-years supply of stylish pens, no ... the atmosphere is fantastic and it is very nice to see the faces behind the names. Also many sessions where very inspirational. My favorite so far was the brilliant speech of Clemens Prerovsky (Aloha-Editor). Also, and I&apos;m definitely no fanboy, but to attend a speech of the Typo3-founder Kaspar Skårhøj was really something I would not have expected after all these years ;-)</content:encoded></item><item><title>Technical Debt and Refactoring - Eurostaff Meetup</title><link>https://windler.dev/blog/technical-debt-and-refactoring-eurostaff-meetup/</link><guid isPermaLink="true">https://windler.dev/blog/technical-debt-and-refactoring-eurostaff-meetup/</guid><description>Talk at the Eurostaff Connect Meetup on technical debt and refactoring, based on the blog series, with slides on Slideshare and good audience feedback.</description><pubDate>Mon, 27 Jan 2020 00:00:00 GMT</pubDate><content:encoded>On 23.01.2020, I gave a talk on the Eurostaff Connect Meetup about Technical Debt and Refactoring. Thanks to the kind audience on that evening, it was a pleasure speaking to you. I received a lot of good feedback afterwards. Eurostaff Connect - Meetup about Refactoring and Technical Debt My talk was based on my recently published (and yet unfinished) articles about this topic. Check them out and let me know your thoughts about it. The actual slides are available on Slideshare. Special thanks to Dominic, Alina and the rest of the Eurostaff team for being great hosts. I&apos;ll definitely join of the next events as guest again!</content:encoded></item><item><title>Template Engines vs. PHTML</title><link>https://windler.dev/blog/template-engines-vs-phtml/</link><guid isPermaLink="true">https://windler.dev/blog/template-engines-vs-phtml/</guid><description>Template engines like Fluid add overhead and are hard to debug, while PHTML files render fast and work with the PHP debugger. A performance case for PHTML.</description><pubDate>Sun, 24 Aug 2014 00:00:00 GMT</pubDate><content:encoded>The Problem: Performance. Once again. It was time to think again about the use of Template Engines (i.e. those like Smarty or Fluid who offer their own syntax) versus so called PHTML files (i.e. basically mixed HTML and PHP), as one of my colleagues currently works on a Typo3 Extbase extension with a very huge HTML output. Unfortunately the rendering process was extremely slow. In our case Fluid, the template engine that comes bundled with Extbase, was to blame. Although using compiled templates, it took about 6 seconds to render. After clearing the cache it was way beyond 20 seconds until the templates were compiled again. What the heck. Where does this massive overhead come from? Looking at the compiled templates, I was a bit shocked: one of it had almost 20.000 lines of PHP code, tons of closures and function calls! It was just a template, now it is a monster. 6 seconds rendering time is not acceptable at all. Surely the extension produced a big HTML code, using loads of loops, partials and view helpers, but we had to find a way to deal with it. Two options where obvious at that moment: Do we really need to use Fluid? How about loading at least parts of the content, which is not immediately used, via AJAX? I admit I&apos;m biased. I never liked using any Template Engine in PHP. That&apos;s why I had a closer look at option 1, while my colleague started working on option 2 meanwhile. Considerations Let&apos;s think about the Pros and Cons of using template engines in PHP. Here is what we came out with: Pros: No PHP knowledge required to build templates: yeah, sure. This is a common argument. So it is ok for the Webdesigner to learn a new template engine, but too much to learn PHP basics. Plus, at least in our team there is nobody who doesn&apos;t speak PHP. Templates are cleaner, easier to read: this depends on the template engine of course, but considering Fluid I would agree on that. It is not very important for me, though. No risk of PHP abuse in template: Yip, good point. I guess we&apos;ve all had these &quot;WTF!?!&quot; moments when we looked at PHTML templates, finding functions with business logic in templates. This surely requires the coders to be disciplined, and/or Code Reviews. Template Engines offer caching mechanisms: true. But without caching they wouldn&apos;t even come close to the performance of PHTML files. There&apos;s nothing to say against implementing your own caching when you use PHTML templates, though. Cons: Using a template engine produces overhead: you can&apos;t ignore the fact that a templating engine per se is additional overhead. This is not necessarily bad, when the overhead is low, but when the content takes more than double the time to render it might not be the correct choice. Templates can not be debugged properly: I&apos;m used to develop using a PHP debugger a lot, especially when I have to deal with many variables and nested arrays. I can&apos;t use that in templates. I can use it in PHTML files. &quot;Why did my change don&apos;t come through? Ah, I forgot to clear the cache again!&quot;: If this applies to you, as it does for me, then template engines can be a bit of a pain sometimes. &quot;I&apos;m not slacking off, my code&apos;s compiling&quot;: Not only a smart reference to XKCD, but also a very annoying aspect: if you develop, you either turn off caching completely (slow!), or you have to clear the cache whenever needed (annoying - and slow!). Ok, there are some points which speak for Template Engines, but are they really worth the overhead? This surely depends on personal preferences, but for me it was clear: No. It is not. Conclusion: Go back Great. We wanted to stick with Extbase, but we didn&apos;t want to use Fluid all the time. So we need a PHTML template renderer for Extbase. It should at least cover the following requirements: We want true MVC! View and Logic must be separated. Extbase/Fluid must not be modified. Copy&amp;Paste has to be avoided. The PHTML renderer should be easy to integrate. Existing controller actions shouldn&apos;t be rewritten at all. The use of Fluid should still be possible. Partials must be supported. Fluid ViewHelpers should be supported, at least some sort of ViewHelpers must exist. Namespaces for ViewHelpers would be nice. Of course there is a mayor drawback: all the Fluid templates which already existed need to be &quot;backported&quot; to PHTML. Oh well... It should however show that the required goal was very easy to achieve. This will be shown in the next post. What are your views on Template Engines? Maybe we missed the one argument to use them instead of PHTML?</content:encoded></item><item><title>The Hidden Environmental Impact of the AWS SDK for PHP</title><link>https://windler.dev/blog/the-hidden-environmental-impact-of-the-aws-sdk-for-php/</link><guid isPermaLink="true">https://windler.dev/blog/the-hidden-environmental-impact-of-the-aws-sdk-for-php/</guid><description>The monolithic AWS SDK for PHP ships 40 MB of mostly unused code per install, causing roughly 75 tonnes of CO2 a year. Async AWS is the lighter alternative.</description><pubDate>Wed, 10 Jan 2024 00:00:00 GMT</pubDate><content:encoded>What does a set of screwdriver bits in common with the AWS SDK for PHP? Surely you have been in this situation before: You only need one particular screwdriver, but since you can&apos;t get them separately, you have to buy a full set. Well, what can you do, and who knows, maybe you&apos;ll need a second one in the future? Same with the PHP SDK for AWS. You may only need one or two services in your project right now, but you still have to install the full SDK with an API for almost every AWS service that exists. But it&apos;s free, so what&apos;s the problem? Just download the bunch and forget about the rest, right? Nothing comes for free First of all, it&apos;s a lot of code. Over 40 MB of plain PHP code, spread across 4000 files. That might be acceptable for a monolith (well, no, not really), but what about a lambda function? For me, it kills the idea of a Lambda if a function has to be shipped with thousands of lines of code just to connect to DynamoDB, for example. I can&apos;t even edit the code in the AWS console because it&apos;s too big for the editor. And it gets updated a lot due to the sheer number of APIs it contains, often twice a week or more. It&apos;s great that it&apos;s well maintained, but a lot of updates are for code you don&apos;t use. It&apos;s like buying a new bit set, just because one of the other bits has changed. Second, and more importantly, there&apos;s the carbon footprint of all this. How do we estimate the emissions caused by the data transfer? Let&apos;s do some number crunching. The AWS SDK for PHP has about 200k daily installs, according to Packagist.org. Gzipped, it&apos;s still about 3.7 MB of data transferred. Let&apos;s see what Carbon emissions of data transfer So what&apos;s the environmental impact of that? If we follow the Sustainable Web Design methodology and assume that 1 GB of network traffic emits about 350g of carbon (0.81 kWh/GB × 442g CO2e/kWh), we end up with over 210 kg of carbon emissions per day. Doesn&apos;t sound so much, but it sums up to over 75 tonnes of carbon per year - for code that we don&apos;t need! If we assume that 3 MB of the 3.7 MB is actually just unnecessary compressed code per download in most cases, we have 200k × 3 MB × 365 = 219 TB of data transfer per year that could have been avoided. Of course, we can debate whether the methodology used here makes sense. It&apos;s based on estimates for the global network, but we have to start somewhere. Even if the numbers are not correct, I think they serve well to illustrate the issue. Please don&apos;t hesitate to provide feedback if you think the approach I chose here is not correct. What would be a solution? Ideally, AWS would have to break the SDK into smaller pieces so that you could only include dependencies for the services you really require. If you prefer not to wait for miracles, you can use the great Async AWS project \3\, which already does this. For me, this is a perfect example of what&apos;s wrong with software development. We have become lazy, and we can simply compensate for this laziness with more resources. This thinking leads to “overweight” software and even more resource consumption. On the other hand, however, it shows that there is great potential to reduce the environmental impact of IT. What do you think? Is this a problem worth thinking about? And do you generally care about the size of the dependencies that are used in your projects?</content:encoded></item><item><title>Torn from the USA – Leaving US Tech Behind</title><link>https://windler.dev/blog/torn-from-the-usa-leaving-us-tech-behind/</link><guid isPermaLink="true">https://windler.dev/blog/torn-from-the-usa-leaving-us-tech-behind/</guid><description>A personal journey of moving away from US tech in 2025 for data sovereignty and political reasons, with European alternatives like Nextcloud.</description><pubDate>Sun, 07 Sep 2025 00:00:00 GMT</pubDate><content:encoded>Are you still relying on digital services from the US? Well, most likely you are, because just a few months ago, this was absolutely normal and a completely sane choice to make. In 2025, however, nothing is sane anymore, and knowing that erratic billionaires have power over your data or are directly getting involved in political processes is more than worrying. For me, it’s terrifying. Unless you want to support these people, you should consider at least not throwing your money at them anymore. From my point of view, there are two dimensions to the problem: private usage and business. In this text, I’ll only focus on my own private digital life and what I did so far to get rid of US tech companies The World We Live in – 2025 edition Yes, it’s getting political, and I wish it wasn’t necessary. It is important, however, to understand that digital services can be used as a lever to exert political pressure. Not even mentioning the taxes that could be introduced in literally any industry at any given moment, but would you, in 2025, doubt that, for example, AWS could be forced to at least temporarily limit or even disable certain services in Europe? If you don’t, it’s worth mentioning that Microsoft already shut down email services of people who are considered as enemies of the aforementioned billionaires. And they admitted, in a hearing, that they can’t guarantee the security of EU data. In other words, there is no such thing as the sovereign European cloud. Monopolies are a problem. Just relying on a handful of services comes with high risks. What if they fail? Recently in Germany, PayPal had a hiccup and caused massive problems. Now just imagine PayPal being unavailable in Europe for a longer or indefinite period. Even if those services are not weaponized, you surely can’t deny that their owners and leaders are ridiculously rich. This comes with its own, full bag of interesting problems. Spoiler: Billionaires are a threat to democracy. Who would have thought? And they now openly show how corrupt they are. The fact that they lost the fear of public opinion should worry you. So, if you don’t want to support those people or those who tolerate and applaud them, it’s time to look for alternatives. Freedom always has a price Admittedly, it’s not easy to get rid of some services. They are excellent. Not surprisingly, considering the billions of dollars that went into their development. However, there are cool projects like https://european-alternatives.eu/ that help you find, well, alternatives. You sometimes have to pay, but remember – if it’s for free, you are the product. Or your data is. Mostly your data. You don’t want to feed it into AI? Then consider what services you use. Let’s get rid of the “everything is for free on the internet” mentality. Another noteworthy website is https://www.goeuropean.org, which is not limited to digital services but covers all kinds of products, like Cola. It surely is a journey. Nothing that comes easy, or fast, or for free. Besides the political dimension, there is also an interesting aspect about digital services, which I’m sure you also experienced – the so-called enshittification. In a nutshell, this term, coined by Cory Doctorow, describes the phenomenon that services (not only digital ones) have to become worse – mostly because of greed. Whoops, humans, do you feel caught out? Current state Here’s what I’ve achieved so far. Data storage I already used Nextcloud as a Dropbox file-sync alternative for many years, keeping my most important files synced across at least two devices, so it’s also part of my backup strategy. But it actually offers so much more: Notes, RSS Feeds, Mails, Calendar, Todo lists, Contacts … Admittedly, it looks a bit old-school; the UI is not that polished, but hey – it’s ok. Open-Source, free, and not controlled by the Tech Bros. You’ll find more examples of it below. And since it uses open standards, like WebDAV, it easily integrates into your OS. As a side note, Nextcloud also recently achieved the Blauer Engel, a label for sustainable software. After running it on a shared hoster for some years, I recently decided to go with managed Nextcloud hosting. It works flawlessly, is reasonably fast, and no maintenance work is needed from my side. Social Media Ok, I’m bad at social media. Or maybe just not that interested in it. I use Mastodon sporadically, and I like it. My problem is not Mastodon, but social media in general. I deleted my Twitter and Facebook accounts long ago. Especially Meta is rotten to its core (one of the many examples: Meta supports “romantic relationships” with children for their chatbots. It’s so utterly disgusting that anyone who uses their services or even works there still today should be ashamed. The only other social network I use is LinkedIn, since it’s supposed to be a business network. I don’t see an alternative for it yet. But I do also see the enshittification here, so it’s just a matter of time. In general, I’m diving more into the Fediverse recently. The Fediverse is the decentralized social network that includes Mastodon and other services and is powered by the ActivityPub protocol. Besides Mastodon, which is a microblogging service and similar to Twitter, there are more services like Pixelfed, which are some sort of Instagram. Task management Since I worked in a company a few years ago where Asana was used for literally everything, I stuck with it. It’s a great service, and the free account offers a lot. But actually, I just used it as Todo list, and for that, Nextcloud Tasks does the job quite well. It nicely integrates with some Linux distros like Ubuntu (or, erm, macOS / iOS…). It surely is no replacement for fancy project management tools, though. Notes Also here – Nextcloud! Nextcloud Notes offers a reliable service for keeping your notes, with tagging, etc. The notes are stored as clean text files in your Nextcloud instance, so there is no vendor lock-in effect. Mobile and desktop apps are available, too, through QOwnNotes. Yeah, it does look a bit clunky. But that’s ok for me. There is a Web Clipper browser extension, too. Joplin, however, could also be a nice alternative, since it doesn’t come with a vendor lock-in. I haven’t tried it yet, though. Backups I have my private AWS account but mostly use it for backing up important private data, like photos and videos. Of course, the service is great, but I switched to Strato HiDrive, which is S3 compatible and thus integrates nicely with my backup workflow. A bit more expensive, but knowing I don’t finance billionaires who take over half of Venice for their wedding is fully worth it. Online shopping Speaking about Amazon, I used it a lot. Of course, with Prime. I stopped it immediately when I heard that Jeff Bezos forced the Washington Post editorial team not to publish an article because he wanted to support (or, let’s say, “not offend”) Trump. There are enough alternatives to buy online. Or just buy less stuff. At least less cheap trash from China. Seriously, we all have enough of that crap. Streaming and TV In Germany, public broadcast offers some good series, documentaries, and movies as well (e.g., ARD, ZDF, Arte). The apps work with my Amazon Fire Stick. And, as a German citizen, I already pay for it anyway. Surely, you won’t get the latest hype, but I don’t care. Admittedly, I still got my Netflix, though – compromises are necessary when you have a family. Payment I don’t want to support people like Peter Thiel, so I stopped using PayPal as well …. mostly. Sometimes I can’t get around it, but it gets better. Wero, an European alternative, is in the making. So far, it only offers money transfer between private people, but online payment is being worked on. Messaging Switching to Signal and Threema here. Also not that great, but all is better than Meta. It’s challenging to get rid of WhatsApp, though, since many people use it for, e.g., organizing sports courses and such. Working on it, at least reducing the usage quite a lot. Shared hosting I hosted my blog and some other, smaller projects, on HostEurope. Bad service (not even SSL with Let’s Encrypt!) high prices, but, you know, migrating stuff takes some time, and I was lazy. Until HostEurope announced to switch their email service to Microsoft 365. Haha, no way, dudes. That was the final push I needed. I now migrated to a small German hoster called Manitu, which has good prices and services and runs on green energy, too. Games Switching from Steam over to gog.com. I’m not playing that many games anyway. The benefit here is you actually OWN the game, not just a license to play it. You can even download and archive them. Nice. For Linux, I use the Heroic Games Launcher. E-Books For years I’ve already been wondering why people are using Kindle (sure, the hardware is great), where everything is regulated with DRM and, similar to Steam for games, you don’t own the books you paid for. I use the Tolino, which is supported by some bigger German bookstores. But since it is completely open, you can simply upload your ebooks, e.g., in EPUB or PDF format. Operating System My desktop PC (yes, I still have that) operates on Ubuntu. I ditched Windows years ago, and I feel so much better since then. The hardware requirements for Windows 11 are ridiculous and turn perfectly fine working machines into electronic waste. It’s an OPERATING SYSTEM, we just want to use it to run software on it, dammit. AI Artificial intelligence seems to be ruled by the US. The problem: these companies don’t care about privacy, about copyrights, or about the ecological impact of their massive server farms. But let’s not forget the European alternatives, like Mistral AI. I especially like GreenPT, which is hosted in the EU and cares about the environmental impact of their services. It’s fully paid now, i.e., no free plan, but again, there is a price to everything, and that’s ok. Functionality-wise, it is a bit behind the big players, though. Search Engines I’m using Ecosia, which is planting trees for your searches, and DuckDuckGo. I know, I know, they use Google and/or Microsoft Bing, but at least you’re not throwing your data at these companies. The struggle goes on Although I’m pleased with where I am right now, I still have a few struggles: Smartphone &amp; Laptop I’m stuck with Apple. I am not sure how to get out of this right now, as I don’t want to buy a new phone yet. Let’s see in a few years what alternatives there are. The MacBook hardware is great, but I would really like to switch to Linux here too. So maybe it will be a Framework laptop and a Fairphone the next time. GitHub As a software developer, I of course have my GitHub account. But since M$ took it over, there is some bad taste to it. I recently came across Codeberg.org and want to give it a try someday. YouTube The Fediverse alternative is PeerTube, but although, for example, the German Heise Verlag is using it, there is hardly any good content on it – yet. LinkedIn: owned by M$ too, oh my… For what it’s worth So, was it worth it. I’d say, Definitely. Digital sovereignty is a must in this rapidly changing world. I’m not anti American at all, and it actually breaks my heart to see this great country going down the drain. However. It is a wake-up call that the centralization of wealth and power is always a threat for societies. The President of the USA started threatening Europe to not treat US services “unfair” through digital taxes or regulations. By now, everybody should know what “fairness” really means: follow our rules, or suffer. However, Europe has enacted these regulations, like the Digital Services Act, to protect its own markets, its own citizens, and also our democracy. Trump is openly fighting against it. It also proves that open source is becoming more important than ever. I think that Europe should start supporting OSS financially rather than subsidizing, e.g., fossil fuels. Software like Nextcloud or the Fediverse could be used by many countries without privacy or political concerns. Why are we still spending money on Big Tech? Let’s move on!</content:encoded></item><item><title>Traits and Extbase</title><link>https://windler.dev/blog/traits-and-extbase/</link><guid isPermaLink="true">https://windler.dev/blog/traits-and-extbase/</guid><description>PHP traits make Extbase extension settings reusable across repositories, scheduler tasks, and hooks where abstract base classes do not fit.</description><pubDate>Tue, 02 Dec 2014 00:00:00 GMT</pubDate><content:encoded>With Extbase, accessing the extensions settings outside Controllers (e.g. in a Repository) requires some manual work which is always the same. I don&apos;t know why Extbase doesn&apos;t support us with helper functions, but anyway, let&apos;s put this needed code where we can reuse it easily. Being limited to PHP 5.3 until last month, my usual approach was to inherit the Repository from an Abstract class which contained a set of often used functions. This still works fine, but if you want these functions to be used in let&apos;s say a Typo3 hook class, or a Scheduler task (where the Extbase support is even worse! Geez!), you probably end up writing a couple of Abstract classes which are more or less the same. Of course you can inherit the Abstract class from another abstract class ... which again doesn&apos;t work with Scheduler tasks, because they need to inherit from a base class anyways... nah... Since we now use PHP 5.4 on our production servers (and yes, I am aware that 2014 is almost over), I felt urged to find out whether Traits can be used with Extbase. Surprisingly (working with Extbase and Typo3 is easier with a good amount of sarcasm) it was as easy as it should be! I tested it on Extbase 6.2, and the Autoloader loads the Trait without any hassle. Here&apos;s some example. First, the trait itself: No rocket science, but stuff you need all over again. I decided to use &quot;Library&quot; as namespace, but this doesn&apos;t really matter. So far, so easy. To include a trait, you only need to add the &quot;use&quot;-statement inside your class, e.g. in a repository: This works really smooth, I think I will get used to Traits very soon. Fun fact: shortly after finishing my Extension where I used Traits for the first time, I was asked for a PHP 5.3 compatible version. Fuuuuuu......</content:encoded></item><item><title>Trap events</title><link>https://windler.dev/blog/trap-events/</link><guid isPermaLink="true">https://windler.dev/blog/trap-events/</guid><description>Use the Linux trap command to clean up lock files for cronjobs on signals like EXIT, HUP, KILL, and TERM, so the queue runs again after a crash.</description><pubDate>Mon, 28 Oct 2013 00:00:00 GMT</pubDate><content:encoded>If you have cronjobs running to trigger a queue, you probably would like to take care that queue is not triggered multiple times, e.g. when the previous run is not finished yet. This can easily be done using a lock file which is written upon the next queue run and removed when it is done. So far, so good. But what happens if the server crashed, or some Admins are restarting the VMs once a week to &quot;solve strange problems&quot;? Then you have to take care that the lock file is removed, otherwise your queue might not run again upon restart. On Linux, this is very easy due to the handy &quot;trap&quot; command: The rm command that removes the log file is executed when either the EXIT, HUP, KILL, INT, QUIT or TERM signal is send. Now we don&apos;t have to delete the file manually after a shutdown.</content:encoded></item><item><title>Typo3 Caching and TypoScript conditions</title><link>https://windler.dev/blog/typo3-caching-and-typoscript-conditions/</link><guid isPermaLink="true">https://windler.dev/blog/typo3-caching-and-typoscript-conditions/</guid><description>TYPO3 builds a cache entry per TypoScript condition, so browser conditions bloat the cache. Move IE hacks into conditional HTML comments to keep it small.</description><pubDate>Mon, 22 Sep 2014 00:00:00 GMT</pubDate><content:encoded>Having taken over a somewhat shabby Typo3 project recently (I prefer using the term &quot;challenge&quot; here), digging through the many TypoScript files revealed something which is probably very common in many Typo3 setups: Why is that a problem? Well, when it comes to caching, Typo3 starts building up Cache entries for every possible condition. So from the above example, we will get 3 cache entries: Internet Explorer 7 Other Internet Explorers All other browsers except Internet Explorer Of course this blows up the database, but space wasn&apos;t the main problem in our case - it was the time it took to rebuild the cache after clearing it. This Typo3 installation serves thousands of pages, and they are crawled regularly to build up the cache, so we really don&apos;t want to waste any time. So what do we do? First and obvious step, drop IE 7 support! Ahhh, that feels so right.... Ok. Now the remaining, really few IE hacks in the ie.css will be included by using good old Conditional comments: The additional load for IE users is minimal, and we got rid of quite some cache entries and saved a good amount of computational power.</content:encoded></item><item><title>Typo3 CMS hooks and namespaced classes</title><link>https://windler.dev/blog/typo3-cms-hooks-and-namespaced-classes/</link><guid isPermaLink="true">https://windler.dev/blog/typo3-cms-hooks-and-namespaced-classes/</guid><description>Register a TYPO3 CMS hook with a namespaced class by using the fully qualified class name in the SC_OPTIONS array, with an optional ampersand for singletons.</description><pubDate>Tue, 16 Jun 2015 00:00:00 GMT</pubDate><content:encoded>During work on my extension cwenvbanner to make it compatible with Typo3 CMS 7.2, I came across a good old friend, the hooks array $GLOBALS\&apos;TYPO3\CONF\VARS&apos;\\&apos;SC\OPTIONS&apos;\_. Since I sometimes struggle with the way how to declare the class and function to be called, I decided to write it down here - once and for all :-) In short, this is how a hook can be defined The ampersand before the class name is optional. If you add it, the class will be instantiated using the Singleton pattern. Let&apos;s have some examples. Firstly, let&apos;s have a look at the old version I had in my extension: For the new Typo3 CMS 7 compatible version of cwenvbanner I wanted to use a namespaced classes for the heck of it. I came up with the inspiring name &quot;Main&quot; which now resides in the Classes directory of the extension, so need I changed the path and filename accordingly. I also need to provide the fully qualified class name, i.e. Cw\\Cwenvbanner\\Main. This is how it looks like now:</content:encoded></item><item><title>Typo3 Extbase: Object not saved</title><link>https://windler.dev/blog/typo3-extbase-object-not-saved/</link><guid isPermaLink="true">https://windler.dev/blog/typo3-extbase-object-not-saved/</guid><description>Extbase silently refuses to save an object when a TCA column is missing, because the object hash differs from the persisted one. Adding the TCA column fixes it.</description><pubDate>Sun, 16 Mar 2014 00:00:00 GMT</pubDate><content:encoded>Recently I stumbled upon a nasty problem with Typo3&apos;s Extbase. The instance of an object was not updated, but as usual (for Flow/Extbase, that is) there were no exceptions, no log entries, no hints... Extbase just silently refused to save the object. Great! After debugging through the code once more (my number 1 source of information regarding Extbase nowadays), I found that 1 of 80 columns of the related table was missing in the TCA array! How dare it! After adding it, everything was working as expected. The core problem: when fetching the object from the repository, Extbase only populates those class members that are configured in the TCA (which in Extbase will be the DataMap later on). This also means that the class member I forgot in the TCA was missing! Then I used a Setter to set a the mentioned missing value, which added the class member. Extbase uses spl\object\hash() to keep track of the objects during a request. Of course, due to the missing member, the existing object and the to be updated object had different hashes ... got it? Yeah... I really wished Extbase would communicate more with the developer. Just silently refusing to do stuff is not ok, in my opinion.</content:encoded></item><item><title>Updating Typo3 CMS 6.2 to 7.2</title><link>https://windler.dev/blog/updating-typo3-cms-6-2-to-7-2/</link><guid isPermaLink="true">https://windler.dev/blog/updating-typo3-cms-6-2-to-7-2/</guid><description>Practical notes on updating TYPO3 CMS 6.2 LTS to 7.2: PHP 5.5 and MySQL 5.5 requirements, RealURL, compatibility6, and CSS and login problems after the upgrade.</description><pubDate>Mon, 22 Jun 2015 00:00:00 GMT</pubDate><content:encoded>Updating our companies major portals from Typo3 CMS 4.7 LTS to 6.2 LTS was a good piece of work, so I was not really keen on updating any websites again. A good excuse for us was the fact that RealURL was not yet available for Typo3 CMS 7, but now it is - no more excuses. We need to do it anyway. Before you even start, you should check the requirements of Typo3 CMS 7. It requires at least PHP 5.5 and MySQL 5.5, which might not be available on your server. So check the Typo3 CMS 7 System requirements before you continue. I started with a relatively small project, which was ideal to get some experience. Only a few dozens of pages, a couple of TypoScript files, and most important, no legacy extensions but only good maintained Extbase 6.2 extension. I was pleasently surprised that the whole migration with fixing all issues (see below) only took roughly one hour, so my thanks to the Typo3 CMS team for that great job! If you have one or more pre Extbase 6.2 extensions which don&apos;t yet use namespaces (i.e. classes are named like Tx\MyExtension\Domain\Model\Whatever instead of just Whatever), there is an extension called &quot;compatibility6&quot; which comes bundled with Version 7.2. You can also use it if you already screwed your Typo3 installation and you can&apos;t login into the backend anymore: you can install it manually by editing the typo3conf/PackageStates.php, search for compatibility6 and change the state from inactive to active. Please note that the usage of this extension has a negative impact on performance, although I can&apos;t quantify the impact. It might just be ok for smaller websites. The update process is explained here: http://wiki.typo3.org/TYPO3\CMS\7.2.0. In our case, the basic steps were: download the Typo3 sources uninstall RealURL delete typo3temp/Cache folder switch typo3\src to new version run all checks in the Install tool login into the backend, update RealURL to the recent version and install it again Update problems Of course the update did not go without any problems, so let&apos;s discuss them in this section. CSS missing! After finishing the update work in the Install tool I went to the backend login page and was somewhat suprised - I didn&apos;t expect that fresh oldschool style: Ok wait, there&apos;s something wrong. Obviously the t3skin.css was missing. It turned out that somehow the PackageStates.php was mixed up, and although the t3skin system extension was marked as active, it obviously wasn&apos;t. Doing some internet research revealed that this problem occurred for others as well. I ended up in simply deleting the PackageStates.php (after doing a backup) and reload the login page. This way, the PackageStates.php was regenerated from scratch. Once it was created again, I needed to re-activate almost all system extensions manually. All in all this was just a matter of minutes, so no big deal. No leading backslashes please! After fixing the CSS issues, I loaded the start page which includes one of our custom extensions, and ended up with another exception: $className &quot;\\My\\Nifty\\Class&quot; must not start with a backslash. Some of our makeInstance() calls had a backslash before the FQCN, which whith Typo3 CMS 7 is not allowed anymore. Since the backslash is not needed, we simply removed it, e.g. This also applies for calls to the ObjectManagers get_\-function! Stating the class name as a string leads to the ugly double backslashes, which nobody likes. With PHP 5.5+, we now can use the ::class constant: which I really prefer because it is more readable and you can now use your IDEs code completion. When the views are gone Next reload, the page loads ... yay! No exceptions. Good. So on to the next issue (a real classic): This time the problem was in the Configuration\\Typoscript\\setup.txt of one extension, where we still used the old name for the view folders: Extbase supports fallback paths for templates, layouts and partials, which is quite cool - when you know it. Fluid uses the highest index (in our case only one, the 10) as directory for looking up the templates, and tries out the next lower one if it fails. Oh, and also it is called RootPaths instead of RootPath for a while already. Say &quot;hi&quot; to number seven Updating to Typo3 CMS 7.2 caused far less trouble than the previous &quot;LTS-Jump&quot;. I really like the fresh look of the backend, and the fact that the Typo3 core has been cleaned up even further. Surely the website I migrated was only a small one with no legacy extensions, but I think I covered some issues which might be helpful to others!</content:encoded></item><item><title>Updating XAMPP without a headache</title><link>https://windler.dev/blog/updating-xampp-without-a-headache/</link><guid isPermaLink="true">https://windler.dev/blog/updating-xampp-without-a-headache/</guid><description>Update XAMPP on Windows without losing projects: rename the old folder, install fresh, copy htdocs and databases, diff php.ini, and keep the old as backup.</description><pubDate>Sun, 11 Aug 2013 00:00:00 GMT</pubDate><content:encoded>After some years the time has come to update my local WAMP stack to a more recent PHP version. I also made good experiences with WAMP (the other cool stack for Windows), but I&apos;ll stick with XAMPP and install 1.8.2. This will also make things easier. Rename the old xampp installation directory C:\\xampp (or where you installed it) to C:\\\xampp Install new XAMPP under C:\\xampp Copy all (needed) files/projects from C:\\\xampp\\htdocs to C:\\xampp\\htdocs Copy all (needed) databases from C:\\\xampp\\mysql\\data to C:\\xampp\\mysql\\data. EDIT: Don&apos;t do that if your databases contain InnoDB tables. Use mysqldump instead. Check differences between both php.ini files, located in C:\\xampp\\php If you made changes on your MySQL configuration, don&apos;t forget to check C:\\xampp\\mysql\\bin\\my.ini as well check your PHP Extensions in php/ext: you will need new versions of any additional PHP extensions (e.g. libpdf). Keep in mind that PHP 5.4 has been compiled using VC9 instead VC6 as in PHP 5.3 when chasing for downloads! Take over changes in C:\\xampp\\apache\\conf\\httpd.conf - most likely you&apos;ll have some VirtualHost configurations Run the security check in XAMPP (http://localhost/security/index.php) to set the MySQL password to the same password you used in the old XAMPP installation (if you&apos;re using a password) Be happy! You now shouldn&apos;t need to change any path configurations, passwords etc. to run your web applications on your new PHP 5.4 stack! The actual migration from PHP 5.3 to 5.4 shouldn&apos;t be a problem, as there aren&apos;t that many compatibility issues. I didn&apos;t experience any PHP issues so far. I was rather concerned about just copying the MySQL files - but it worked like a charm and is definitely quicker than doing mysqldumps and loads on many big databases - UNLESS you don&apos;t have InnoDB tables in your databases. In this case better use mysqldump. In general it&apos;s a good idea to keep an eye on the mysql\error.log in the data directory. Good thing about this approach: you still have your old XAMPP installation at hand which you can reuse by simply renaming the two directories. Always be backed up!</content:encoded></item><item><title>URL ViewHelper and Child Routes in ZF2</title><link>https://windler.dev/blog/url-viewhelper-and-child-routes-in-zf2/</link><guid isPermaLink="true">https://windler.dev/blog/url-viewhelper-and-child-routes-in-zf2/</guid><description>In Zend Framework 2, the URL view helper ignores child routes unless you append the child route name to the parent with a slash, e.g. test/default.</description><pubDate>Thu, 22 Aug 2013 00:00:00 GMT</pubDate><content:encoded>Given this route configuration for a module I wanted to create an URL using the ViewHelper which directly links to an action of the Index Controller, e.g. To achieve this, it is important (and not so obvious, maybe) to append the name of the child route to the name of the parent route separated with a slash, e.g. otherwise the helper won&apos;t care about the child route and only link to /test. Tricky...</content:encoded></item><item><title>Use HeidiSQL with your vagrant box</title><link>https://windler.dev/blog/use-heidisql-with-your-vagrant-box/</link><guid isPermaLink="true">https://windler.dev/blog/use-heidisql-with-your-vagrant-box/</guid><description>Connect HeidiSQL to a local Vagrant VM via the MySQL SSH tunnel connection type, using the box SSH user, private key, and port 2222 by default.</description><pubDate>Tue, 02 Sep 2014 00:00:00 GMT</pubDate><content:encoded>I already discussed how to use HeidiSQL with a remote server in a former post. I now switched to use a local Vagrant VM instead of a remote VM. Of course I still wanted to use my beloved HeidiSQL. And it is - again - very easy! [ On the above page, you need to use the MySQL Username and Password. On the &quot;SSH tunnel&quot; tab we have to use the Username and Password for the SSH connection. I use a Private Key instead of a password, so I leave the password empty and specify the Private key file instead. My box is configured to use SSH port 2222 instead of the default port 22. This will most likely differ on other boxes, so it is worth to check this first if the connection is not possible. That&apos;s it :-)</content:encoded></item><item><title>How to use the MySQL GUI client HeidiSQL with a remote DB server</title><link>https://windler.dev/blog/use-the-mysql-gui-client-heidisql-with-a-remote-db-server/</link><guid isPermaLink="true">https://windler.dev/blog/use-the-mysql-gui-client-heidisql-with-a-remote-db-server/</guid><description>Connect HeidiSQL to a remote MySQL server over SSH using the MySQL (SSH tunnel) connection type, with the Settings and SSH tunnel tabs configured for 127.0.0.1.</description><pubDate>Mon, 27 Jan 2014 00:00:00 GMT</pubDate><content:encoded>Most IDEs nowadays work nicely with remote servers. But how about MySQL? phpMyAdmin is ok when you only have to use it once in a while, but a pain in the a... for everyday work. So I wondered if my favorite MySQL Client HeidiSQL (which has a slightly stupid name, but this shouldn&apos;t keep you off from trying it!) was able to help... ... and it was! You simply have to use the connection type &quot;MySQL (SSH tunnel)&quot; and set up the two tabs in the Connection Manager correctly: (thanks to Thomas Haller for the nice aggregation!) It simply works like a charm (given a decent internet connection, of course) and gives you all the comfort a lazy Windows user wants (and needs :-). Another tip from Thomas blog: if you experience problems with the connection, try to delete the path to the plink.exe. This will show the error messages which otherwise would be suppressed.</content:encoded></item><item><title>wget in Git Bash</title><link>https://windler.dev/blog/wget-in-git-bash/</link><guid isPermaLink="true">https://windler.dev/blog/wget-in-git-bash/</guid><description>How to add wget to Git Bash on Windows by extracting a MinGW build of wget.exe into a ~/bin folder that is already on the MSys PATH.</description><pubDate>Tue, 01 Jul 2014 00:00:00 GMT</pubDate><content:encoded>As reported, the link is currently dead (Database connection error), so I post the original text here: The msys shell that comes with a Windows install of Git has curl, which is an awesome little utility, but sometimes you want access to wget. The MinGW project on SourceForge has a build of wget ported to work with MinGW/MSys: download this archive, create a folder called in your home directory, and extract to that folder. Since should be in your MSys PATH (at least it was for me), this should let you run from any directory when using Git Bash. Credit to trasana.org’s page on creating a build environment for pointing me in the right direction Original post: http://www.kadamwhite.com/archives/2012/wget-in-git-bash Because sometimes you do need your wget ;-) Thanks Adam!</content:encoded></item><item><title>When curl is refusing to work as you expect...</title><link>https://windler.dev/blog/when-curl-is-refusing-to-work-as-you-expect/</link><guid isPermaLink="true">https://windler.dev/blog/when-curl-is-refusing-to-work-as-you-expect/</guid><description>When PHP curl returns an empty string but file_get_contents works, you likely forgot CURLOPT_FOLLOWLOCATION to follow redirects.</description><pubDate>Thu, 12 Dec 2013 00:00:00 GMT</pubDate><content:encoded>...you probably need to look at the many options curl offers. But let me start from the beginning. Problem: was returning an empty string, while worked fine. Now I&apos;m not the biggest fan of opening an URL using file\get\contents(), so I tried some of the many options and finally found the one that solved my problem.</content:encoded></item><item><title>Why adopt Green IT, and how?</title><link>https://windler.dev/blog/why-adopt-green-it-and-how/</link><guid isPermaLink="true">https://windler.dev/blog/why-adopt-green-it-and-how/</guid><description>Webinar with Scaleway on why and how to adopt Green IT now: EU regulations, FinOps overlap, and right-sizing infrastructure for monetary and ecological gains.</description><pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate><content:encoded>On October 26th, 2023, I had the honour of being part of the Webinar &quot;Why adopt Green IT, and how?&quot;, hosted by Scaleway. Together with Anne Currie, Director of Strategically Green and co-author of &quot;Building Green Software,&quot; Romane Clement, Co-Founder and CEO of the responsible digital design studio Ctrl S, and Simon Shillaker, Engineering Manager Serverless Computing at Scaleway, we explored the question of why companies should adopt Green IT, and how they could achieve it. These are some key takeaways from the session: Companies are still in the early stages of Green IT adoption, emphasising the need for immediate action. International regulations, especially from the EU, are on the horizon, making Green IT a necessity for companies in the near future. The journey to Green IT is a long one, so starting early is key. FinOps and Green IT intersect in many areas, and even simple changes like right-sizing IT infrastructure can yield substantial monetary and ecological benefits. A comprehensive, holistic approach is paramount for achieving truly sustainable IT operations. You can watch the full recording of the Webinar on YouTube. So sad that we had to stop it after just one hour, I&apos;m sure the discussion would have continued for hours. If you are interested in more talks about sustainability and Green IT from me, check out the Talks section of my website.</content:encoded></item><item><title>Why change code that works? Refactoring &amp; Technical Debt - Part 1</title><link>https://windler.dev/blog/why-change-code-that-works-on-refactoring-and-technical-debt-part-1/</link><guid isPermaLink="true">https://windler.dev/blog/why-change-code-that-works-on-refactoring-and-technical-debt-part-1/</guid><description>Part 1 of a series on refactoring and technical debt: why software ages, why the bus factor matters, and why refactoring is essential for any tech company.</description><pubDate>Thu, 12 Dec 2019 00:00:00 GMT</pubDate><content:encoded>Refactoring is the process of altering existing source code without changing the actual behaviour of the application. Or in other words: If we’ve done it right, no customer will see any changes at all. Now good luck explaining that to your boss! But seriously, why would anyone spend time and thus money rewriting software which is — from non-developer perspective — doing fine? In this first of three articles, I’ll explain why refactoring is essential for any tech company. In Part 2, I’ll suggest how you can deal with it in your daily routine. Finally, it will go more technical when I elaborate on the many manifestations of Technical Debt and talk about tools and processes to avoid accruing it (upcoming Part 3). Does software age? Would you board a plane from an airline which offers super cheat flights because they simply skipped all maintenance? So far they had no crashes, so all is fine! What could go wrong? I bet you want to see this happening before your next flight! — Photo by Pandu Agus Wismoyo on Unsplash Everyone is ok with the fact that machines need to be maintained. Parts wear off and get replaced, liquids need to get exchanged. It’s apparent because it’s common sense. A car has to go through the regular check-up, hardly anybody speaks against it. You can even see it, e.g. when the tires are worn off. But software is just bits &amp; bytes, so there’s nothing “real”, nothing tangible that could get old, or? Software is ageing as well, but differently. Of course it doesn’t wear off like machines. However, hardly any industry is changing faster than the IT. I’m working in the Web Development, and I admit that sometimes it’s super tough to keep up to date (yes, JavaScript, I’m looking at you!). Tech stacks, i.e. the software components applications are built upon, are changing rapidly and setting the pace. Keeping software up to date is vital if you plan to use it for longer than just a year. Otherwise, sooner or later, it will not work with current tech stacks anymore. There is an easy solution: just keep it running on the same tech stack with the same developers for the next couple of years! Well, no. Let me give you an example why this is no option: I once worked in a company where the essential software was quite old. It was maintainable only by very few people who were working with it for a long time already. You would hardly find new programmers for it, because nowadays nobody wants to learn the programming language the software was written in anymore. Now imagine that these guys quit or get seriously sick! This risk called the Bus factor: how many people have to get hit by a bus until the company is in trouble? Although a bit cynical, it describes the problem pretty well — the lower the factor, the bigger your problem, because you are relying on just a few specialists to run your business. A dedicated manager should care about this! Piling up the debt Every time we skip maintenance, or we postpone an unavoidable change on the code, we pile up Technical debt. Think of it as a loan from a “time bank”: not doing necessary work right now will buy you more time to work on new features. It is tempting, and sometimes it’s even the only chance to keep release schedules. Keep in mind that you just postpone it though. You have to pay it back. But why is that? Let’s think of an example. We realise that our application makes use of Anti-patterns (bad practices which software developers should never use, yet we frequently do) in some parts of the code. Instead of solving these issues directly, we decide not to touch it right now, since we have to keep deadlines. “We’ll fix that later” we reassure ourselves. Of course we don’t note that down anywhere, so this technical debt will be forgotten very soon. Aaaand it’s gone. And here’s the catch: lousy code tends to spread. Other developers who don’t know the application design so well or are less skilled might take over these pieces of code to use them elsewhere. That is not happening because of bad intention, but because they think it is ok to do so! Due to this so-called copy-paste or cargo-cult programming, an initially small problem is suddenly everywhere to be found in your application. But that’s not all yet. Imagine now the version of the programming language your application is written in will reach the end of life cycle at some point. It will not be developed further, not even security fixes. Updating your code is one thing, but usually you have to update the frameworks and libraries you use as well to make them work with the new language version. So in hindsight, we did it wrong in the beginning by not spending these few extra hours and fixing the root problem. The update now becomes especially hard to do because you have many lines of code to change instead just a few. In the long run, you might have to scrap the complete application because it became not maintainable anymore with a reasonable amount of effort. What makes Technical debt so threatening is the fact that it is usually hardly visible. It’s not like a bunch of bugs which cause unhappy customers. It’s not just lying around somewhere, sleeping peacefully if just left alone. It’s causing real harm by slowing down the development process. The more technical debt you accumulate in a project, the slower the development of features usually gets. This costs a lot of money. Like debt from a real bank, you have to pay interest on technical debt. By piling up technical debt, the development of new features will become harder over time: the interest on technical debt — Illustration by Carsten Windler using xkcdgraphs.com There are valid reasons for accumulating technical debt though, e.g. you are building a prototype, you want to A/B test a feature because you are not sure of its impact or you need to keep deadlines, e.g. to avoid lawsuits or angry customers The question is not if you have to pay back technical debts, but when. And how much interest you paid. If you decide to go with the debt, make sure it gets paid back as soon as possible! Otherwise, at some point, the application will become almost unmaintainable, and you’ve got another Legacy application in your portfolio. Down below, you’ll find some ideas on how to pay it back. Developers You got kicker tables, fruit baskets, free drinks and team events. Still, you’re wondering why developers are leaving, or your company is not able to acquire new talents? Maybe it’s time to have a look at your tech stack! Software developers need to evolve themselves; otherwise, we will get bored, since we’re curious by nature. As mentioned above the IT landscape is changing fast, continually introducing new technologies we have to learn about. We usually get unhappy when we have to only work on Legacy applications because we fear that we‘re falling behind the industry standards too much. And because it’s boring, of course. This dilemma is the emotional aspect of technical debt. If you want to keep your developers engaged, you have to accept the fact that they have to be trained regularly. Refactoring can be training as well. Companies spend a lot of money on training their employees, so why not think of refactoring as part of that training? Surely, if you’re only thinking short term, this will cost you money. However, if you take into account the hiring costs of developers, including the onboarding process and the time until a new developer can work productively on a project, this quickly pays off. Not to mention the knowledge that leaves your company, or the negative impact on the atmosphere in the development department if colleagues are leaving. Another important aspect is that Technical debt is causing frustration. Why? Because developers usually know that there are ways to do it better. We are not happy to deal with clumsy workflows when we know there are modern tools to ease processes, leaving us more time to do what we are being paid for - writing code! It is super demotivating to produce two new bugs when you just try to fix one, just because the application you are working on is so complex that side-effects can not be predicted. Missing or outdated documentation and small test coverage of the code make each new release like playing the lottery. In the end, it’s a win-win-situation (if not even a win-win-win). You keep (1) your developers trained, up-to-date and happy, while you ensure that (2) your application will last the next years and (3) your company stays competitive in the developer market. Wow, why would you not like to do that? Security There will always be people who try to hack your application. Be it for fun, fame or profit. Exploited security holes will cost your company a lot of money. It can even endanger your whole business when your customers lose trust in your company. The problem: applications often make use of frameworks, packages or libraries as well. That code is written and maintained by 3rd parties — updating those to newer versions often close security holes. Best-case the update is just a matter of downloading the latest release. However, there will be the day when the next major version of a library is released and comes with breaking changes. You can’t update to the next version anymore without changing existing code. At this point, refactoring is necessary to keep the 3rd party code in your application up to date. There are ways to reduce the amount of work required to do the update, yet that takes more time beforehand, which is often not spend. Of course also our code has security holes. Usually a lot more than we want to admit. There are (commercial) tools that help scanning your codebase for security problems. But someone has to fix the findings eventually. Sometimes it’s just a matter of adding a couple of lines of code, but often enough it requires significant code changes aka refactoring. Code requires refactoring to be kept at least somewhat secure. You can take the risk and go on with all those open security holes, or you let them get fixed. It’s a risk management decision. Performance Parts of code which are no longer necessary are slowing down an application either by increasing the execution time or by increasing the amount of ../../../assets that the browser needs to download. If you don’t take care of it regularly, the application will eventually become bloated and cluttered. Probably you are no longer using some 3rd party tools, yet they still get downloaded by every users browser since they were never removed from your source code. There are many other ways to improve the performance, like replacing slow technologies with newer and often faster ones. Since we (hopefully) all know that a slow website is still one of the main factors which affects the conversion rate negatively, we should tackle that immediately. Another performance aspect is not affecting the customer, yet still causing high costs: internal development speed. If you refactor existing workflows to make them faster or require less manual work, you will speed up the development in general. Last but not least, removing dead or improving poorly written code will make the application more straightforward to understand for newbies and yourself. Stay critical After all these important points, let&apos;s not forget the other extreme: we should not refactor just because we can. Developers will always find reasons to rewrite existing code. Sometimes I feel the urge to refactor my code I wrote three weeks ago, just because it does not feel right anymore. Uncontrolled refactoring can easily lead to another extreme: Overengineering. Your software gets so well designed that the average developer will not be able to grasp it. It might be right according to the books or a recent blog post, but not everybody in your team is a coding ninja and will understand it so quickly. Done is better than perfect. There are very valid reasons to strive for making code as &quot;good&quot; as possible (how to measure &quot;good&quot; will be covered in Part 3 of this series). For example, if you are working on an Open Source project, where you want to make sure that many people want to participate. However, this high level of quality requires a lot of time. As company, you might need to decide to work on a bit lower level. A feature or bugfix that takes significantly longer because of refactoring might in the end cost the company more (e.g. because of lost revenue) than the value we get from the refactoring itself. In Part 2, I will cover this topic more in depth. Conclusion &amp; Outlook Refactoring is necessary to keep your software alive and secure while maintaining performance. It also serves as a motivator to keep developers up-to-date and engaged. That alone should be enough arguments to make refactoring an essential part of the daily development work. But since technical debt usually remains hidden, it’s often not paid back fast enough, so it piles up like an invisible mountain. In the next part of this article I&apos;ll suggest a way to solve this problem. Hang on!</content:encoded></item><item><title>Why change code that works? Refactoring &amp; Technical Debt - Part 2</title><link>https://windler.dev/blog/why-change-code-that-works-on-refactoring-and-technical-debt-part-2/</link><guid isPermaLink="true">https://windler.dev/blog/why-change-code-that-works-on-refactoring-and-technical-debt-part-2/</guid><description>Part 2 on refactoring and technical debt: a 3-step plan to reveal, analyse, and pay back technical debt as part of daily work, not as a one-time project.</description><pubDate>Tue, 17 Dec 2019 00:00:00 GMT</pubDate><content:encoded>In Part 1 of this article, I talked about how Technical Debt negatively affects many aspects of Software Development. All right, so what are we still talking about — let’s roll up our sleeves and refactor the heck out of it, shouldn&apos;t we!? Refactoring is an ongoing process. It will never be done. I think the first step is to realise that refactoring is not a task that has a clear beginning and a definite end. It’s not a one-time project! It is part of our daily work, and it should not even be the question if you should do it. Instead, think about how much time to spend on it besides the ongoing feature development, and where to start. Not sure how to do that? Let me propose a simple 3-step plan than can help tackle technical debt. Dealing with technical debt in 3 easy steps — Illustration by Carsten Windler Step 1: Reveal &amp; Document Do you know what the biggest pain-points in your software are? Usually, your developers have a good understanding of the problems in their projects, but how to make everyone (including the management) aware of it? First of all, make sure that these issues get documented. I know this sounds very obvious, but if you don’t do it yet, define a workflow and make it happen! For example, ask your developers to write a ticket for each piece of technical debt they think they encountered. That could e.g. be the usage of the already mentioned anti-patterns or the needed update to a new version of a substantial library that was just released. Technical debt not necessarily lies only in your code. Wrong architectural decisions can massively decrease the performance of your team. How to deal with those? They too have to get written down somewhere at first, so a ticket is a good start for the big ones as well. We will deal with those in the next step a bit more. The above items go into the backlog (a list of tasks that your development team is planning to implement). Agree on a way to tag or organise technical debt tickets in the same way, so you can find them easily later. Great, now you have the problems easily accessible for everyone. We’re getting there. Step 2: Analyse &amp; Prioritise Now as you have a bunch of tickets - how do you decide what to refactor next? How do you know what value the refactoring brings to your project? I&apos;d suggest to start with setting up regular sessions (often called groomings), where the development team evaluates the issues identified as technical debt in step 1. If you already have groomings in place, the debt tickets will fit in perfectly. During these sessions, your team should assess both the needed effort and the potential value of each item. While effort is — to some extent — relatively easy to predict, what about the value? This can end up in lengthy discussions. Let’s assume there is this piece of business logic that is working just fine for years. It’s there, has no external dependencies (so updates are no problem), is battle-tested and after all the time pretty much bug-free. But still, our code quality analysers, i.e. tools which are scanning our source code relentlessly for violations to modern coding standards, complain that the code, well, sucks! Sure, it’s super ugly and outdated from an academic point of view. But what value do we add by refactoring it to make it apply to rules which were introduced long after the code was written? In my opinion, this should be one of the last pieces of code to be touched! Of course, there is value in making code easier to understand for developers. But the risk of introducing new bugs is higher than the benefit of having clean code which, in the end, only does the same thing. This risk is exceptionally high if your application is not covered with automated tests. And even if there are automated tests, these might not test every little part of the logic or are just not testing it properly. Value is not only about money earned, it’s also about reducing effort — Photo by Pixabay on Pexels Figuring out the real business value, i.e. an equivalent in money for paying back technical debt, is pretty tricky and would be surely worth an article of its own. Reducing technical debt is more about lowering effort than earning money, but with that extra level of uncertainty. Good news: we don’t even have to go that far! Start simple and use T-Shirt sizes (e.g. from XXS to XXL) to have rough estimations for both business value and effort. While it is not easy to define the specific value of a refactoring task, it’s usually easier to put them into relation. Which one is bigger than the other? Which one brings more value? You then can identify which tasks are the most beneficial - you don’t have to put labels with concrete numbers on it at all. To visualise it even better, arrange all evaluated tasks in a value-effort-matrix that you may already know from Lean Development: Illustration by Carsten Windler based on a blog post by Pavel Kukhnavets A task which is is done quickly (low effort) but brings us a lot of benefits (high business value) is a Quick Win. Let&apos;s do these first! Tasks of significant size (high effort) but with lower impact on our revenue (low business value) are Time Sinks, which should be avoided. Keep the Maybes in your backlog, but with lower priority. Often enough, these little things might not gain much value, but are still somewhat annoying for the developer. Fix them when you got some time left, it’s often worth it. Big bets often are structural problems hidden within your application architecture or even your whole infrastructure. Groomings are not enough here. Do workshops where your developers can put their heads together instead and come up with solutions. It’s nothing you can fix by doing some refactoring tickets now and then, it will require a new project and is thus out of scope for this 3-step-plan. That doesn’t mean you should not do them — it’s quite the contrary. You just can’t solve these items in your daily routine. Step 3: Payback Just tracking tickets in lists and drawing nifty graphs won’t help if there is no possibility to pay back the debt. So now it’s time to think about how much effort your team can, or better, should spend on it! Finding the right balance between feature delivery and refactoring is crucial. Refactoring alone will not convince your users to use your application and pay the bills in the end. The ratio between features and refactoring can and should change over time, depending on your current situation; remember those nasty deadlines! Now comes the tricky part: The Business or the Product Management or whoever is setting the roadmap of features for your project surely won&apos;t sacrifice development time so easily. Of course, the notion of refactoring being a sacrifice is wrong. You can use the arguments from Part 1 to convince them. If the business cares about to longevity of the application, they should understand. You can also come up with a deal: the developers get some time to work on the most significant problems with priority (like a Refactoring sprint, for example), and afterwards the focus is on delivering some cool new features again. Lastly, at some point you want to re-assess older refactoring tickets every now and then. Maybe your team got more experienced and would see things differently now, or the focus shifted, and you now realise that considerable changes in your architecture are more worth it than you initially thought. Reality Check That sounds all nice and not too hard to implement, but will it really work? Well, initiating the process might take a bit, because the developers have to accept it. It&apos;s one thing to complain about technical debt (that is usually very easy), but working on a structured approach to solve it means extra effort for them. Writing tickets is surely not the biggest fun for developers. You probably have to chase it a little bit. You have to remind them, e.g. by looking at the actual amount of technical debt tickets in your backlog together regularly. If the tickets have been tagged properly, it&apos;s usually simple to get an overview, and you can check the progress. If there was none because no tickets have been added, remind your fellow developers kindly to write them. Secondly, if the Business won&apos;t give you enough time for bigger refactoring tasks, all you can do is document the debt, raise it again and again and wait for the moment when everything goes down the drain. In the end, it&apos;s a Management decision. If good arguments won&apos;t help, they have to learn it the hard way. Let me be clear: I know how hard it can be to integrate all this into the daily work! It doesn’t mean you shouldn’t try it, though. Conclusion &amp; Outlook Keep in mind that refactoring is an ongoing process and don’t stop at some point where you think you did enough. The simple 3-step process I explained above might help you, maybe even if you take just parts out of it so it fits to your company. It surely is more overhead, but I think it&apos;s worth it. You can&apos;t solve a problem which you don&apos;t fully understand or oversee. Our goal is to make the technical debt tangible. Probably you don’t even need to go full ticket mode all the time. Let the developers agree on the boy scout rule: Leave the code in better shape than you found it! While working on new features, have a look to the left and the right and fix all these little things immediately. The actual task takes a bit longer, but over time those minor improvements will help a lot, and don’t require any management overhead. In the end, every company has to earn money. It’s crucial to find the balance between maintenance and feature development which suits both business and technical needs. In Part 3 (upcoming) I&apos;ll get more technical, when I talk about the many manifestations of Technical Debt, and how to avoid accruing it. Stay tuned!</content:encoded></item><item><title>Why PHPs Carbon is bad for the climate</title><link>https://windler.dev/blog/why-phps-carbon-is-bad-for-the-climate/</link><guid isPermaLink="true">https://windler.dev/blog/why-phps-carbon-is-bad-for-the-climate/</guid><description>The nesbot/carbon package is installed 200k times a day but slow and bloated next to PHP native date functions, causing avoidable carbon emissions at scale.</description><pubDate>Thu, 20 Apr 2023 00:00:00 GMT</pubDate><content:encoded>Carbon is bad for the climate. Thus, Green IT aims to reduce the impact of IT on the climate as much as possible by reducing the emissions. While we can’t write software that does not consume any electricity, we should use it wisely. This is especially true for software that is used a lot. With approx. 200,000 Installations per day, nesbot/carbon is surely one of the most used Composer packages today. It is packed with features and offers translations for almost every language you could think of. But it’s feature-richness and popularity comes with a price: a vast amount of, well, carbon emissions it causes. Oh, the irony. Carbon, unfortunately, is slow and bloated. Allow me to explain what I mean. Carbon is slow PHP has its own date-related objects and functions. Their usage and syntax might not be as streamlined as Carbons API, yet they often enough do the job just right. To compare the performance of the PHP-native functions with the Carbon counterparts, I used PHPBench. You can find the benchmarks in my repository. Please note that I didn’t pick any particularly bad examples on purpose, just some everyday use cases. Example 1: Subtract 30 days First simple scenario: subtract 30 days from the current time, and return the timestamp. The PHPBench file looks like this: Let&apos;s have a look at the results. Of course, the absolute values will vary, but we are more interested in the relations. The mode column indicates the Microseconds (μs) it took to run the Benchmark on average: Both PHP-native strtotime function and the DateTime class are not much harder to use than the pendant of Carbon, but significantly faster. It takes Carbon at least 5 times and up to almost 10 times as long for the same result. Example 2: Date format Now, let&apos;s generate a Date string from the current timestamp. Same here - the date\-Function works great, and beats Carbon easily. Example 3: Diff The last example is about getting to know the difference between two dates. Admittedly, Carbon&apos;s API is much nicer to use here, but is it worth to be 10 times slower? What do the results tell us? As you can see, Carbon always gets outperformed by native PHP functions. This is not really surprising, since the native functions are always faster. So at least, Carbon should give us a much better coding experience to compensate for the poorer performance. This is a matter of taste, I&apos;d argue that mostly the PHP-native way is not much different. But does it really matter if it takes 1 microsecond or 9? If it occurs only a few times during a request, surely not - unless you can live with the fact that the way you chose is 9 times slower for no good reason. Yet, if you use Carbon in, let’s say, a CSV import function for big data loads, it will make a difference and piles up to wasted seconds. So if you can&apos;t live without Carbon, at least consider not using it in performance critical parts of your application. Improvements The instantiation of a Carbon object is quite time-consuming, since with 3 MB in memory, it is pretty big. You can save a lot of execution time if you create the instance once, and reuse it, like in the following example: What can we learn from these results? Reusing an instance definitely pays off! For the same result, the execution time varies between 3ms and 40ms (Please note that the results are in Milliseconds (ms) and not Microseconds (μs) anymore!) This is over 13 times the difference! And yes, 40ms makes a difference, if added to an API response, for example. It also shows that doing a quick check of the performance of your chosen solution pays off as well. Especially when you are working on performance-critical parts of your code, consider and test alternatives. From an environmental perspective, Carbon just consumes unnecessary energy. How reliable are these tests? Finally, a word on the methodology chosen: PHPBench can only tell you the time needed on the machine where the tests were performed. The tests in this post were run on a Macbook Pro M1 and PHP 8.1.13. If you run the tests on your machine, they will most likely show you different results. I tested them on different machines as well, and, of course, ended up with different results. Yet, one thing was always the same: Carbon was always the slowest option. Carbon is bloated But Carbon is not only slow, it is bloated as well. As we saw above, a Carbon instance alone consumes quite some memory. It doesn&apos;t stop here. Once downloaded, Carbon uses up approx. 5 MB on your local disk. Not bad for a DateTime API, right? Let’s have a closer look. You’ll quickly identify a folder called Lang which alone weights 3.5 MB. This folder holds over 180 localization files. This is, on the one hand, pretty great because it brings the worldwide community closer together. It comes with a serious cost, though. Most likely, your application will not support all these languages. A good amount of data in this directory is useless for you, and many others. Let’s assume an average project only uses 500kb of localization data, which is already a lot. This means that 3 MB has been downloaded in vain. Let&apos;s do the math Doesn’t sound much? Well, as mentioned, Carbon (the package) has approx. 200,000 daily(!) installs, which in turn means that 600,000 MB (200,000 × 3 MB) gets downloaded every day. This equals 585 GB per day and sums up to 213,687 GB (200,000 × 3 MB × 365) or 208 TB per year - without serving a purpose. Assuming an energy consumption of 0.81 kWh per GB of data traffic, and 442 g CO2e per kWh (using the Sustainable Web Design methodology), this sums up to over 70 tonnes (!) of carbon (the gas) per year that is caused only by these unnecessary data transfers of language files. 213,867 GB × 0.81 kWh/GB = 173,242 kWh 173,086 kWh × 442 gCO2e/kWh = 76,568,730 gCO2e 76,568,730 gCO2e / 1000 / 1000 = 76.5 tCO2e / Year Isn’t that a bit much of carbon (both the gas, and the package) wasted? To be fair, the actual mileage will vary, as we do a lot of assumptions here. Estimating or even measuring carbon emissions of Software is challenging to say the least. Yet, it should show that software does have a noticeable impact on the climate. And this is only one little package amongst many. The same thinking led the creator of the also well known fzaninotto/Faker package to abandon its creation. It would help a lot of the maintainers of Carbon could refactor the library to separate the localization files from the code. I can&apos;t say how much effort this would cause, both regarding refactoring and future maintenance, but definitely it would be a great step towards sustainability. Conclusion With the knowledge we gathered above, my conclusion is: avoid the Carbon package if you can. Not because it is not good (it is well written and offers a lot of functionality), but because we pay a high price for a bit of comfort. Or better, the environment and our users pay the price. Often enough, PHP will do the job. If you still need Carbon, at least consider using it only if really necessary, and try to avoid continuous instantiation – especially in parts of your application which are executed a lot. What do you think? Is Carbon still worth it?</content:encoded></item><item><title>Migrating from Wordpress to Astro</title><link>https://windler.dev/blog/wordpress-to-astro-migration/</link><guid isPermaLink="true">https://windler.dev/blog/wordpress-to-astro-migration/</guid><description>How and why I migrated my personal website from WordPress to a static Astro site, and what I learned along the way.</description><pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate><content:encoded>The first &quot;professional&quot; website I ever created - a small info page for my fathers business - was purely HTML and CSS. Hand-written in a text editor without any autocomplete or other support. After many years operating on WordPress, this website is now also a purely static page, built upon Astro. In this blog post, I explain the why and the how. How it started When I created my first personal website, a blog under my old domain carstenwindler.de many years ago, it was clear to me from the very beginning that I had to use some sort of content management system. Simply because that&apos;s what I was proficient with back then, having worked as a freelancer mostly with Typo3, that notorious Open-Source-CMS monster. WordPress back then was already strong, providing good-enough standard templates, and a rich collection of plugins. Yeah, the code quality ... WordPress has never been the best example of good PHP code, and although we can claim that PHP still drives most sites of the internet, I think it&apos;s also true that WordPress, and particularly the plugins, are partly responsible for the terrible reputation of this language. I, for example, still get sweaty palms when I think of the code of the WooCommerce shop from back in the day, a plugin I had to deal with for a small side project. But hey, WordPress was easy enough to get my first results up and running, and that goal was achieved very well. How it went Over time, the whole ecosystem became enshittified (greetings to Cory Doctorow). More and more plugins became commercial, and while I support paying money for software, I&apos;m no fan of the subscription model. The constant fear of being hacked if I don&apos;t check and update my installation every other day was annoying. Finally,Project Gutenberg, this - for me - extremely annoying editor, was the final piece that led to my decision to leave WordPress. I just wanted to write, not to maintain another web app. Something I do enough in my day job. Static websites also tend to have a smaller carbon footprint, since content is only generated once, unlike dynamic pages (ok, caching, yes I know, it all &quot;depends&quot;). A website generated by a static website generator sounded perfect for my very limited needs. In between, I&apos;ve fallen in love with Markdown, so the goal was clear: migration to Hugo! Mostly because it was the only tool of that kind that I knew of at that moment. It took me a couple of years, though, because I never really found the time. Or the motivation. Until LLMs entered the game. Current state My experience with AI-assisted coding finally made me give it another try. I tried Astro.js instead of Hugo, though, since it was technically closer to the stack I&apos;m used too. After a quick PoC, it was clear to me that my goal was finally achievable with an overseeable amount of time and effort. So I devised a masterful plan: Excerpt all content from my old WordPress blog Migrate that content to Markdown Set up the new page with Astro AI-magic Success WordPress to Markdown Looks like I was not the only person with the goal of moving away from WordPress, so I, e.g., came across a tool which exported my blog posts and pages into ok-ish Markdown, plus kept all media assets organized. Yay, 2 steps at once, thanks a lot to Lonekorean! It&apos;s FOSS! Surely the results were not perfect but good enough to continue. Since my blog is relatively small, it took me a couple of LLM-assisted sessions to clean up most of the pages and posts. The Astro project Setting up Astro with AI is pretty straight forward, but of course you have to still know what you are doing, and especially probably the hardest part, know what you actually want! Eventually, I ended up using the Astro starter kit as theme and these packages: @astrojs/markdown-remark @astrojs/mdx @astrojs/rss @astrojs/sitemap @jdevalk/astro-seo-graph @jdevalk/seo-graph-core astro astro-pagefind pagefind reading-time satori sharp MDX is basically Markdown with embedded JavaScript. Sounds scary, I know. I actually rather keep any logic out of my Markdown files, but sometimes it&apos;s just helpful to have the extra flexibility. Other than that, I don&apos;t need much. Sitemaps, RSS feeds, page search, and so on are generated once during the build. For page insights, I&apos;m using Matomo.Privacy first, no cookies, no user tracking, or anything like that on my site, just basic JavaScript for site statistics. SEO considerations Of course I also wanted a fast and technically clean solution. Visually appealing, but lightweight. SEO/GEO-friendly. Minimal JavaScript. You can&apos;t go faster than static HTML, so the page load part was more or less solved. I&apos;m no frontend developer, but with AI I was able to quickly solve some of the issues reported by Lighthouse (some are still to go, I know). Using an SEO skill from Yoast turned my blog into an SEO wonderland (or at least that&apos;s what&apos;s being promised). I&apos;m not fully done here as well; right now I first want to deliver some more content, since I haven&apos;t been that active lately, then iterate on the remaining issues. I will take some time to see the actual results. Of course, I&apos;m not naive when it comes to dropping visitor rates caused by AI, e.g. because of the AI-generated summaries, so I have to take that into account as well. Hosting It shouldn&apos;t be that difficult to find a hoster for a bunch of static files; however, I had some requirements: my page must be hosted in Europe and using energy from renewables, since I want to keep my digital footprint low. I still have an account at a small German shared hoster, and right now, I&apos;m just using plain old SFTP to update my page. It feels like time travel back to medieval times, and not even being able to use rsync is a bit clumsy. For now, it works, but I guess at some point I need to find an alternative. &quot;Why don&apos;t you just use GitHub Pages?&quot;, you say? I&apos;m glad you asked: Because I want to get away from GitHub. Code repository The day GitHub was bought by Microsoft, I made the decision to at least try to find alternatives one day. And oh boy, that is not easy. I could move to GitLab, and that still is my backup plan. However, it is an US company, too, so it bears some risk. And I was curious about other alternatives. One interesting project surely is Forgejo, a self-hosted GitHub clone software forge. I didn&apos;t want to host my own instance, though, so I gave Codeberg, a Forgejo instance hosted by a German non-profit organization. Codeberg also offers hosting for static pages (https://codeberg.page/) and CI/CD. I haven&apos;t really explored both yet, but will do so soon. Was it worth it? I&apos;m really happy with the results, given the time I spent on it. Surely I always see many more things I could do on my blog (and my issues list on Codeberg is long...), but after all, it is just a small, unimportant website. Not having to worry about security issues, and being able to use Markdown for writing is such a relief. I have full control about the page content and don&apos;t have to deal with content blocks and such. The page speed is amazing, although that was to be expected due to the nature of a static website.</content:encoded></item></channel></rss>