[{"content":"It all started quite innocently, during a NixOS meetup last year. A friend of mine (Hello Theo!) showed off his new SenseCap Tracker T1000E running Meshtastic, and that was it ! My curiosity was well and truly piqued. I have been exploring the world of LoRa and \u0026ldquo;off-grid\u0026rdquo; networks ever since, and what a journey it has been. I thought it was a good time to write down my experiences, so here\u0026rsquo;s a look at how a curiosity turned into some kind of full-blown obsession.\nDipping My Toes into Meshtastic # To get the ball rolling, I decided to start with Meshtastic, an open-source \u0026ldquo;off-grid\u0026rdquo; messaging platform for LoRa networks. It seemed like the perfect entry point. I picked up a pair of WisMesh Tags just to run some basic tests and see what all the fuss was about. During a trip to Italy, I was so impressed to see that I could communicate with my family from the plane without any trouble. I was also receiving signals from other Meshtastic users on the ground. Such a small device, yet it could reach so far. I was hooked. The WisMesh Tag worked brilliantly, but as is always the way with these things, I immediately wanted more range and better network coverage.\nBuilding the Solar Relay Node # Delivery unboxing time! Yay! If I was going to do this properly, I needed to extend the Meshtastic network. This meant gathering some hardware to build my own relay node. Here\u0026rsquo;s the kit I ended up putting together:\nA MikroTik 868 Omni Antenna A RAK4631 core module sitting nicely on a RAK19003 base board An environment sensor RAK1906 to monitor the temperature, humidity, pressure, and air quality A 3000mAh battery A Unify enclosure with a built-in solar panel A window suction mount A RAK19003 and its RAK4631 core module, minimal and very efficient setup After some tinkering, I had my Meshtastic relay up and running. I mounted it on my Velux window with the window suction mount, where it is happily ticking away 24/7\u0026hellip; well, mostly\u0026hellip; Belgium weather has other ideas :)\nThe meshtastic node under construction The Belgian weather is the real bottleneck here. On days with decent sunshine, it is flawless and runs for days. But as anyone living in Belgium will tell you, those days are not exactly guaranteed. The 3000mAh battery is just a bit too small to bridge the gap during our gloomy stretches, so the node occasionally drops offline from a lack of light. Worry not because an upgrade to a beefy 10000mAh battery is on my to-do list in the upcoming days\u0026hellip; but let\u0026rsquo;s be honest, given the crazy heatwaves we have been experiencing in Belgium lately, there hasn\u0026rsquo;t been much of a problem. The node has been running flawlessly for weeks now.\nThe Meshtastic node mounted on the Velux window, on a very gloomy day Falling into the Reticulum Abyss # As if Meshtastic wasn\u0026rsquo;t enough to keep me occupied, I stumbled upon the Reticulum project. And\u0026hellip; oh boy, that was an absolute game-changer. It is a proper bottomless pit of fascinating tech.\nWhile Meshtastic is a great project, it is a bit limited in its scope. Reticulum, on the other hand, is a full-fledged mesh networking stack that can be used to build all sorts of applications. For example, Reticulum can be used to provide the same feature set as Meshtastic. The possibilities are endless, and I am having a blast exploring them.\nI have been buying and mounting devices left, right, and centre, and running tests everywhere I can. It has been a fascinating process to understand how everything routes and communicates.\nA RAK19003, two RAK19007 and a RAK13800 module (ethernet) After wrapping my head around the basics, the concepts, and the terminology, I finally managed to set up a small Reticulum network at home.\nAfter that, I started investigating how to make a public node that would contribute to the wider network. To do that, a couple of requirements had to be met to align with NixOS standards and practices, as further explained in the next section.\nIn practice, anyone can run a Reticulum node, and no specific hardware is required: running the rnsd daemon with a proper configuration is enough to contribute to the network. Once you have a node up and running, you can also run the lxmd daemon (from the LXMF project) to provide a local messaging service for your Reticulum network. This allows you to send and receive messages from other nodes. The lxmd daemon is also a great way to test your setup and confirm everything is working properly.\nAs if all of this were not enough, I decided to build a public LoRa and TCP gateway to contribute to the Reticulum network. Reticulum is a mesh network after all, and the more nodes there are, the better the network becomes! :D\nSo I decided to buy a new set of things:\nA RAK4631 core module sitting on a RAK19007 base board An ethernet module RAK13800 and its PoE module RAK19018 An environment sensor RAK1906 to monitor the temperature, humidity, pressure and air quality A NOR flash module RAK15001 required for microReticulum A Unify enclosure without solar panel A couple of 10000mAh batteries to increase the uptime of the node during the gloomy Belgian weather Another window suction mount. Actually, I have 2 Velux windows, so I can keep 2 nodes up and running at the same time: the more, the merrier! I initially bought these devices because I had seen ethernet support land in a PR. Sadly, the PR has been closed and I am unable to use the ethernet module with the most up-to-date firmware as of today. I hope proper ethernet support lands in microReticulum one day, but for now I am stuck using the USB serial interface to connect to my node.\nI love the Reticulum project, but I am a bit sad to see so much fragmentation in its ecosystem. There are many implementations of Reticulum itself, and many of RNode, the Reticulum firmware to install on real hardware. Unlike Meshtastic, there is no central repository or place to find all the different implementations of RNode. I hope that in the future, the Reticulum project will be able to unify its ecosystem and provide a more cohesive experience for users.\nReticulum works very differently from Meshtastic, and it is a bit more complex to set up because the physical device does not own the user identity; instead, the identity is generated by the Reticulum software itself running on your device. This paradigm shift is great, but it requires a bit more work to set up. As an example, it is harder to set up an autonomous RNode on your roof simply because a RNode alone is not very useful without a running rnsd (Reticulum Network Stack daemon) operating it.\nThat said, there is an alternative firmware called microReticulum, which lets you run an autonomous RNode on a microcontroller without relying on an external rnsd instance. It is a promising approach, my favorite, and it is the one I use by default. Once deployed on your hardware, it removes the need for a separate daemon, because the Reticulum stack runs directly on the chip. This is similar in spirit to how Meshtastic works, though the architecture is not exactly the same. A microReticulum-powered node can operate in host-controlled mode like a regular RNode, but it can also be switched to transport mode. In transport mode, it runs the embedded microReticulum stack directly on the microcontroller and autonomously routes packets for other Reticulum nodes on the LoRa mesh.\nOne of the biggest frustrations I had was seeing a bit of smoke come out of one of my RAK boards just after plugging in the new 10000mAh battery. I was so excited to see my Reticulum node up and running that I did not check the polarity of the battery, a rookie mistake. Needless to say, I learned my lesson.\nSo, after a broken board, a few other broken expectations and attempts, a lot of tinkering\u0026hellip; I finally managed to get my Reticulum node up and running.\nThe Reticulum roof node being assembled with a 10000mAh battery The roof node acts as a transport node on the LoRa mesh and communicates with another node at home, connected to a local server over USB. That home server is then bridged to the internet, allowing me to seamlessly link the LoRa mesh with the wider Reticulum network.\nA RAK19007 with the RAK4631, RAK13800, RAK19018, RAK1906, RAK15001 modules On top of exploring the arcana of this project and tinkering with the hardware, I have also been exploring the various applications that can be used to communicate over Reticulum. I have been testing Columba, Ratspeak, Reticulum Mobile App, Retichat, Sideband, Nomadnet, Meshchat, MeshchatX, \u0026hellip; Most of these implementations use the Reticulum reference implementation in Python, and I can\u0026rsquo;t wait to see better alternatives in the future. Not that Python is bad (erm erm!), I believe it is a great language for prototyping, but I also think that better implementations in other languages will be needed to make Reticulum much more efficient, especially on smartphones.\nMy wish list for the future of Reticulum is a more unified ecosystem: an alternative implementation in a compiled language, a more coherent set of applications for communicating over Reticulum, and a clearer path for contributing to the core project. Open source should give users the freedom to choose the implementation that best suits their needs, but not at the expense of the project\u0026rsquo;s overall health. I do not really know the details behind why the GitHub repository for Reticulum is no longer open to contributions, but I hope that, in the future, it will become easier to contribute to the project and help it grow while keeping the core stable, secure, and aligned with the vision of its original author, Mark Qvist.\nI also hope for broader hardware support, especially for the RAK13800 ethernet module and the RAK1906 environment sensor. I hope the microReticulum project will continue to grow and evolve into an even more robust and reliable implementation of Reticulum for microcontrollers.\nGiving Back # I have always believed that if you are going to use open-source projects heavily, you ought to give something back when you can. Since NixOS is my daily driver, I focused my efforts there in the Nix ecosystem.\nFor Meshtastic, I introduced firmware builds. It is also now entirely possible to build the firmware straight from source (#466509).\nFor Reticulum, the work is ongoing but very exciting. I currently have two new modules (rnsd and lxmd) in the works (#530406). Introducing these modules required the introduction of a new formatter for Nix code so that the configuration files for Reticulum (using configobj format) could be generated from Nix code. It was a very exciting development, as it was the first time I had to write a custom formatter for Nix code. Lastly, I have also contributed by adding various tools and implementations of Reticulum like Reticulated, Leviculum, Reticulum-go, rs-reticulum, rs-lxmf, lxmf-rs, rns-proxy, reticulum-group-chat, \u0026hellip;\nWhat\u0026rsquo;s Next? # Honestly, I am having the time of my life messing about with all this. There is always a new device to test, a new configuration to try, a new RNode firmware version to deploy\u0026hellip; or another bit of code to package in Nix.\nIf you are on the fence about getting into LoRa, consider this your sign to just go for it. Grab a couple of nodes (it is not that expensive\u0026hellip; erm, wait!), set them up, and see where the rabbit hole takes you!\n","date":"8 July 2026","externalUrl":null,"permalink":"/2026/down-the-lorabbit-hole-from-meshtastic-to-reticulum/","section":"Posts","summary":"","title":"Down the LoRa(bbit) Hole: From Meshtastic to Reticulum","type":"posts"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/hardware/","section":"Tags","summary":"","title":"Hardware","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/lora/","section":"Tags","summary":"","title":"Lora","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/lxmf/","section":"Tags","summary":"","title":"Lxmf","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/meshtastic/","section":"Tags","summary":"","title":"Meshtastic","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/nix/","section":"Tags","summary":"","title":"Nix","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/","section":"Not A Number","summary":"","title":"Not A Number","type":"page"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/off-grid-network/","section":"Tags","summary":"","title":"Off-Grid Network","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/reticulum/","section":"Tags","summary":"","title":"Reticulum","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/rnode/","section":"Tags","summary":"","title":"Rnode","type":"tags"},{"content":"","date":"8 July 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/community/","section":"Tags","summary":"","title":"Community","type":"tags"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open-Source","type":"tags"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/reproducibility/","section":"Tags","summary":"","title":"Reproducibility","type":"tags"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/retrospective/","section":"Tags","summary":"","title":"Retrospective","type":"tags"},{"content":"2025 was not a year of rupture like 2024. It was something else: a year of consolidation, clarification, and, at times, quiet stubbornness.\nMany of the transitions that had started the year before continued to unfold. I was still working at the intersection of software engineering, reproducibility, open source, and public-sector IT, but this year gave me more space to connect those threads together. It also gave me more reasons to do so. The more I looked around, the more I felt the same thing over and over again: complexity is still wildly underestimated as a source of cost, fragility, and institutional dysfunction.\nSo, in one way or another, a lot of my year revolved around pushing in the opposite direction: making things clearer, smaller, more reproducible, more explicit, and hopefully a bit more sane.\nReproducibility, still not optional # If there is one theme that continued to shape my year more than any other, it was reproducibility.\nAfter finishing my Master\u0026rsquo;s thesis on reproducibility in software engineering in 2024, I had the opportunity in 2025 to continue turning that work into something more practical and more transmissible. One of the real highlights of the year was contributing to teaching activities at the University of Mons and helping introduce students to the topic more formally.\nThat meant a lot to me.\nReproducibility is one of those concepts that sounds almost too obvious to defend. Of course we should be able to rebuild what we build and what we ship. Of course environments should be consistent. Of course deployments should be predictable. Of course results should be verifiable. And yet, in practice, much of the software industry still behaves as though these were optional luxuries rather than the foundations of trustworthy engineering.\nThe more I work on the subject, the more I think the problem is not technical first. It is cultural.\nReproducibility demands discipline, humility, and delayed gratification. It asks teams to invest effort now so that someone, perhaps someone else, can understand, verify, maintain, or rebuild the system later. That is not always rewarded. In many environments, the incentives still favour speed, improvisation, and the comforting illusion that \u0026ldquo;it works on my machine\u0026rdquo; is close enough to success.\nPicture of the office lab when reproducibility is treated as optional Well, it is not.\nA process that cannot be repeated under controlled conditions is not robust: it is bricolage (fricklerhandwerk in german if you prefer). A build that only works in one CI runner configured through tribal knowledge is not reliable. A deployment that depends on hidden or global state, manual corrections, or a specific laptop blessed by the gods of local configuration is not engineering. It is theatre with a successful first act.\nI found myself returning to this point again and again in 2025, in code, at work, in writing, in discussions, and in teaching. Reproducibility should not be a niche concern. It is deeply connected to reliability, security, onboarding, supply-chain integrity, auditability, and cost control. It is one of the rare engineering properties that makes almost everything else easier.\nTeaching, learning, and trying to pass it on # One thing I particularly appreciated in 2025 was the chance to remain connected to the university.\nBeing able to share some of what I had learnt, particularly around reproducibility, deployment, and tooling, felt like a natural continuation of the work I had already started in previous years. I have become increasingly convinced that these topics deserve a far more central place in software engineering education. Students learn to code, which is good. They sometimes learn algorithms, architecture, and a bit of testing, which is also good. But the practical reality of deploying and operating systems that are maintainable, verifiable, and reproducible often remains oddly peripheral.\nWell-deserved stickers distribution after getting hands-on with the often-overlooked realities of software engineering That gap matters.\nBecause in the real world, a large part of software engineering is not about writing new code at all. It is about understanding constraints, choosing tools carefully, reducing accidental complexity, documenting decisions, managing dependencies, and making sure someone else can still operate the thing when you are gone or merely on holiday.\nI tried, in my own modest way, to make that visible.\nOpen source as engineering discipline # Open source continued to take an important place in 2025, as it has for a long time now. But more and more, I see it not just as a model of distribution or collaboration, but as a discipline in itself.\nOpen source changes the way you build things when you take it seriously. It forces a different kind of explicitness. It nudges you towards clearer interfaces, better documentation, simpler assumptions, and more reusable abstractions. Not automatically, of course. There is plenty of chaotic open source too. But at its best, open source encourages a kind of engineering honesty that is still sadly missing in many closed institutional environments.\nThroughout 2025, I continued contributing to and maintaining various projects, but one of the most personally meaningful developments was publishing my first Rust open-source project: markdown-code-runner.\nThe project started in April from a very concrete need: I wanted a tool that could help fix and normalise the syntax of code examples in the NixOS manual and Nixpkgs manual. The first version was meant to be a Python project, because that would have been the obvious and comfortable choice. But I quickly rewrote it in Rust, partly for performance, partly because I wanted to learn Rust properly by building something useful rather than by only reading about it, and partly because I found the Python ecosystem useful but increasingly messy.\nIt became a small command-line tool that processes Markdown files, detects code blocks, executes them via configurable commands, and optionally rewrites the document with the results. A fairly simple idea on paper. But, as is often the case, the \u0026ldquo;simple\u0026rdquo; tools end up being the ones that force you to think properly.\nWorking on it pushed me to improve the design several times: parsing, placeholder substitution, command execution, error accumulation, multi-threading, test coverage, AST-based rewriting, configuration design, and the general tension between flexibility and clarity. I genuinely enjoyed that process. It was one of those projects where the size stayed modest, but the lessons were real.\nThe most satisfying part was that it did not remain only a personal learning exercise. Once the tool existed, it was adopted in the Nix documentation through NixOS/nixpkgs#397142, and all Nix code in the manuals could then be formatted consistently with the Nix formatter. That is exactly the kind of outcome I like in tooling: a small, specific program that quietly removes a class of inconsistency from a project.\nStatistics generated using staabm/oss-contribs In numbers, the year was still very active, but in a slightly different way than the previous one. I had 405 pull requests merged on GitHub in 2025, making it my second-highest year after the 422 merged pull requests of 2024. The interesting detail in the graph is that this did not come from touching more and more projects. Quite the opposite: the number of projects I contributed to dropped from 44 in 2024 to 28 in 2025.\nPart of that decrease also came from the professional transition described later in this retrospective: changing career direction takes time and energy, and I had less of both available for broad open-source exploration.\nThat says something useful about the shape of the year. After the broad spread of 2024, 2025 was more concentrated. Most of that activity was focused on NixOS/nixpkgs, with 315 merged pull requests there alone, followed by work in my own repositories, some university-related repositories, and a few smaller projects such as trix, which also helped me continue learning Rust. It was less a year of expanding the surface area of my open-source activity than a year of spending more sustained effort on fewer places.\nThe raw number is not the interesting part, though. What I found more meaningful was the kind of work behind it. A large share of those contributions was maintenance work: package updates, refactorings, build fixes, small cleanups, support for newer Nix idioms, dependency reductions, and security-related updates. It is the kind of work that rarely looks spectacular from the outside, but which quietly improves the ecosystem for everyone who depends on it.\nMore broadly, 2025 reinforced my taste for tools that privilege explicitness over magic implicitness, composition over hidden behaviour, and boring predictability over fashionable cleverness.\nNixpkgs as maintenance (free) work # Around 75% of my open-source contributions this year happened in NixOS/nixpkgs, with 315 merged pull requests.\nLast year\u0026rsquo;s Github activity Some of it continued the work I had started around PHP packaging. I kept improving the PHP builders through changes such as support for lib.extendMkDerivation (NixOS/nixpkgs#385830), DRY improvements, various fixes and later a broader stability pass on the builder.\nThat work was satisfying precisely because it was not only about PHP. It was about making packaging interfaces clearer, more override-friendly, less surprising, and easier to maintain by people who did not have all the historical context in their head. That is one of the things I like about NixOS/nixpkgs: even a small packaging improvement can encode an engineering lesson, and once merged, that lesson becomes part of the shared toolbox.\nI also spent time on more general NixOS/nixpkgs maintenance: moving packages towards the finalAttrs pattern, removing unnecessary dependencies, updating tools I care about, and fixing issues where packages dragged in more of the world than they should. One concrete example was the work in NixOS/nixpkgs#439122, where a change reduced the closure size (sum of the size of the application and all its dependencies). I did that for a couple of other packages as well after noticing at work that some dependencies were being pulled in unnecessarily and could be removed.\nOutside of NixOS/nixpkgs, as part of my effort to learn Rust, I also contributed to trix, mostly around Nix-oriented cleanup, formatting behaviour, overlays, refactoring, and small usability improvements.\nNix, governance fatigue, Nixcon # But 2025 was also the year when I had to be more honest with myself about the Nix community.\nTechnically, I still believe Nix is one of the most important pieces of software infrastructure we have. My conviction there did not weaken. If anything, the more I work on reproducibility, supply chains, deployment, and long-term maintenance, the more obvious the value of Nix becomes.\nThe community side, however, became much harder to ignore.\nOver the last few years, and very visibly again in 2025, the Nix project went through repeated governance and community crises: lack of leadership, conflicts around sponsorship, the role of companies connected to the military-industrial complex, transparency inside the Steering Committee, moderation accountability, public accusations, resignations, election campaigns, private Matrix gossip, and endless threads where technical work disappeared behind political and interpersonal escalation.\nI do not think these problems are unique to Nix. Most of them are social rather than technical, and in that sense open source communities are also projections of the world around them. They reproduce many of the same tensions we see elsewhere: mistrust, polarisation, moral exhaustion, fragmented attention, and the temptation to treat every disagreement as proof of bad faith.\nThat is also why I do not believe those problems can be solved through aggression, humiliation, or performative violence, whether verbal or institutional. Some conflicts require boundaries, and some behaviours need consequences, but a community is not repaired by making escalation its default language. It takes time, patience, restraint, and the slow rebuilding of trust between people who still have to share the same project after the thread is closed.\nThere is something important to say here, and it also applies to anyone I interact with online without knowing them in real life. I will be blunt: I do not care where you are living or about your sexual orientation, gender or your personal identity, your kinks, or whether you wear cat ears in your spare time, or even your beliefs. By \u0026ldquo;I do not care\u0026rdquo;, I do not mean contempt, dismissal, or indifference to people. I mean that those things are not mine to judge, inspect, or turn into conditions for collaboration. I do not need access to someone\u0026rsquo;s private life in order to treat them decently or work with them seriously. What matters to me, in the context of an online project, is whether we can make the project successful together for everybody who depends on it and contributes to it, and hopefully useful to humanity as a whole. That is also why I usually avoid sharing too many details about my own private life online. I firmly believe that those details are nobody else\u0026rsquo;s business, and I do not think a software project benefits from forcing that kind of intimacy into its technical spaces. I am not going to relitigate every episode in detail. That would not be useful, and I am not interested in turning this retrospective into a timeline of grievances. But I cannot pretend it had no effect on me.\nFor a long time, my relationship with Nix was simple: contribute, review, help people, improve, repeat. That was healthy. It gave me a concrete way to participate in a project I deeply cared about. But the more community energy got absorbed by conflict, the more I felt my own attention being pulled into places where very little was built and very little was clarified.\nThat was not an abstract feeling. I had already written something similar in the Nix Community Survey 2024 Results: Gender distribution (1, 2) discussion, where I said that I had never observed any form of discrimination and that too much energy was being spent on a thread that could have been spent on documentation, the website, or pull-request reviews. I later found myself making a related point in the Anduril's threat is existential thread: no matter how much time people spend trying to persuade each other about non-technical questions, the basic reality of open source remains hard to escape. These conversations may sometimes be necessary, but they are not free. They ask for time, attention, restraint, and emotional energy from contributors who often came to the project to build and maintain software. They also ask even more from people who are not writing in their native language. For me, doing all of this in English, while my native language is French, added a constant extra layer of effort: choosing words carefully, avoiding misunderstandings, checking tone, and trying to stay precise while already tired from the emotional strain of the situation.\nThe same pattern showed up around symbolic project branding. The NixOS/nixos-homepage#1775 discussion started from a simple question that several people had raised in one form or another, and for which some were treated very harshly, even banned: what did the temporary Pride logo mean, and was NixOS now taking social or political stances ? To me, the problem was not the logo swap itself, but the absence of an initial explanation when it was changed. For such an international project, changing the public logo is a strong symbol, and not everyone, myself included, necessarily has the right cultural frame of reference, the same interpretive grid, or enough awareness of the context, timing, and intended message behind such a change. It could have been me asking such a question,\u0026hellip; and eventually banned.\nAugust 20 2025, the breaking point, I had to step back and it happened in NixOS/nixpkgs#435310.\nI stopped trying to follow every discussion. I made my GitHub profile private from that point on. I left toxic private Matrix spaces where the main product had become gossip, speculation, and ideological positioning. I became more selective about the threads I read and the discussions I entered. I also reconsidered how much responsibility I wanted to carry inside the project. Contributing code is one thing, remaining emotionally available for every drama is another.\nBecause I was not happy with how things had unfolded, especially the lack of communication and transparency, I opened NixOS/nixos-homepage#1830 a few days later, together with the Ukraine logo Discourse thread. I proposed a Ukrainian flag variant and tried to frame the question around consistency, process, and transparent criteria. If the project was willing to use its public branding to support causes, then it should at least be able to discuss how such support is decided and whether the same logic could apply to support Ukraine (or any other cause). Unsurprisingly, it still became another discussion about intent, representation, neutrality, solidarity, and what a technical project should publicly signal.\nThe Discourse thread made the same problem even more visible. Some contributors argued that symbolic support should not happen on an ad hoc basis, that the project logo was not the right venue, or that a technical community should unite around good software rather than public statements on causes. Others argued that human rights and community safety were already part of the project\u0026rsquo;s social reality. What also struck me was that some of the comments came from sporadic contributors, or from people relatively distant from the day-to-day technical work of the project. It sometimes felt as if controversy had its own gravity, attracting people who seemed far more interested in circling the mess than in cleaning anything up. I tried to keep the discussion focused on process and consistency, but the thread still moved towards personal interpretation of motives, including the suspicion that the Ukraine proposal was really a way to attack the rainbow logo. The thread was eventually locked before NixCon, with an explicit note that the topic and moderation could be discussed in person there, which I did.\nWhen working collaboratively in an open-source project or anywhere else, whatever decisions we make, there will always be people who disagree with them. The important part is whether we are able to accept compromise, accept that we cannot always agree, and still be at peace with ourselves while collaborating on a project where our own ideas will not always be the ones that prevail. That is how a project keeps moving forward together. Some people are willing to make that effort. Others, clearly, are not.\nThe uncomfortable part is that I broadly agree with the principle that an open-source project should either remain neutral in order to avoid ranking causes, or have a clear and consistent process for deciding which symbolic gestures it makes. The Ukraine proposal was partly a way to test that consistency and see whether the community had a principled answer. My conclusion was that the answer was much less clear than it should have been.\nBy late August, the situation had affected me enough that I contacted the NixOS mediation initiative for help, a great initiative by Numtide. On 25 August 2025, I sent a request describing the strain caused by the community situation and asking for guidance on how to react and how to move forward. Two days later, I had a conflict-coaching call about it. I appreciated the time Ross took to understand my point of view and help me find a way to cope with it. It definitely helped.\nThen came NixCon 2025, in Rapperswil-Jona, Switzerland, from 5 to 7 September. I went there for two reasons. The first was simply that I wanted to visit Switzerland, since I had never had the chance to visit that amazing country before. The second was that I wanted to chat with as many contributors as possible after the drama and cancellation attempts I had faced online. I enjoyed my time there much more than I expected. The venue was breathtaking, actually, the best venue for IT conferences I ever went! The technical talks and hallway conversations were interesting, but what mattered most to me was the chance to have direct, face-to-face discussions with people about what had happened, how they saw the situation, and how the project could move forward without letting online conflict consume everything. The Nix community I met in person was not the same community I had come to know online. People were much kinder, more nuanced, and easier to talk to face to face, and it became obvious to me that the online Nix community is not representative of the Nix project as a whole. Those conversations did not solve everything, of course, but they reminded me that the community is not reducible to its worst threads.\nAfter NixCon, in NixOS/branding#33, I materialised the proposal by adding Ukrainian branding derivations. Even there, I had to address rumours about why the proposal existed in the first place. As of 2026, that PR is still open and has not been merged. I had private contact with the marketing team about it, including contributors I appreciate a lot, and they invited me not to pursue that PR in the branding repository, but in another which is yet to be created. The reasoning was understandable: a national-flag variant can be interpreted as support for a state or government rather than only for people affected by war, it may create difficult precedent questions around other national flags and conflicts, it risks dividing contributors along national lines, and it would add maintenance pressure for a potentially open-ended set of variants.\nI can understand that position, and I do not want to turn the branding repository into a battlefield for symbolic gestures. Still, the lack of consistency is a bit unfortunate, especially when similar pull requests, such as the NixOS/branding#11 trans flag variant, had previously been merged without the same level of public discussion or process. In hindsight, and from the later private discussion I had about it, the mistake was probably not the existence of that variant itself, but merging it too quickly, before the project had taken the time to discuss branding advice, consultation, and a clear policy for what official variants mean, who decides them, and how similar requests should be handled later. That is precisely the kind of thing I mean: once a project starts making symbolic gestures without a clear process, contributors can end up spending a surprising amount of time explaining motives, defending consistency, and maintaining conversations that are not about the software itself.\nTaken together, all of this changed my relationship with the project, but it did not make me want to abandon it. It made me change the shape of my involvement.\nOne of the effects I had not really expected was the relational cost. These dramas made me lose friends, or at least people I genuinely appreciated and with whom I had shared good moments. That hurt more than the public threads themselves, because it made the conflict feel less like an abstract community problem and more like something that had entered real relationships. I kept contributing where I felt the work was concrete, useful, and aligned with why I joined the project in the first place: reproducibility, packaging quality, better tools, lower maintenance cost, and a more predictable contributor experience. But I became much less willing to donate attention to drama. Attention is a finite resource, and open source already consumes enough of it when things are going well.\nThat said, the whole experience also made me think more seriously about governance. A project cannot scale on technical excellence alone. It needs clear processes, fewer grey zones and ambiguity, explicit responsibilities, accountable moderation, conflict-of-interest handling, transparent decision-making, and enough institutional restraint to avoid turning every disagreement into an existential battle. Without that, even a technically brilliant project can become exhausting to inhabit.\nI still want Nix to succeed. I still want more people to use it, understand it, contribute to it, and benefit from it. But 2025 made one thing very clear to me: I have to choose my battles more carefully. My energy is better spent on systems, tools, documentation, reviews, and reproducible infrastructure than on trying to keep up with every social drama around the project, politics, trying to argue through every ideological battle, or trying to mediate between factions.\nThat is not indifference. It is self-preservation, and perhaps also a more mature form of contribution.\nRust, Typst, Nix, JJ… # My day-to-day tooling continued to evolve in 2025, though not radically. More like a process of gradual refinement.\nTypst remained firmly established in my workflow and has long since replaced LaTeX for nearly everything I need. It continues to hit that sweet spot between power and sanity that too few tools manage to reach.\nNix also remained central to how I think about environments, packaging, and infrastructure. At this point, I can say it again without hesitation: when the problem is dependency management, environment consistency, deployment predictability, or build reproducibility, Nix does not merely help a little. It removes entire classes of nonsense. Not all of them, sadly, but enough to keep me convinced.\nI also kept using JJ daily, and the feeling did not fade. Quite the opposite. The more I use it, the more I feel that traditional Git ergonomics are needlessly hostile in ways we have collectively normalised. JJ still feels to me like: a version-control system designed by people who actually wanted humans to succeed.\nAnd then there was Rust.\nI would not pretend that Rust is simple. It is not for me at least, yet ! But I increasingly appreciate the type of difficulty it imposes. It is often the kind that forces you to think clearly rather than letting you postpone the consequences of vagueness. In a software world increasingly saturated with convenience-first ecosystems and poorly governed dependency swamps, that feels refreshing\u0026hellip; and challenging, that the least I can say.\nComplexity is not free # Professionally, 2025 continued some of the familiar patterns that had already become visible in 2024 and that I described in the previous Retrospective 2024.\nIt was also the year when, after 10 years, I finally left DIGIT to join DG EAC.\nLeaving DIGIT was not just a change of acronym or office. It felt like closing a chapter that had become increasingly difficult to inhabit in a healthy way. I had learnt a lot there, and I do not want to reduce the experience to frustration. But by early 2025, it was clear to me that I needed a different environment: one where my energy could be spent less on surviving accumulated organisational complexity and more on architecture, maintainability, engineering practice, and the kind of long-term technical work I actually care about.\nJoining DG EAC (Directorate General of Education, Youth, Sport and Culture) gave that professional year a different shape. It did not magically remove the usual constraints of large public-sector IT, but it did give me a renewed sense of direction. The move put me closer to architecture and DevSecOps work, and closer to questions I find meaningful: how systems are structured, how teams make technical choices, how shared platforms evolve, and how public institutions can build software capacity without surrendering clarity or control.\nThat contrast also sharpened some of my observations.\nI kept working in environments where technical quality often has to push its way through organisational inertia, fragmented decision-making, poor standardisation, and a great deal of accidental complexity. That may sound harsh, but I do not think it is unfair.\nWhat struck me again and again was how often complexity is treated as though it were an unavoidable background condition rather than an actively produced cost. But complexity is not free. Every workaround has a price. Every undocumented assumption has a price. Every duplicated script, every inconsistent convention, every hidden dependency, every strange release process, every overengineered YAML pipeline stitched together with imperative shell fragments in three different languages, all of it has a price.\nAnd the larger the organisation, the easier it becomes to absorb that waste without confronting it directly.\nThat, to me, is one of the deepest dangers in large institutional environments: inefficiency can become so pervasive that it starts to look normal. Sometimes, even the maintenance of technical debt starts to feel normal too, as if keeping systems difficult to understand can become beneficial to someone trying to secure their own comfortable position.\nSo, as much as I could, I kept trying to work in the other direction: reducing duplication, making code easier to reason about, improving typing, refactoring away unnecessary inheritance, making behaviour more explicit, tightening development practices, and generally pushing for systems that can be understood without requiring a priesthood.\nIt is not glamorous work, I know, but at least it feels useful, I feel useful.\nPublic-sector IT, digital sovereignty, institutional amnesia # Throughout 2025, I kept reflecting on digital sovereignty, and I mean it in a sense much broader than simply \u0026ldquo;hosting location\u0026rdquo;.\nFor me, digital sovereignty is about control, intelligibility, auditability, and the practical ability to act on the systems we depend on. It is about not building critical public infrastructure on layers of opaque dependencies, outsourced assumptions, and proprietary constraints that no one fully understands or can meaningfully challenge. It is about ensuring that public institutions retain not just access to software, but agency over it.\nThis concern only grew stronger as questions around supply chains, SBOMs, dependency tracking, compliance, and the Cyber Resilience Act continued to become more relevant. The same basic question kept surfacing in different forms: do we actually know what we are running, how it was built, what it depends on, and whether we could rebuild or replace it if needed ?\nFlash (Zootopia), the sole remaining Civil Servant who actually remembers how the legacy application works Too often, the honest answer remains: not really.\nAnd this is where open source, reproducibility, and declarative infrastructure start to converge in a very practical way. They are not just technical preferences. They are preconditions for autonomy.\nI remain convinced that public institutions should be leading here. They should be setting the standard for transparency, maintainability, interoperability, and vendor independence. They should be investing in shared building blocks, reusable tooling, open governance, and long-term digital capacity. Too often, though, they still end up reproducing the very dependency patterns they ought to be resisting.\nThis is particularly frustrating because the talent exists. The resources exist. The need certainly exists. What is often missing is continuity, coordination, and the willingness to treat engineering choices as strategic choices rather than procurement side effects.\nLocal Linux User Group # One thing I appreciated more in 2025 was the value of smaller, more grounded communities.\nI remained active in open-source circles and continued engaging with people around reproducibility, Nix, packaging, and infrastructure. I also spent time helping keep local technical communities alive, because I increasingly think these spaces matter more than we sometimes admit.\nOne concrete expression of that was organising the first BeNix meetup in Nivelles on 7 November 2025. It was intentionally small and friendly: a few short presentations, pizza, drinks, open discussion, and enough room for both curious beginners and more experienced Nix users. The venue was kindly offered by Le Phare, which made the whole thing feel local in the best possible sense.\nThe venue, before the talks, the pizza and the conversations That evening mattered to me because it made the Nix community feel concrete again. I like in-person meetups precisely for that reason: they show you the real community, the one made of people who show up, listen, ask questions, help each other, and are willing to be present with the full complexity of a conversation. That is very different from the disembodied version of community that sometimes appears online, where some people seem mostly interested in criticising every imperfection with maximum intensity and very little personal courage. It is also a useful reminder that the most vocal people are not necessarily representative of the project. A large part of the contributor base is quieter, more practical, and far less interested in turning every disagreement into a public spectacle.\nThere is also a very different quality to explaining Nix, Linux, devshells, wrappers, and reproducibility to people sitting in the same room than there is to arguing about abstractions online. It brings the subject back to practice: what people are trying to build, what they do not understand yet, what friction they hit, and what small examples can suddenly make a difficult idea usable.\nRemote collaboration is useful. Shared repositories are useful. Chat tools are useful. But none of these fully replaces what happens when people meet, exchange ideas informally, have a coffee, eat pizza and chips, sketch nonsense on a napkin, argue over a toolchain, or discover during a side conversation that they have been solving the same problem in parallel for half a year.\nSome of the healthiest technical energy I felt in 2025 came from precisely those kinds of interactions, and this is also the reason why I like going back to the office.\nLife # 2025 was not just about code, drama, teaching and infrastructure.\nIt was also the year when Nakano passed away, in August. After losing Izumi at the very end of 2023, saying goodbye to Nakano less than two years later was another quiet and painful marker in the year. He had been part of the house, part of its routines, and part of the small ordinary presence that makes daily life feel anchored. His absence stayed with me more than I expected.\nNakano ♥ Part of the year was also spent dealing with very concrete, local, human issues closer to home: neighbourhood tensions, technical nuisances, mediation, documentation, exchanges with public actors, and all the strange little situations where evidence, communication, patience, and endurance matter more than ideology.\nOne example became especially present towards the end of the year: the recurring noise from a neighbour\u0026rsquo;s heat pump behind our house. It had already been a long-running issue, but the breakdown of a temporary compromise around late 2025 made it much harder to ignore. I found myself documenting facts, gathering measurements, talking with neighbours, contacting the relevant actors, and trying to keep the process constructive despite the fatigue that comes with a problem that invades daily life in such a physical way, simply because it is impossible to sleep with the noise it produces at night, around 55 dB(A) while the limit in Belgium is 40 dB(A) at night.\nAn overview of the sound pressure levels taken from my bedroom window during the night Oddly enough, these experiences reinforced some of the same beliefs: opaque systems generate mistrust, poor communication prolongs conflict, hidden assumptions make resolution harder, documentation helps, precision helps, calm persistence helps. And when institutions fail to engage seriously with the people affected by a problem, frustration compounds very quickly.\nWhether in software or daily life, I kept seeing the same pattern: systems become hostile when they stop being intelligible to the people who must live with them.\nWritings # I also kept writing in 2025, and the older I get, the more I think writing is one of the best antidotes to conceptual laziness.\nA lot of professional environments are dominated by ephemeral communication: meetings, chats, vague announcements, improvised decisions, disconnected tickets. Writing pushes in the opposite direction. It forces sequencing. It forces explicitness. It reveals weak arguments. It exposes missing links. It gives ideas enough structure to be challenged properly.\nOver the year, I wrote and revised material on reproducibility, software engineering, public-sector IT, and work more generally. Some of it remained private, some of it became public, and some of it is probably still waiting for me to stop polishing it.\nBut in all cases, the purpose was similar: to understand what I really think, and to say it a bit more clearly than the surrounding noise usually allows.\nI am increasingly convinced that careful writing is itself a technical skill.\nLooking forward # If I had to summarise 2025 in one sentence, I would say this:\nIt was a year of trying to align practice with principles.\nNot perfectly. Not without frustration. Not without contradictions either. But more deliberately than before.\nI continued defending reproducibility, open source, simplicity, and digital sovereignty not because they are fashionable talking points, but because I have seen, repeatedly, what happens when they are absent. Costs rise. Fragility rises. Dependency rises. Confusion rises. And after a while, people start adapting to avoidable dysfunction as though it were an immutable law of nature.\nI do not think it is.\nI still believe we can build software ecosystems that are more understandable, more maintainable, more transparent, and more respectful of both users and developers. I still believe public institutions have both the opportunity and the responsibility to lead by example. I still believe teaching matters, open communities matter, documentation matters, and that reducing complexity is one of the most valuable forms of engineering labour there is.\nSo that is what I want more of in 2026: fewer buzzwords, more rigour; fewer black boxes, more understandable systems; fewer isolated efforts, more shared building blocks; fewer theatrical transformations, more real engineering.\nAnd, ideally, just a little less nonsense disguised as innovation.\nThe views expressed in this post are my own and do not necessarily reflect those of my employer or any institution I am affiliated with. This reflection is based on personal experience and observations. I used a very old refurbished server hosted in my basement to fix the typos of this text using different open-source LLM, using Ollama and Open-WebUI. This post was produced using a controversial assistive technology known as a \u0026ldquo;physical keyboard\u0026rdquo;, configured with a US layout. I understand this may be disappointing to purists and I apologise in advance to anyone who believes real writing must be done manually, preferably with a goose feather and no autocomplete. ","date":"13 May 2026","externalUrl":null,"permalink":"/2026/retrospective-2025/","section":"Posts","summary":"","title":"Retrospective 2025","type":"posts"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/rust/","section":"Tags","summary":"","title":"Rust","type":"tags"},{"content":"","date":"19 April 2026","externalUrl":null,"permalink":"/tags/configuration-management/","section":"Tags","summary":"","title":"Configuration Management","type":"tags"},{"content":"","date":"19 April 2026","externalUrl":null,"permalink":"/tags/debugging/","section":"Tags","summary":"","title":"Debugging","type":"tags"},{"content":"","date":"19 April 2026","externalUrl":null,"permalink":"/tags/den/","section":"Tags","summary":"","title":"Den","type":"tags"},{"content":"9 days ago, I published Evaluating Den - A Dendritic Configuration Framework, where I described a real modelling issue I hit while evaluating vic/den framework for my infrastructure.\nToday, on April 19, 2026, less than 10 days later, that issue is now fixed. I was not expecting such a quick turnaround, and I am very happy to share the story, again.\nThe concrete fixes landed in vic/den#468, and it was made possible by the deep internal refactor from vic/den#462, which reworked Den\u0026rsquo;s resolution core around vic/nix-effects.\nThis is a great moment for the framework: Jason, the author of both PRs, not only fixed the bug but fundamentally evolved the core engine, just that.\nTLDR: this is exactly the kind of open-source feedback loop you hope to see but rarely get this fast.\nWhat Was Broken # In the previous post, I showed a 1 -\u0026gt; N topology where aspects containing both nixos and homeManager configurations were forwarded to multiple users.\nThat created duplicate host module declarations when the same aspect reached resolution through overlapping paths. As an example, when multiple users include the same aspect that emits host-level options, those options were emitted multiple times:\n1error: The option `boot.kernelPackages\u0026#39; is defined multiple times while it\u0026#39;s expected to be unique. What Changed # PR vic/den#468 introduces module-level deduplication for host-aspects overlap support.\nThe key idea is excellent:\nNamed aspects now carry a stable identity key on collected modules (pattern: \u0026lt;class\u0026gt;@\u0026lt;identity\u0026gt;) Deduplication happens across independent resolve paths when those keys match Anonymous or synthetic aspects are intentionally excluded from this keying so legitimate repeated anonymous includes can still coexist Visually, this is the difference:\n+--------------+ | Host (Igloo) | +--------------+ ^ ^ | | | | | | +------------.-+ +-.------------+ | User (Alice) | | User (Bob) | +--------------+ +--------------+ ^ ^ ^ ^ | \u0026#39;-----------. | | | | | | | .-------|-----\u0026#39; | | | | | +-.----------.--+ +--.-------------.-+ | Aspect (Base) | | Aspect (Desktop) | +---------------+ +------------------+ Result: host-level options can be emitted twice and collide.\nWait, isn\u0026rsquo;t Nix supposed to be declarative ? Yes, but the previous engine was effectively building a giant set of definitions by traversing a tree. When two paths included the same aspect, the engine \u0026ldquo;saw\u0026rdquo; two different instructions to define the same option. Without a reliable way to identify that these were actually the same logical instruction, it had no choice but to error out.\nPath A [via alice] Path B [via bob] +------------------------+ +------------------------+ | emit nixos@base | | emit nixos@base | | key = \u0026#34;nixos@base\u0026#34; | | key = \u0026#34;nixos@base\u0026#34; | +------------.-----------+ +-----------.------------+ | | \u0026#39;---------------. .---------------\u0026#39; | | v v +--------------------------------+ | classCollector | | seen \u0026#34;nixos@base\u0026#34; already ? | +----.------------------.--------+ | | first time duplicate | | v v +--------------+ +-----------+ | keep it | | discard | +------.-------+ +-----------+ | v +--------------------+ | single module | | in final output | +--------------------+ This fix was made possible by a large Den core rewrite in PR vic/den#462.\nThat refactor moved resolution from legacy tree-walking into an effects-based pipeline, powered by vic/nix-effects, which provides a freer-monad effect layer in pure Nix with a dependent type checker. Do not be afraid of the jargon, I will explain what that means later, keep on reading!\nPractically, this architectural shift made it much easier to express resolution concerns as composable handlers (include, transition, constraints, collection, tracing), and to introduce robust deduplication behavior, precisely the issue I had in my previous post.\nOr said differently: vic/den#468 is the fix users see, vic/den#462 is the groundwork that made this class of fix much cleaner to implement.\nA Tiny Mental Model # Think of each step as: \u0026ldquo;I need X, here is what to do next with X\u0026rdquo;.\nWith a very simple function:\nFunction: makeWelcomeCard Needs: personName, cityName Result: \u0026#34;Welcome {personName} to {cityName} !\u0026#34; Computation requests personName then requests cityName then builds the final sentence The function itself does not know where personName or cityName come from. It just declares what it needs.\nThe handler is the part that answers, for example:\npersonName = \u0026ldquo;Alice\u0026rdquo; cityName = \u0026ldquo;Brussels\u0026rdquo; Then the same computation returns:\nWelcome Alice to Brussels ! This is exactly the algebraic-effects split:\nComputation: declares operations it needs Handler: interprets those operations That separation lets Den encode concerns like constraints, transitions, tracing, and collection independently.\nWhat Is A Freer Monad, Practically ? # In practice, the useful mental model is: algebraic effects with handlers. If that still sounds abstract, think about ordering food:\nYou request what you need (for example: \u0026ldquo;one coffee\u0026rdquo;) The kitchen decides how to fulfill it and sends the result back Effects generalize that pattern. A computation can say \u0026ldquo;I need a hostname\u0026rdquo; or \u0026ldquo;I emit class nixos\u0026rdquo; then handlers decide how to answer and how to continue.\nNow it is true that if you are not into effect systems, \u0026ldquo;freer monad\u0026rdquo; can sound scary, but the practical idea is straightforward. Instead of directly executing logic while recursively walking a tree:\nYou first build a description of computations as effect requests plus continuations Then you run that description through handlers that decide behavior Briefly, a free monad is the classic way to model this idea: you represent a program as data first, and interpret it later. In other words:\nBuild the program structure without executing effects immediately Keep composition pure and testable Run it later with an interpreter/handler that gives operational meaning But here, Den uses a freer monad style, which is a more flexible variant that allows for more direct composition and easier handling of effects without needing to build an explicit data structure for the entire program upfront.\nIn practice, you do not need to memorize the category theory ! Just understand that for Den, \u0026ldquo;freer\u0026rdquo; means each effect handler can be implemented independently (like a plugin) without coordinating through a centralized, monolithic interpreter. This is exactly what made extensions like the deduplication handler (ctx-seen) easier to add.\nWhy \u0026ldquo;freer\u0026rdquo; ? Historically, it comes from being \u0026ldquo;more free\u0026rdquo;, in particular by making extensible effects easier to model with fewer practical constraints in the representation. The name was popularized by the 2015 paper Freer Monads, More Extensible Effects by Oleg Kiselyov and Hiromi Ishii.\nIn the context of Den, the resolver no longer hardcodes every decision in one recursive traversal. It emits operations like:\nemit-include: triggers the resolution of a sub-aspect emit-class: contributes a NixOS/Home-Manager module register-constraint / check-constraint: handles exclusion logic chain-push / chain-pop: tracks the \u0026ldquo;provenance\u0026rdquo; of an inclusion into-transition: walks context transitions ctx-seen: deduplicates context stages And dedicated handlers decide what each means operationally. This is powerful because control flow becomes data.\n| Legacy recursive walk | Effects pipeline ------------------------------+-------------------------- resolve(aspect): | comp = aspectToEffect(aspect) for include in includes: | run(comp, handlers): resolve(include) | on emit-include --\u0026gt; recurse/skip collect classes | on emit-class --\u0026gt; collect apply transitions | on into-transition --\u0026gt; dispatch | on check-constraint --\u0026gt; gate | Analogy #1: Tree Traversal # A tree is a natural structure to see this clearly, since tree traversal is a concept most programmers have already encountered at some point\u0026hellip; I hope.\nImagine a tree where each node can contribute data, and children are traversed recursively:\n+---------+ | root | +--.---.--+ / \\ / \\ v v +--------+ +--------+ | left | | right | +--------+ +--------+ | Recursive model | Effects model -------------------+---------------------------------------- visit(root) | send visit(root) collect(root) | --\u0026gt; handled by traversalHandler visit(left) | --\u0026gt; resume continuation visit(right) | send collect(root) | --\u0026gt; handled by collectorHandler | --\u0026gt; resume continuation | send visit(left) | --\u0026gt; handled by traversalHandler | send visit(right) | --\u0026gt; handled by traversalHandler | Both can traverse the same tree and produce the same final result. The difference is where control lives:\nRecursive model (Visitor Pattern): the traversal policy is hardcoded inside visit(). This is the traditional, imperative way to walk a data structure. Effects model (Event-based): the computation is essentially \u0026ldquo;event-based\u0026rdquo;. It encodes the next steps via continuations, while handlers interpret effects and influence behaviour through state, forwarding, or even aborting. That means you can change behaviour (deduplication, tracing, filtering, transition rules) by simply swapping or adding handlers, instead of rewriting the entire traversal logic.\nAnalogy #2: Parsers # If you come from a background in XML or HTML parsing, another excellent analogy is the difference between DOM and SAX parsers:\nDOM parsers build and traverse an entire in-memory tree (much like the legacy recursive model). SAX parsers are event-based, they stream through the document and fire events as they encounter elements. Den\u0026rsquo;s new effect-based resolver behaves more like a SAX parser. It emits signals (events) that are handled incrementally.\nAnd the best part ? This architectural shift yielded a staggering ~5 speedup compared to the previous imperative tree-walking implementation !!!\nAnalogy #3: The Middleware Pattern # Another analogy, and it will be the last one, is HTTP middleware stacks. If you have worked with them, the pattern should feel familiar.\nIn a middleware pipeline, each layer receives a request, optionally transforms it, and decides whether to pass it down to the next layer or short-circuit and return a response early:\n| HTTP middleware stack | Effects handler chain -------------------------+---------------------------- Request | send \u0026#34;emit-class\u0026#34; | | | v | v [Auth middleware] | [classCollector handler] | pass / abort | | resume / abort v | v [Logging middleware] | [tracingHandler] | pass / abort | | resume / abort v | v [Route handler] | [constraintHandler] | | | v | v Response | collected modules | Both allow you to compose independent concerns (logging, auth, deduplication) without mixing them into the core logic.\nThe key difference is scope: middleware operates on a single linear request/response cycle, while algebraic effects can express more complex patterns like branching, tree traversal, shared mutable state between steps, and custom control flow, all without changing the computation itself.\nBut the mental model is the same. If you are comfortable with middlewares, you already understand the core intuition behind algebraic effects.\nThis is powerful because control flow becomes data. When control flow is data, you can add or swap behaviour without rewriting the entire resolver. That is exactly the kind of flexibility that made the deduplication fix in vic/den#468 cleaner to express.\nWhy This Helps With The Overlap Bug # The overlap bug was fundamentally about how collected modules from different paths are reconciled.\nIn an effect pipeline, that reconciliation can live in collection/identity handlers and state, instead of being tangled with traversal mechanics.\n+------------------+ send emit-class +---------------------------+ | aspectToEffect() | ------------------------\u0026gt; | classCollector handler | +------------------+ | state: map[key] -\u0026gt; module | ^ +-------------+-------------+ | | | | key = class@identity | | | v | +---------------------------------+ | | if key exists: keep only one | | | else: insert | | +----------------+----------------+ | | \u0026#39;---------------------- resolve-complete \u0026lt;--------\u0026#39; So the technical win is not just \u0026ldquo;deduplication was added\u0026rdquo;. The deeper win is architectural: Den now has a resolution model where this kind of policy is easier to implement, reason about, and evolve.\nCommunity Moment # On top of being a really cool technical achievement, another aspect of this story is the open-source social feedback loop in action.\nI validated the fix proposed by @sini, reviewed by @theutz, and was merged not so long after.\nVictor wrote me privately today and I share this with his permission, because it captures exactly why I love open source:\n\u0026ldquo;I really love that Den is no longer just me\u0026hellip; I came back from day-of-rest and found a PR by sini, approved by theutz and validated by you saying this fixes your blog post. I love this.\u0026rdquo;\nThat message made my day. Thank you to everyone who contributed to this great project.\nAnother great part of this refactor is that it is backward compatible. While the \u0026ldquo;guts\u0026rdquo; of Den were swapped out, existing aspects and configurations stay exactly the same. You just get a smarter resolver that handles overlapping topologies better.\nOne thing that might come back soon thanks to this fix is builtin bidirectionality. Vic mentioned that since we can now reliably deduplicate host-level modules, we might be able to let host-aspects contribute user-level classes (like homeManager) to all its users automatically, without people having to use any manual bridge batteries. This would be a massive ergonomic win for complex setups.\nDoes This Remove The Modelling Challenge ? # No, and that is important.\nThe fix resolves the concrete overlap/duplication failure I documented. That is a real improvement for users and ergonomics.\nBut my previous core argument still stands:\nFrameworks can reduce accidental complexity They cannot erase essential policy complexity You still need to model ownership boundaries and activation semantics explicitly when your topology becomes non-trivial. The difference now is that Den\u0026rsquo;s core engine will handle this much more gracefully.\nUpdated Evaluation # After this week, my evaluation of Den is stronger than before:\nThe framework is technically ambitious and keeps improving quickly The architecture is becoming more explicit and more extensible The community process is already healthy: users report, contributors fix, maintainers enable and guide I am planning to finalise and merge drupol/infra#124 very soon so I can start using Den by default for my own infrastructure. In infrastructure tooling, correctness is critical. In open source, responsiveness is critical. Seeing both in action in under 2 weeks is impressive.\nClosing Thoughts # I wrote the previous post to document a real limitation I encountered. I am writing this one because the limitation is now fixed.\nThat is the full story we should tell:\nReport problems clearly, in other words, avoid the XY problem Reduce them to reproducible models, provides a failing test case, that helps maintainers understand the issue concretely Validate fixes publicly, so everyone can learn from the process and see the improvement in action Credit the people who did the work, because open source is a team sport and we should celebrate wins together Huge thanks again to Victor, Jason, Michael, you rocks ! For sure 😎 !\nBack to finalising drupol/infra\u0026hellip;\n","date":"19 April 2026","externalUrl":null,"permalink":"/2026/den-framework-follow-up-issue-fixed/","section":"Posts","summary":"","title":"Den Framework Follow-up: Issue Fixed !","type":"posts"},{"content":"","date":"19 April 2026","externalUrl":null,"permalink":"/tags/infrastructure-as-code/","section":"Tags","summary":"","title":"Infrastructure as Code","type":"tags"},{"content":"","date":"10 April 2026","externalUrl":null,"permalink":"/tags/aspect-oriented-programming/","section":"Tags","summary":"","title":"Aspect-Oriented Programming","type":"tags"},{"content":"I am currently rewriting again my infrastructure repository, now renamed drupol/infra, and documenting the work on an ongoing draft pull request: #124.\nAfter my previous rewrite based on a feature-first mindset, I wanted to push the architectural concept further using vic/den, a Nix framework built around aspects, context transformations and dendritic pattern.\nThe short version: Den is impressive, genuinely powerful, and intellectually satisfying. However, while experimenting with it in a real infrastructure, I ran into an architectural constraint that feels deeper than any specific framework.\nThis post explores that specific problem: a collision of cardinality, scope, and ownership in declarative configuration.\nWhy Den Looked Like the Right Next Step # Den models \u0026ldquo;dendritic\u0026rdquo; configuration as:\nAspect-oriented configuration (handling cross-cutting features) Context pipeline transformations (e.g., mapping host -\u0026gt; user, with optional reverse relationships) Per-class outputs (nixos, homeManager, and others) This maps beautifully to how I think about modular infrastructure.\nIf a feature is desktop, I want to define it once, then have it intelligently influence all relevant configuration domains. At first glance, this is exactly what Den enables.\nA Minimal Example # To illustrate the problem, let\u0026rsquo;s look at a minimal example.\n+-------------------+ | Host (igloo) | | - nixos | +-------------------+ ^ ^ ^ includes | | | includes .-------------\u0026#39; | \u0026#39;-------------. | owns | | +---------------+ +---------------+ +------------------+ | Aspect (base) | | User Aspect | | Aspect (desktop) | | - nixos | | (alice) | | - nixos | | - homeManager | +---------------+ | - homeManager | +---------------+ ^ ^ +------------------+ | | includes | | includes .-------------\u0026#39; \u0026#39;-------------. | | +-----------------+ +-----------------+ | Built-in Aspect | | Built-in Aspect | | define-user | | primary-user | +-----------------+ +-----------------+ This is not my actual configuration, but a simplified version that captures the essence of the issue.\n1{ 2 lib, 3 den, 4 ... 5}: 6{ 7 # Enable HomeManager for all users by default 8 den.schema.user.classes = lib.mkDefault [ \u0026#34;homeManager\u0026#34; ]; 9 10 # Define a host `igloo` with one user `alice` 11 # This implicitly creates the `igloo` and `alice` aspects, which we can then extend 12 den.hosts.x86_64-linux.igloo.users = { 13 alice = { }; 14 }; 15 16 # Extend the `alice` aspect that includes user definition and primary user role 17 den.aspects.alice = { 18 includes = [ 19 # These aspects are built-in, see: https://den.oeiuwq.com/guides/batteries/ 20 den.provides.define-user 21 den.provides.primary-user 22 ]; 23 }; 24 25 # Extend the `igloo` aspect that includes `base` and `desktop`, plus some NixOS options 26 den.aspects.igloo = { 27 includes = with den.aspects; [ 28 base 29 desktop 30 ]; 31 32 nixos = { 33 boot.loader.grub.enable = false; 34 fileSystems.\u0026#34;/\u0026#34; = { 35 device = \u0026#34;/dev/null\u0026#34;; 36 fsType = \u0026#34;none\u0026#34;; 37 }; 38 }; 39 }; 40 41 # Define the `base` aspect that includes both Home Manager and NixOS options 42 den.aspects.base = { 43 homeManager = { 44 home.stateVersion = \u0026#34;25.11\u0026#34;; 45 }; 46 47 nixos = 48 { pkgs, ... }: 49 { 50 boot.kernelPackages = pkgs.linuxPackages_latest; 51 system.stateVersion = \u0026#34;25.11\u0026#34;; 52 }; 53 }; 54 55 # Define the `desktop` aspect that includes both Home Manager and NixOS options 56 den.aspects.desktop = { 57 homeManager = { 58 programs.firefox.enable = true; 59 }; 60 61 nixos = { 62 services.desktopManager.plasma6.enable = true; 63 }; 64 }; 65} Conceptually, this delivers exactly what aspect-oriented configuration promises:\nOne conceptual feature (e.g., base, desktop) Multiple configuration targets (e.g., nixos, homeManager) In practice, this is where the friction begins.\nPropagation Scope # If we evaluate the configuration above, we hit an immediate snag:\n1$ nix build .#nixosConfigurations.igloo.config.system.build.toplevel 2 3error: The option `home-manager.users.alice.home.stateVersion\u0026#39; was accessed but 4has no value defined. Try setting the option. The home.stateVersion defined in the base aspect is not propagating to the user alice.\nFear not ! Den anticipates this and provides a mechanism to establish a mutual provider relationship:\n@@ -7,6 +7,11 @@ # Enable HomeManager for all users by default den.schema.user.classes = lib.mkDefault [ \u0026#34;homeManager\u0026#34; ]; + # Allows you to define mutual configurations by letting you to define named + # aspects under `.provides.` to create explicit relationship between users and + # hosts. See https://den.oeiuwq.com/guides/mutual/#denprovidesmutual-provider + den.ctx.user.includes = [ den._.mutual-provider ]; + @@ -24,10 +29,12 @@ # Extend the `igloo` aspect that includes `base` and `desktop`, plus some NixOS options den.aspects.igloo = { - includes = with den.aspects; [ - base - desktop - ]; + provides.to-users = { + includes = with den.aspects; [ + base + desktop + ]; + }; Basically, this means that the base and desktop aspects included in the igloo host aspect will now be forwarded to the users of that host, making the homeManager configuration available to alice as expected:\n+------------------+ | Host (igloo) | | - nixos | +------------------+ ^ ^ ^ includes | | | includes .------------------\u0026#39; | \u0026#39;------------------. | owns | | +------------------+ +------------------+ +------------------+ | Aspect (base) | | User Aspect | | Aspect (desktop) | | - nixos | | (alice) | | - nixos | | - homeManager |-------------\u0026gt;| |\u0026lt;-------------| - homeManager | +------------------+ to-users +------------------+ to-users +------------------+ ^ ^ includes | | includes .---------------\u0026#39; \u0026#39;---------------. | | +-----------------+ +-----------------+ | Built-in Aspect | | Built-in Aspect | | define-user | | primary-user | +-----------------+ +-----------------+ A mixed aspect like base naturally contains both:\nHost-level concerns (nixos): kernel packages, state versions, GPU drivers,\u0026hellip; User-level concerns (homeManager): shell aliases, desktop apps, user packages,\u0026hellip; This exposes a classic OS design problem: the separation of Mechanism and Policy.\nThe framework provides the mechanism to pass configurations between contexts. But it cannot dictate the policy. If an aspect is attached at the host level (igloo includes base), what exactly should happen for the users ? Do all users get the homeManager payload ? Only some users ? Only the primary user ? Only users matching a specific role ? \u0026lt;you-name-it\u0026gt; ?\nThe framework requires you to encode this intent. But as we scale, encoding this intent creates a deeper structural issue, leading to more complex and less intuitive models.\nFrom 1-\u0026gt;1 to 1-\u0026gt;N # With a host and 1 user, forwarding host-selected aspects to users is trivial. The evaluation behaves exactly as expected:\n1nix-repl\u0026gt; nixosConfigurations.igloo.config.home-manager.users.alice.home.stateVersion 2\u0026#34;25.11\u0026#34; 3 4nix-repl\u0026gt; nixosConfigurations.igloo.config.home-manager.users.alice.programs.firefox.enable 5true The breaking point appears when we move from a 1-\u0026gt;1 topology to a 1-\u0026gt;N topology. Let\u0026rsquo;s add a second user, bob, to the igloo host:\n@@ -12,10 +12,11 @@ # hosts. See https://den.oeiuwq.com/guides/mutual/#denprovidesmutual-provider den.ctx.user.includes = [ den._.mutual-provider ]; - # Define a host `igloo` with one user `alice` - # This implicitly creates the `igloo` and `alice` aspects, which we can then extend + # Define a host `igloo` with users `alice` and `bob`. + # This implicitly creates the `igloo`, `alice` and `bob` aspects, which we can then extend den.hosts.x86_64-linux.igloo.users = { alice = { }; + bob = { }; }; @@ -27,6 +28,13 @@ ]; }; + # Extend the `bob` aspect that includes user definition + den.aspects.bob = { + includes = [ + den.provides.define-user + ]; + }; The graph topology now looks like this:\n+-------------------+ | Host (igloo) | | - nixos | +-------------------+ ^ ^ ^ includes | | | includes .-----------------------\u0026#39; | \u0026#39;----------------------. | owns | | | .-------+-------. | | | | | +------------------+ | | +------------------+ | Aspect (base) | to-users +--------------+ +--------------+ to-users | Aspect (desktop) | | - nixos |----------\u0026gt;| User (alice) | | User (bob) |\u0026lt;----------| - nixos | | - homeManager |-. +--------------+ +--------------+ .-------| - homeManager | +------------------+ | ^ ^ ^ ^ | +------------------+ | to-users | | | | | \u0026#39;--------------|-------|-------\u0026#39; | | | | | to-users | | \u0026#39;-----------|------------\u0026#39; | | .--------+--------. | includes | | | includes | | | +-----------------+ +-----------------+ | Built-in Aspect | | Built-in Aspect | | primary-user | | define-user | +-----------------+ +-----------------+ But evaluation now fails with:\n1error: The option `boot.kernelPackages\u0026#39; is defined multiple times while it\u0026#39;s expected to be unique. 2 3Definition values: 4 - In `/nix/store/...-source/modules/igloo.nix, via option den.aspects.base.nixos\u0026#39; 5 - In `/nix/store/...-source/modules/igloo.nix, via option den.aspects.base.nixos\u0026#39; 6 7Use `lib.mkForce value` or `lib.mkDefault value` to change the priority on any of these definitions. In software engineering, this is analogous to the Diamond Problem, exacerbated here by a cardinality mismatch.\nIn data modelling, this is analogous to a SQL join fan-out: a host is unique (cardinality 1), but after joining through users (cardinality N) it gets duplicated, and when projected back to host scope it collides with itself.\nBecause boot.kernelPackages is defined in the base aspect, and both alice and bob receive the base aspect from the host, they both attempt to feed that host-level nixos configuration back up the evaluation graph.\nIn this demo, base and desktop are active on both the host path and the forwarded user paths, which is why a unique host-level option can collide when cardinality moves from 1-\u0026gt;1 to 1-\u0026gt;N.\nVisually, the evaluation graph looks like this:\n+--------------+ | Host (Igloo) | +--------------+ ^ ^ | | | | | | +--------------+ +--------------+ | User (Alice) | | User (Bob) | +--------------+ +--------------+ ^ ^ ^ ^ | \u0026#39;-----------. | | | | | | | .-------|-----\u0026#39; | | | | | +---------------+ +------------------+ | Aspect (Base) | | Aspect (Desktop) | +---------------+ +------------------+ The host (cardinality of 1) receives the identical configuration twice from the users (cardinality of N), creating a collision.\nTo fix this, we must make ownership boundaries explicit by splitting the mixed aspect into dedicated host and user variants, as follows:\n+----------------+ | Host (igloo) | | - nixos | +----------------+ ^ ^ ^ ^ ^ to-users | | | | | to-users .----------------------------------------\u0026#39; | | | \u0026#39;-------------------------------------. | includes | | | includes | | .-------------------------\u0026#39; | \u0026#39;------------------------. | | | | | | | | .------+------. | | | +-----------------+ | owns | +--------------------+ | | |Aspect(base-host)| | | |Aspect(desktop-host)| | | | - nixos | +--------------+ +--------------+ | - nixos | | | +-----------------+ | User (alice) | | User (bob) | +--------------------+ | | +--------------+ +--------------+ | +-----------------+ ^ ^ ^ ^ ^ ^ ^ +--------------------+ |Aspect(base-user)|-----------------------\u0026#39; | | | | | \u0026#39;-----------------------|Aspect(desktop-user)| | - homeManager | | | \u0026#39;-----|------|---------------------------| - homeManager | | |--------------------------|---|--------\u0026#39; | | | +-----------------+ | | | +--------------------+ | \u0026#39;--------. | | includes | | includes | | | +------------------+ +------------------+ | Built-in Aspect | | Built-in Aspect | | primary-user | | define-user | +------------------+ +------------------+ And the complete corresponding configuration now looks like this:\n1{ 2 den, 3 lib, 4 ... 5}: 6{ 7 den.ctx.user.includes = [ den._.mutual-provider ]; 8 den.schema.user.classes = lib.mkDefault [ \u0026#34;homeManager\u0026#34; ]; 9 10 den.hosts.x86_64-linux.igloo.users = { 11 alice = { }; 12 bob = { }; 13 }; 14 15 den.aspects.alice = { 16 includes = [ 17 den.provides.define-user 18 den.provides.primary-user 19 ]; 20 }; 21 22 den.aspects.bob = { 23 includes = [ 24 den.provides.define-user 25 ]; 26 }; 27 28 den.aspects.igloo = { 29 includes = with den.aspects; [ 30 base-host 31 desktop-host 32 ]; 33 34 provides.to-users = { 35 includes = with den.aspects; [ 36 base-user 37 desktop-user 38 ]; 39 }; 40 41 nixos = { 42 boot.loader.grub.enable = false; 43 fileSystems.\u0026#34;/\u0026#34; = { 44 device = \u0026#34;/dev/null\u0026#34;; 45 fsType = \u0026#34;none\u0026#34;; 46 }; 47 }; 48 }; 49 50 den.aspects.base-host = { 51 nixos = 52 { pkgs, ... }: 53 { 54 boot.kernelPackages = pkgs.linuxPackages_latest; 55 system.stateVersion = \u0026#34;25.11\u0026#34;; 56 }; 57 }; 58 59 den.aspects.base-user = { 60 homeManager = { 61 home.stateVersion = \u0026#34;25.11\u0026#34;; 62 }; 63 }; 64 65 den.aspects.desktop-host = { 66 nixos = { 67 services.desktopManager.plasma6.enable = true; 68 }; 69 }; 70 71 den.aspects.desktop-user = { 72 homeManager = { 73 programs.firefox.enable = true; 74 }; 75 }; 76} While this definitely solves the evaluation error, it defeats the primary goal of aspect-oriented configuration.\nWe no longer have a single, cohesive atomic cross-cutting feature. We have returned to rigidly separated data silos, making the model more verbose and arguably less intuitive, potentially making the use of a framework less worthwhile.\nThe Contextual Meaning of Features # This reveals an underlying truth: \u0026ldquo;Features\u0026rdquo; do not exist in a vacuum. In a multi-user environment, base or desktop are not simple boolean toggles. Their meaning mutates depending on the bounded context they evaluate in.\nAs soon as a host has more than one user or another similar pattern, \u0026ldquo;including an aspect/feature\u0026rdquo; ceases to be a simple import. It becomes a domain-modelling problem.\nAccidental vs. Essential Complexity # In his paper (10.1109/MC.1987.1663532) No Silver Bullet, Fred Brooks divides software engineering difficulties into Accidental Complexity (clunky syntax, boilerplate) and Essential Complexity (the inherent difficulty of the problem domain).\nFrameworks like Den brilliantly solve accidental complexity. They provide:\nComposition primitives: aspect inclusion, context transformations, and mutual providers Context-aware dispatch: allowing you to route configurations based on user roles, host types, or any custom context stage Modular organisation and deduplication patterns: defining features once and reusing them across contexts But no framework can solve the essential complexity of policy:\nWho fundamentally owns a feature ? How should a host-level capability cascade to multiple heterogeneous users ? Where do exceptions live ? These are architectural decisions. They depend entirely on your specific infrastructure use case, your team constraints, and your security posture. A framework cannot infer the \u0026ldquo;right\u0026rdquo; propagation rule because a universal rule does not exist (yet ?).\nA Note About Den # I want to be explicitly clear: this post is not a criticism of Den, nor of Victor Borja, its author.\nVictor has been consistently responsive, helpful, and genuinely friendly throughout my experiments. His work on Den is incredibly solid, and I appreciate his dedication enough to sponsor him on GitHub. (He is also the author of vic/import-tree, which powers all my projects by default).\nMy goal here is to highlight a fundamental class of modelling constraints that any framework will inevitably encounter when reconciling host-level (nixos) and user-level (homeManager) boundaries at scale.\nPractical Consequences # My previous rewrite taught me to pivot from host-first to feature-first. Den confirms this is the right direction and provides superior building blocks to achieve it, for sure 😎 !\nAt the same time, it made a deeper truth highly visible:\nAspect-oriented composition improves how we express configuration, but it does not eliminate the need to strictly define ownership boundaries between entities.\nThe hard part of IaC is no longer \u0026ldquo;how to write this or that module\u0026rdquo;. The hard part is deciding which entity has the authority to control activation semantics.\nTo resolve this in practice, engineers usually adopt one of these strategies:\nSplitting Aspects: Separating mixed features into explicit host and user variants (sacrificing cohesion), defeating the primary goal of aspect-oriented configuration. Capability Gating: Adding metadata to users to gate user-level activation (adding overhead). Role-Driven Forwarding: Building custom context layers to route configurations based on roles. Convention over Configuration: Dictating rules like \u0026ldquo;Hosts include infrastructure features; users include experience features\u0026rdquo; All of these are valid. None of them are free. Each strategy forces you to encode policy.\nThe Real Evaluation Criterion # I started this migration asking: \u0026ldquo;Which framework should I use ?\u0026rdquo; I now realise the better question is: \u0026ldquo;Which framework makes my policy decisions explicit, easily adaptable, and maintainable in the long run ?\u0026rdquo;\nDen scores exceptionally high here. It gives me enough control to model my intent precisely, right down to custom context stages and dispatch strategies. But it is not a silver bullet (No pun intended !). It does not absolve the engineer of the responsibility to define ownership and map out cardinality boundaries.\nConclusion # This rewrite is still in progress, and I still have open questions before merging PR #124.\nThe main takeaway so far is a timeless engineering lesson:\nFrameworks have the potential to reduce accidental complexity. Frameworks cannot remove essential complexity. In configuration management, that essential complexity is almost always found at the boundaries: host vs. user, mechanism vs. policy, and cohesion vs. specificity.\nI am still exploring the most elegant shape for these boundaries in my own setup. If you have faced similar trade-offs—whether with Den, flake-parts, or another framework: I would love to hear how you modeled them.\n","date":"10 April 2026","externalUrl":null,"permalink":"/2026/evaluating-den-a-dendritic-configuration-framework/","section":"Posts","summary":"","title":"Evaluating Den - A Dendritic Configuration Framework","type":"posts"},{"content":"","date":"10 April 2026","externalUrl":null,"permalink":"/tags/home-manager/","section":"Tags","summary":"","title":"Home Manager","type":"tags"},{"content":"","date":"10 April 2026","externalUrl":null,"permalink":"/tags/software-architecture/","section":"Tags","summary":"","title":"Software Architecture","type":"tags"},{"content":"","date":"1 May 2025","externalUrl":null,"permalink":"/tags/flake-parts/","section":"Tags","summary":"","title":"Flake Parts","type":"tags"},{"content":"","date":"1 May 2025","externalUrl":null,"permalink":"/tags/refactoring/","section":"Tags","summary":"","title":"Refactoring","type":"tags"},{"content":"The drupol/nixos-x260 repository began as a simple and practical way to manage the configuration of my Lenovo ThinkPad X260 laptop, hence the (bad) name. Unsurprisingly, I quickly became hooked on the NixOS Linux distribution, and before long, I was running it on every machine I owned\u0026hellip; first at home, then even at work (shhht!). As the obsession grew, so did the project. It naturally expanded to support a wide variety of systems: from a simple Intel-based laptop, to a Raspberry Pi router tucked away in the basement, and even an old iMac from 2012. Each machine came with its own quirks and specific requirements. Like many personal setups, what started as a clean and elegant solution gradually evolved into a tangled web of host-specific hacks and duplicated logic.\nFor a long time, I kept postponing a proper rewrite, procrastinating \u0026ldquo;like a boss\u0026rdquo;. I was daunted by the scale of the work and, frankly, didn\u0026rsquo;t yet have a clear vision (or the knowledge?) to pull it off. The ideas I had in mind were just out of reach.\nBut eventually, the moment came. I decided to start over. From scratch. No more excuses.\nThe Case for Declarative Infrastructure # Source: Dellaiera, P. (2024). Reproducibility in Software Engineering. https://doi.org/10.5281/zenodo.12666898 When it comes to managing systems at scale, not all approaches are created equal. Over time, three primary models of configuration management have emerged. Each of them with their strengths, limitations, and implications for reproducibility and maintainability.\nDivergent Configuration Management # This is the most traditional and error-prone approach (illustrated in Figure 15). Systems are configured manually by individuals, leading to configuration drift as changes accumulate over time without central oversight. What starts as a uniform setup quickly turns into a collection of inconsistently configured machines, each with its own quirks and undocumented changes. Reproducing these environments becomes nearly impossible, and unpredictability becomes the norm.\nConvergent Configuration Management # In this model illustrated in Figure 16, tools like Ansible, Puppet, or Terraform aim to bring systems back into alignment with a desired state. While this improves consistency, it rarely guarantees it. Machines may \u0026ldquo;converge\u0026rdquo; towards a shared configuration, but subtle variations and feedback loops can persist. It is an improvement over divergence, but not a cure for non-determinism.\nCongruent Configuration Management # This is the strictest and most reproducible model (illustrated in Figure 17). Systems are declared immutably, and their configurations are enforced to be identical from the outset. Drift is prevented rather than corrected. This is the philosophy behind tools like Nix and Guix, which aim to provide deterministic, declarative environments that can be reliably rebuilt and reproduced. While congruent systems can be less flexible for rapidly-changing needs, they offer unmatched confidence in consistency and reproducibility.\nSo now you might wonder why go through all this trouble, why maintain a repository just to manage a few personal machines? The answer is simple: consistency, reproducibility, and peace of mind. With NixOS, every machine is configured declaratively, from A to Z, meaning I describe the desired state, and Nix ensures it gets there, reliably and repeatably, following a congruent configuration model.\nUnlike traditional Linux distributions where system configuration often involves manual tweaks and hard-to-track changes (Divergent model, Figure 15), NixOS treats everything as code. This allows me to:\nRoll back broken changes instantly Rebuild any machine from scratch with a single command Share and reuse configuration across machines Track every change in version control Avoid \u0026ldquo;it works on my machine\u0026rdquo; problems entirely This repository isn\u0026rsquo;t just a bunch of \u0026ldquo;dotfiles\u0026rdquo;, it is the source of truth for my infrastructure. Whether it is a laptop, a desktop, or a headless server aggregating the dust in the basement, I know exactly how it is configured, what services it runs, and how to reproduce it elsewhere.\nWhy Start Over? # As the number of machines grew, maintaining host-centric configurations quickly became insufficient. Each host had its own folder, its own system and home files, and often its own bespoke logic, even when the underlying requirements were identical. Structuring everything hierarchically through folders seemed like a good idea at first, but it soon became a burden. This approach simply did not scale. Adding a new machine or tweaking a shared setting meant copy-pasting or rewriting the same patterns, and I hate repeating code. In fact, repetition in any programming language is often a symptom of poor design.\nMore fundamentally, the original structure was organised around where things applied (e.g. imac, router, x280, x13) rather than what they did (e.g. desktop, dev, vpn, ssh, ai, virtualisation). This design decision had long-term implications, limiting modularity and reusability across the configuration.\nGoals for the Rewrite # Modularisation: Create features organised by functionality rather than by host\nI want to be able to define features once and reuse them across different machines. This will make it easier to maintain the configuration and reduce duplication. The idea is to group configuration files by their purpose, and not by the machine they apply to. This will make it easier to share and reuse code across different machines.\nAutomatisation: The loading of modules and configuration files\nEnough of dealing with manual file imports, I want to avoid manual loading of modules and configuration files. The system should automatically discover and load everything it needs dynamically.\nConsistency: Embrace a declarative and consistent approach to both NixOS and Home Manager\nI want to be able to declare my system and user configurations in a consistent way, using the same patterns and conventions across both NixOS and Home Manager. This will make it easier to understand and maintain the configuration.\nStandardisation: Modules can be reused across machines and configurations\nI want each module to be independent blocks, reusable across different machines and configurations. This will reduce code duplication and facilitate the maintenance.\nMaintainability: Facilitate the onboarding of new systems and their maintenance\nI want to make it simple to add new systems and maintain existing ones. This means reducing overall complexity, improving readability, and making it easier to understand how everything fits together.\nWhat Changed? # The pull request that introduced this change is a bit of a monster, but it had to be. The massive diff is largely due to the introduction of NixOS Facter and the inclusion of facter.json files. The large number of files is also a result of splitting the configuration into smaller, more focused modules living in their own files.\nSome parts of the old codebase still need to be migrated. I have temporarily moved them into a _to_migrate directory and plan to refactor them gradually. Migration is tedious and slow. One of the reason is that I need to generate the facter.json files on each machine while it is running. A few systems, like the Raspberry Pi router I had, have since been decommissioned, so I no longer have access to it\u0026hellip; but I still want to keep the configuration around, just in case.\nFlipping the Configuration Matrix # The new version adopts a fundamentally different approach: the configuration is now structured around features, not hostnames. It is a shift in the axis of composition, essentially an inversion of configuration control. What may seem like a subtle change at first has profound implications for flexibility, reuse, and maintainability.\n-\u0026gt; Instead of asking \u0026ldquo;what does the \u0026lt;insert-machine-name-here\u0026gt; need?\u0026rdquo;, I now ask \u0026ldquo;which features does this machine require?\u0026rdquo;\nThis shift enables:\nA feature like desktop support, VPN, SSH, or AI services to be implemented once as a reusable module All modules to live under a unified modules/ directory, loaded automatically, once, no manual glue logic System declarations can possibly remain per host like the previous pattern, but most logic is now shared, reused, and easily maintained How It Works # This project is built using flake.parts, a modular and composable framework for structuring Nix flakes. Unlike traditional monolithic flake setups, flake.parts allows me to break down the configuration into logical, reusable parts, each focused on a specific concern (e.g., formatting, NixOS modules, Home Manager modules). This keeps the flake configuration clean and scalable, and more importantly, promotes maintainability, extensibility, and collaboration.\nThe first step is enabling the modules feature in flake.parts, which allows you to define and aggregate modular custom configurations.\nI define two types of modules:\nnixos modules for system-level configuration, for NixOS machines only homeManager modules for user-level configuration, for NixOS machines, but not only, could be applied to any machine running Home Manager Together with vic/import-tree, these modules are automatically discovered and loaded. They are then aggregated by flake.parts into a single attribute set, which is used to build the final configuration.\nFor example, here is a custom flake.parts module. It defines the fonts configuration for both the dev and desktop features. No Home Manager configuration is defined here.\n{ flake.modules = { nixos.dev = { pkgs, ... }: { fonts.packages = with pkgs; [ dina-font monaspace ]; }; nixos.desktop = { pkgs, ... }: { fonts.packages = with pkgs; [ aporetic ]; fonts.fontconfig = { defaultFonts = { monospace = [ \u0026#34;Aporetic Sans Mono\u0026#34; ]; sansSerif = [ \u0026#34;Aporetic Sans Mono\u0026#34; ]; serif = [ \u0026#34;Aporetic Sans Mono\u0026#34; ]; }; }; }; }; } In the next example module, the module defines the dev and desktop Home Manager features. It does not define any NixOS configuration.\n{ flake.modules = { homeManager.dev = { pkgs, ... }: { home.packages = with pkgs; [ go php python3 rustc ]; }; homeManager.desktop = { programs.firefox.enable = true; }; }; } Once in the modules/ directory, these modules are automatically picked up by vic/import-tree in the main flake.nix file:\n{ description = \u0026#34;My Nix infrastructure at home\u0026#34;; inputs = { #... }; outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); } Note: This is the only place where import-tree is used !\nThe aggregated files are then merged into config.flake.modules.nixos by flake.parts, thanks to its built-in modules feature`. This merged configuration is ultimately used to build the NixOS configurations, a core capability enabled by Nix flakes.\n{ inputs, lib, config, ... }: let prefix = \u0026#34;nixosConfigurations/\u0026#34;; in { flake.nixosConfigurations = lib.pipe (config.flake.modules.nixos or { }) [ (lib.filterAttrs (name: _: lib.hasPrefix prefix name)) (lib.mapAttrs ( name: let hostname = lib.removePrefix prefix name; in { name = hostname; value = inputs.nixpkgs.lib.nixosSystem { modules = [ config.flake.modules.nixos.${hostname} ]; }; } )) ]; } Importantly, the file that declares this logic is itself also a flake.parts module! Every file in the project becomes a reusable building block, regardless of its location or filename. One of the major advantages of this approach is that it enables the definition of multiple configurations within the same file. I can now declare both NixOS and Home Manager modules side by side, and they will be automatically discovered and loaded without additional wiring. Although I do not currently take full advantage of this, the flexibility is built-in and could prove valuable in future scenarios.\nTo go one step further, it would be ideal to define a list of features for each machine and have both the system and home configurations automatically assemble themselves accordingly. Look no further ! This is precisely the role of the custom loadNixosAndHmModuleForUser function built for this project.\n{ inputs, ... }: { flake.lib = { loadNixosAndHmModuleForUser = config: modules: username: assert builtins.isAttrs config; assert builtins.isList modules; assert builtins.isString username; { imports = (builtins.map (module: config.flake.modules.nixos.${module} or { }) modules) ++ [ { imports = [ inputs.home-manager.nixosModules.home-manager ]; home-manager.users.${username}.imports = [ ( { osConfig, ... }: { home.stateVersion = osConfig.system.stateVersion; } ) ] ++ builtins.map (module: config.flake.modules.homeManager.${module} or { }) modules; } ]; }; }; } Finally, a host machine can declare its configuration as such:\n{ config, ... }: let modules = [ \u0026#34;base\u0026#34; \u0026#34;x13\u0026#34; \u0026#34;bluetooth\u0026#34; \u0026#34;desktop\u0026#34; \u0026#34;dev\u0026#34; \u0026#34;displaylink\u0026#34; \u0026#34;games\u0026#34; \u0026#34;git\u0026#34; \u0026#34;sound\u0026#34; \u0026#34;vpn\u0026#34; \u0026#34;virtualisation\u0026#34; ]; in { flake.modules.nixos.\u0026#34;nixosConfigurations/x13\u0026#34; = config.flake.lib.loadNixosAndHmModuleForUser config modules \u0026#34;pol\u0026#34;; } And voila!\nThe same pattern has been also successfully applied to another project of I did at work ecphp/devs-profile, a project offering user profiles, each packed with command-line programs and configurations designed specifically for developers. Perhaps I will write a blog post about it one day, but for now, I am happy to share that the same modular approach has been successfully applied there as well.\nLessons Learned # The biggest challenge in this rewrite was learning to organise modules by purpose rather than by name. It required unlearning the reflex to group files by machine. Instead, everything is now named for what it does: desktop, networking, shell, media, ai, and so on.\nThis turns the repository into a toolkit. Each feature simply declares where it should be applied. Each module is a building block that can be combined with others to create one or multiple custom configurations in the same files or spread across multiple files.\nTrade-Offs # Steeper learning curve\nEven after contributing to the flake.parts framework through a module, it took me a while to fully grasp how flake.parts works, not just in terms of its syntax, but also in understanding how the pieces fit together to build a clean and extensible structure. It is definitely the best Flake framework and it is simply out of this world! The power it offers is undeniable, but it requires a mindset shift and a solid understanding of the underlying model.\nOngoing and time-consuming migration\nMigrating the existing host-centric setup to the new functionally-driven model has been a slow and occasionally painful process. Not everything has been ported yet, and some machines are still waiting for their facter.json files to be generated. I am progressing gradually as I need those systems, but it is definitely a long-term effort.\nFuture Work # Continue maintaining and refining the repository\nWhile the new structure represents a significant improvement, I am not yet fully satisfied with it. There is still work to be done, particularly around completing the migration of older configurations to the new modular model. I have several ideas in mind for improvements, but they will require time and careful implementation.\nSimplify the user interface for defining a host machine\nThe current interface for defining a host machine is still a bit clunky, relying on a custom function (loadNixosAndHmModuleForUser). I would like to simplify it further, making it easier to define a machine and its features. This could involve creating a more user-friendly syntax or abstraction layer that hides some of the complexity of the underlying implementation.\nExpose Home Manager configurations for composability\nOne area I would like to explore further is how to expose individual Home Manager modules so they can be composed into reusable profiles. This would allow for the creation of more complex, user-specific setups without duplicating code. Each module should be exposed through the flake interface, enabling profile-based composition. I know it is technically possible, but I haven\u0026rsquo;t yet figured out the right approach. This definitely warrants deeper investigation.\nCreate a Nix starter template to help newcomers to adopt this approach.\nI would like to build a lightweight, beginner-friendly template to help others adopt this modular approach to managing NixOS and Home Manager configurations. The goal is to offer a clean starting point that does not overwhelm new users, while promoting good practices and reducing the learning curve. It is a small contribution that could have a meaningful impact for those just getting started.\nRename the project\nThe current name drupol/nixos-x260 no longer reflects the scope or intent of the repository. It originated with my Lenovo ThinkPad X260, but the project has evolved far beyond a single machine. I would like to choose a name that better represents its purpose.\nEdit: The repository renaming has been done a few days after the blog post was written. The new name is drupol/infra.\nInspiration # I would like to thank Shahar \u0026ldquo;Dawn\u0026rdquo; Or (mightyiam) for pioneering this approach. My repository is inspired by his work.\nConclusion # This rewrite brings the project into a new era. It is cleaner, more scalable, and far easier to extend. Shifting from a naming-based layout to a functionality-oriented one has made a world of difference.\nFeel free to suggest improvements or ideas. I am always open to suggestions and would love to hear your thoughts on this project. The project drupol/nixos-x260 is open-source and available on GitHub, so feel free to check it out and contribute if you want.\n","date":"1 May 2025","externalUrl":null,"permalink":"/2025/refactoring-my-infrastructure-as-code-configurations/","section":"Posts","summary":"","title":"Refactoring My Infrastructure As Code Configurations","type":"posts"},{"content":"Last year was quite something, I went through a lot, both personally and professionally.\nTo begin with, the first six months of 2024 were intense: juggling work, school, and writing my thesis simultaneously.\nIn June, my 3-year journey at the university came to a successful end. With my Master\u0026rsquo;s degree in Computer Science finally in hand and one fewer frustration, I defended my thesis on the 12th June 2024, and shortly afterwards, I made the full source available (on GitHub, on Codeberg). Since then, it has received several minor contributions from the community, which is great to see. The best highlight? I was invited to deliver both theoretical and practical sessions for students, focusing on software deployment and, of course, reproducibility. That marked the beginning of my formal collaboration with the university as a scientific volunteer in the Software Engineering team, something I am particularly proud of.\nOpen Source, still going strong # My involvement in open source continued to grow. In 2024, I contributed to 44 different projects (up from 38 in 2023), with 419 pull requests merged (compared to 357 in 2023).\nStatistics generated using oss-contribs I am still using Typst, and I can confidently say it has completely replaced LaTeX for me. I even migrated my CV template to Typst, and I continue to enjoy working with it. Typst strikes a perfect balance between simplicity and power, and at this point, I genuinely do not see myself going back.\nIn a similar spirit of adopting tools that just make sense, this year also marked the adoption of a new day-to-day tool: Jujutsu, a modern version control system, fully compatible with git. I installed it in September 2024 and have used it daily ever since. The more I work with it, the more I feel that git should have been designed this way from the start. Jujutsu is fast, efficient, and guess what\u0026hellip; it is written in Rust! What else could you want? One small thing perhaps for me, I really wish to see a consensus on a feature for improved patch identity/tracking (see this discussion) in the future, I think it would be very beneficial. Anyway, don\u0026rsquo;t try it, you might like it :)\nFrom PHP to Python # The middle of 2024 marked a significant shift in my professional landscape. Right after finishing my exams, the \u0026ldquo;PHP Development Competency Centre\u0026rdquo; team I had been part of for nearly 5 years was shut down without notice.\nDuring my time there, I contributed in various capacities: helping DGs transition from ColdFusion to PHP, delivering internal technical sessions, analysing and setting up solutions to unify development environments, setting up servers \u0026ldquo;in the cloud\u0026rdquo; and developing foundational tools for all PHP teams. Symfony was our go-to framework though some teams made other choices, which was perfectly fine, showcasing the flexibility inherent in open source and after all, it was still PHP.\nSince all the tools and artefacts I created are open source, I made a conscious effort to keep them generic and framework-agnostic. The best example is the cas-lib and ecas libraries, authentication solutions for the CAS protocol. In those projects, I deliberately relied only on standardised abstractions through interfaces (Thanks PSR!). This allows the library to be integrated into any PHP project, regardless of the framework, by requiring the consumer of the library to implement these standard interfaces. This approach shifts the responsibility for the concrete implementation details and integration security to the end user, where it belongs, while the library focuses on providing a robust, standards-compliant core.\nAlongside these efforts, I also contributed improvements and bug fixes to several of the open source projects we depended on, giving back to the ecosystem that made our work possible.\nOpen source demands more rigour, but it pays off. As the saying goes:\n\u0026ldquo;If everyone on a research team knows that everything they do is going to someday be published for reproducibility (hear: open source), they will behave differently from day one.\u0026rdquo; (source)\nOpen sourcing encourages better software, more thoughtful abstractions and clearer documentation. While many of my colleagues are not yet familiar with building and contributing to open source, I have had the opportunity to guide some of them. As a result, cas-lib now includes support for other PHP frameworks.\nI also managed versioning for the PHP packages, a not so pleasant task I seriously underestimated, even with Semantic Versioning. In total, we open-sourced 16 projects, something I remain genuinely proud of. Most of the authentication bundles I developed are still in use today internally but not only\u0026hellip; they are used at the University of Liège, and University of Aix-Marseille.\nAt the same time, I built and maintained the OSPO infrastructure running NixOS. Our note-taking server has been up and running without interruption for more than 2 years now:\n1root@note ~# uptime 2 16:51:01 up 817 days 3:46, 1 user, load average: 0.00, 0.00, 0.00 The entire infrastructure is version-controlled in a private Git repository, maintained collaboratively. Updating it is as simple as bumping the flake.lock file and deploying via deploy-rs. Everything is managed within a single repository: dependencies are pinned, deployments are boring and predictable fully bit-per-bit reproducible, upgrades are atomic and rollbacks effortless. It is as close to a dream setup as it gets, a level of transparency, security and control which is not achieved anywhere else at work.\nAnother project, developer-profile, continues to grow. Originally a proof of concept, it was completely rewritten into a robust CLI environment built around the Fish shell (also rewritten in Rust!), bundled with tools to support developers. It is now widely used among my colleagues and beyond, and I often recommend it to those curious about Nix and willing to pimp their command line.\nLastly, the proof-of-concept project ec-lib offers a set of reusable tools and utilities under the ec namespace. Among them are enhanced OCI (Docker, Podman,\u0026hellip;) image builders (ec.dockerTools.buildImage and ec.dockerTools.buildLayeredImage), which extend Nix\u0026rsquo;s native image-building capabilities by automatically embedding SBOMs into OCI container metadata. This approach is particularly valuable for teams that prioritise transparency, security, reproducibility, and compliance when building containers.\nSo, at the end of June 2024, I moved on to a new project with a new team, a completely different tech stack, and said goodbye to all the PHP projects I had built and maintained over the years. It felt a bit like leaving behind orphans,\u0026hellip; a bittersweet moment. I joined a team developing the institution\u0026rsquo;s internal AI chatbot. It was a brownfield project that was originally developed by a research department about a year earlier (press release). In the team, each developer worked in a distinct operating environment, which brought a diverse set of constraints and perspectives to the project.\nAddressing development environment inconsistencies # One of the first issues I tackled was the inconsistency in development environments.\nAt this point, you might erroneously assume that using our corporate laptops would already ensure a standardised and suitable development setup, the reality was quite the opposite. Despite being centrally managed, these machines often came with restrictive configurations and lacked the flexibility required for modern software development. As a result, many developers, including myself, chose to use their personal laptops to bypass some of these limitations and gain the freedom needed to work effectively. It is simple, I do not know any developers effectively using their corporate laptop. To compensate for this unsuitability, we were eventually provided with a cloud managed Ubuntu-based environment. This provided some relief, but came with its own constraints, which I discuss later. After evaluating the options available to us, namely Docker and Ansible, I concluded that while these tools had been useful in the past, they were no longer suitable for creating a consistent development environment across different operating systems. These technologies are now outdated when it comes to building reproducible and reliable environments for long-term use. I therefore chose Nix, which turned out to be an excellent decision. At first, most of my colleagues saw Nix as a UFO. However, after just a few weeks of using it, it was seamlessly integrated into our workflows and became transparent in day-to-day use. Overall, they were pleased with the results. Nix helped us save time, ensured consistency across environments, provided full transparency over dependencies, offered isolation from host systems, and improved team collaboration. It also made onboarding significantly easier, as new team members could set up a fully functional development environment in minutes, without having to worry about system-specific configurations. We were quickly able to spin up everything we needed, including the database, code interpreter and all essential tools, on any Linux or macOS machine. Nix gracefully blasted to smithereens an entire class of problems we had previously faced (and brought some new ones we didn\u0026rsquo;t have before as well !), and I am genuinely pleased with the outcome.\nEnhancing code quality and maintainability # While developing bugs and fixing features, I focused heavily on reducing complexity and improving reliability, by adding typing, refactoring, and writing more tests. A lot of code was duplicated to interact with the database through repositories and reducing code duplication was also a great concern to me. I refactored the code to remove as much code duplication as I could, used composition in place of inheritance and implemented a generic repository class. This generic repository is using the Returns library which has been very useful to implement repository methods that return something meaningful and fully typed while handling correctly all the potential issues that could happen when working with a database. Overall, these efforts led to a smaller, cleaner, and more maintainable codebase. That said, adopting the Returns library, promoting a more functional, declarative style and robust error handling, was not without its challenges\u0026hellip; but the outcome was worth it.\nI also contributed to improving the Git commit history by promoting the Conventional Commits standard. Some colleagues jokingly referred to me as a \u0026ldquo;Git n**i\u0026rdquo; for being a bit too strict about how I expected commits to be written and structured in pull requests, not the nicest nickname, but I took it as a compliment to my consistency.\nLast but not least, security was also an important concern throughout the project. I made sure to regularly update the Python interpreter, third-party libraries, and development dependencies (e.g., MongoDB, Mongo shell, ruff, etc,\u0026hellip;) on a monthly basis. Thanks to Poetry and Nix, this was not a painful task. It was quick, reproducible, and became part of the routine.\nReflections on language ecosystems # Switching from PHP to Python was not difficult. I truly enjoyed Python\u0026rsquo;s list/dict comprehensions, something I will miss if I ever do PHP again. What frustrated me most was the ecosystem. Many libraries seem to exist in the \u0026ldquo;zero-space\u0026rdquo; (PDF), with unclear governance or maintenance. The packaging landscape is chaotic: pip, poetry, uv, and conda all compete. I started with poetry, but would now choose uv.\nOverall, and feel free to disagree in the comments, I think Python is great for prototyping, scripting, and data science, but I would not use it for production. It is too permissive, too slow, and parts of its ecosystem lack maturity.\nOver the year, I have realised that being a software engineer is not just about writing code (and so on\u0026hellip;), but rather choosing the right tools, the right libraries and the right pattern for a given algorithm or project. It is not really about picking PHP, Python or whatever, but about understanding the constraints and goals of the task at hand and, ultimately making the right choice.\nA major part of making that right choice is dispelling a common software engineering illusion: the belief that adopting a new framework or library will magically erase technical debt.\nBefore adopting a shiny new tool (or library, or framework, or technology), our projects usually look something like this: a solid chunk of business value weighed down by a clear, predictable block of homegrown technical debt (e.g., spaghetti code, missing tests, reinvented the wheel, lack of automation, etc etc).\nThe before: A clear view of our own custom-made technical debt. When a team gets frustrated with this, the natural reflex is to reach for an external library or a comprehensive framework or another new tool. The expectation? That it will act as a silver bullet, sweeping away all our historical mess and leaving only pure, pristine business logic.\nThe expectation: The magical library (or framework or tool) that \u0026ldquo;solves\u0026rdquo; almost everything. But over the years, and particularly throughout 2024, I have come to realise that we never truly eliminate complexity\u0026hellip; we only change its shape. When we replace custom code with an external dependency, we are not deleting technical debt, we are merely trading it for \u0026ldquo;ecosystem debt\u0026rdquo;. The total volume of debt often remains the same or gets a little bit smaller, but it fragments into different, sometimes more insidious, forms.\nThe reality: Tesler\u0026rsquo;s law or \u0026ldquo;the law of conservation of complexity\u0026rdquo;. The debt is still there, just distributed differently (e.g., glue code, Dependency updates (CVEs), framework limitations, vendor lock-in, etc etc). Instead of fixing our own poorly written code, we find ourselves fighting impedance mismatches and discrepancies (e.g., writing complex \u0026ldquo;glue code\u0026rdquo; to force a framework to fit our specific business needs, tracking upstream breaking changes, managing security vulnerabilities, and debugging black-box abstractions).\nUltimately, adopting a third-party tool is not a magic trick for debt reduction: it is a governance choice. You are simply deciding whether you would rather maintain your own imperfect code or manage the relentless update cycles, potential bloatware, and architectural constraints of someone else\u0026rsquo;s. Since \u0026ldquo;every single line is a liability\u0026rdquo;, the same principle applies to every type of dependency. The key is to make these choices deliberately, fully aware of the trade-offs and to be prepared to manage the new form of complexity that comes with it.\nThoughts on digital sovereignty in the public sector # Throughout 2024, I found myself thinking more and more about digital sovereignty, especially in the context of public sector. For me, it goes far beyond the question of where data is hosted. Digital sovereignty is also about transparency, control, and the ability to fully understand and act on the software and infrastructure we depend on. It is about knowing what runs in production, being able to audit and modify it, and reducing dependency on opaque, proprietary ecosystems that leave little room for adaptability or scrutiny (Public money, public code).\nThis concern is particularly relevant today with the Cyber Resilience Act (CRA). It rightly puts a strong emphasis on software security, lifecycle management, and the transparency of software components. But it also raises practical challenges. Especially around how to generate, maintain, and verify Software Bills of Materials, how to track vulnerabilities in dependencies, and how to ensure compliance across increasingly complex supply chains.\nIn this context, reproducible builds, declarative infrastructure, and open development practices are not just nice-to-haves, they are key enablers of compliance. My commitment to open source was already motivated by ideals of robustness and reuse. But the CRA has added a new dimension: regulatory alignment. If we want to build secure, resilient, and future-proof systems in the public sector, we need the tooling, the culture and the governance models that support that vision.\nPublic institutions, in my view, have a responsibility to lead (it is time to lead by example) by example, not just by complying with regulations like the CRA, but by embracing the spirit of them. This means investing in open technologies, making software choices that prioritise transparency, autonomy, sustainability and avoid vendor lock-in at all costs, supporting reproducible and verifiable systems. This is not just a present-day concern\u0026hellip; it is a battle that has been fought (and arguably lost) before. A recent paper by Nora von Ingersleben-Seip, \u0026ldquo;How the European Union Fell Out of Love with Open-Source Software\u0026rdquo; (2025), details how the EU\u0026rsquo;s strong, pro-sovereignty stance on open source in 2004 was reversed by 2010 due to intense lobbying from proprietary incumbents. The paper is a sobering reminder that the push for digital sovereignty is constantly at risk from the political and economic influence of established technology giants.\nNavigating systemic challenges: frustrated by design # My experiences in 2024, particularly within a large public IT institution, brought my frustration to a climax and led to broader reflections on systemic challenges. While once considered a prestigious place for forward-thinking projects, I have felt a growing sense of frustration. I\u0026rsquo;ll be very blunt, apologies beforehand for it, but after more than ten years, I have seen how administrative complexity, excessive meetings, and communication challenges can, at times, significantly hinder progress. Over the years, I have noticed that key decisions are sometimes made without sufficient analysis or consultation, and important decisions are not clearly documented or justified. The environment can feel excessively bureaucratic, with vague strategic direction and limited no space for genuine innovation. Often, there is no valid technical reasoning behind accepting or rejecting a decision, a tool or technology, and many projects lack any coherent long-term strategy. Rather than leading the way in digital transformation, as we ought to be, it often feels as though we are simply chasing trends or implementing ideas that someone dreamt up overnight, without any real vision, justification or governance. That said, I still believe it has the talent, capacity and responsibility to lead by example. If we can shift the focus from overly procedural discussions to more outcome-oriented collaboration, things could genuinely improve.\nA clear example of this lack of future-proof vision was the abrupt shutdown of the PHP team I was working in. Around 2019, we were encouraged to adopt PHP, which was, at the time, the officially recommended language for web applications. Many of my colleagues were unfamiliar with it, but they took the time to learn, they were even offered training and gradually migrated their legacy applications. It was not without difficulty, but they succeeded, supported by my team throughout the process. However, the decision to shut down our team was made, and the consequences were clearly not fully considered. Over the years, I had developed a substantial collection of tools and infrastructure that were widely used internally, all of which suddenly found themselves without maintainers. Thankfully, these projects are open source and remain accessible, but without a team to coordinate their evolution. And, unsurprisingly, one of the most important of these projects is related to security and user authentication. Many colleagues expressed their frustration and confusion over the decision, as it seemed to lack any clear rationale. Faire et défaire, c\u0026rsquo;est ne rien faire! they remarked. While this decision may have allowed someone to justify their precious time (and salary!), it left others questioning its purpose. They valued having our team acting as a coordinating hub of the open-source development of shared building blocks for so many applications. I completely understand their perspective and share their frustration. IMO, this was a surprising decision that led to missed opportunities for efficiency, a risk of losing domain expertise, and a challenge for meaningful collaboration across teams using shared, open-source tools and libraries. The overall direction felt at times disjointed, lacking a clear long-term strategy, consultation, or continuity.\nA recurring technical obstacle was the absence of consistent versioning practices across teams. Very few followed Semantic Versioning, which led to confusion, compatibility issues, and delayed releases. I never thought I would say this, but in our case, a monorepo could have saved us a lot of time. I proposed this approach, but it was dismissed. Some perceived it as a step backward, with comments like \u0026ldquo;Yeah sure, we’ll use a monorepo like 10 years in the past!\u0026rdquo;. Rather than dismissing ideas based on trends, I think we should assess each proposal on its practical merits, case by case.\nAnother major technical challenge was the mismatch between our tech stack and operational realities. Python is ideal for rapid prototyping, but applying rigid release cycles to dynamic tools leads to friction. We had a single shared dev environment, no per-developer sandboxes. Requesting one felt harder than scaling Everest, bare-handed and ropeless.\nAs already mentioned before, local development on our corporate laptops was difficult impossible, mainly due to the constraints of the Microsoft operating system and limited access to necessary tools and network resources due to internal policies.\nIn this context, initiatives like EU-OS are worth having a look, it represents a promising step towards improving the user, and to some extent, developer experience in a more autonomous and sovereign way. Investing in these efforts could help align technical workflows with European values.\nTo work around these limitations, we were provided with a remote Ubuntu-based environment. While using Linux is a step forward, it also introduced its own drawbacks: relying on a US-based company for sensitive EU data and applications (btw, do you know what Recall is?), performance bottlenecks, a sluggish user interface, the need to use a proprietary client to connect, and the lack of SSH access. At a time where digital sovereignty is key, especially in this very special political context, this is a concern, don\u0026rsquo;t you think? This highlights the recurring challenge for public institutions to reconcile immediate operational needs with broader strategic goals like autonomy and sovereignty.\nWith the wider adoption of mainstream collaboration tools from across the Atlantic, things have not always improved as expected. While these tools are theoretically designed to enhance communication, they often result in information overload or misalignment practically. More importantly, they seem to have eroded the sense of human connection between colleagues. Cameras are rarely turned on during meetings (that could last a whole day sometimes!), and I have worked with some people without ever meeting or seeing them, I do not even know what they look like. This lack of personal contact, likely amplified by widespread teleworking, makes collaboration more transactional and less empathetic, and gradually chips away at the team spirit that is so essential to meaningful and effective work. Despite the frustrations, great technical discussions with colleagues kept me sane. I learnt a lot and hopefully taught a bit too. This is also why going back to the office is important for me, I would not want to go back everyday, but I believe that keeping a balance of ±2 days per week is sufficient. Sometimes, the best ideas come from a stupid joke, a random conversation at the cafeteria or an after-lunch walk and I believe this helps to keep the team spirit alive.\nIn such a constrained environment, where technical freedom is limited and tooling is often suboptimal, developers cannot afford to ignore complexity. Quite the opposite actually! They must actively seek to reduce it. Every layer of indirection, every unnecessary abstraction, and every workaround adds overhead to an already fragile workflow, every single line is a liability. Simplicity is not just a design choice, it becomes a necessity. In this context, good software engineering means keeping things simple, easy to understand, and easy to maintain. When everything around is already complex, there is no need to make the codebase even harder to work with, right?\nSimplicity is a great virtue, but it requires hard work to achieve and education to appreciate. And to make matters worse, complexity sells better — Edsger Dijkstra\nThe situation could be improved by embedding continuous learning, training, and education more organically into daily work. Creating space for shared learning experiences such as internal workshops, technical deep-dives, or collaborative study groups, can reignite curiosity, foster empathy, and help rebuild a stronger sense of purpose. Public institutions have much to offer and much to learn. These doors should remain open, but that still requires the will to make it happen.\nIn November 2024, I attended Benevol2024, a Software Evolution workshop at the University of Namur. It was important for me to be there since I contributed a very tiny bit to \u0026ldquo;An Overview and Catalogue of Dependency Challenges in Open Source Software Package Registries\u0026rdquo;, a paper that was presented for the first time by Tom Mens. A great experience, and I hope to attend more. It reminded me how much could be gained by fostering closer ties between academic research and public institutions.\nOne concrete manifestation of this disconnect is visible in the way many teams have started setting up their own infrastructure. Without alignment, shared vision, or trust in central services, they avoid the official solutions provided by central IT services, which are perceived as too expensive, too old, too slow to evolve, lacking features, or difficult to adapt to their needs. This is particularly evident in the push for unified CI/CD pipelines. The central department invests heavily in this area, but seems to forget that before standardising the pipeline, it is essential to standardise the projects themselves, perhaps developing them with the consistency and rigour you would expect from an open-source project! Instead, the result is often overly complex CI pipelines where declarative YAML is intertwined with an infinite list of imperative commands, written in a chaotic mix of programming languages. There is absolutely no effort to abstract these scripts into concrete projects, which not only makes them impossible for developers to run locally but also prevents any form of reuse elsewhere. This approach leads to solutions that are overengineered, underdocumented, and reinvented from scratch in each project, ultimately increasing the bus factor. This fragmentation leads to duplicated effort, increased maintenance costs and inconsistent practices across institutions, ultimately working against the goal of long-term sustainability and collaboration. Internally, DGs, including the central IT department, share almost nothing of what they build and often develop similar tools or components (e.g., multiple check in/out applications, multiple chatbot instances, too many Gitlab instances, \u0026hellip;) in parallel. This presents a significant opportunity for further harmonisation and resource optimisation, which could be better achieved through improved coordination and shared efforts.\nIt is frustrating to see so much duplication of effort and missed opportunities for collaboration in an environment that could and should be setting the standard. Instead of resisting these developments, the institution could actively engage with its clients and users. A shared working group with rotating membership could collect feedback, identify needs, and propose modular, reusable solutions, open-source when possible. This would lower maintenance costs and foster cross-DGs collaboration. But more importantly, rather than selling expensive services, the department could shift its focus towards co-creating solutions with its users: listening first, then building flexible, extensible tools that address real needs. This user-centred approach would reduce redundancy, increase adoption, and make better use of shared infrastructure. By investing in horizontal interoperability instead of vertical silos, the organization could re-establish itself not as a vendor, but as a trusted enabler of digital public services, one that facilitates collaboration, simplifies workflows, and amplifies the impact of internal talent. This is particularly important in an organisation that has the people, the resources, and the potential to set an example for others.\nI believe there is still a real opportunity and responsibility for the institution to reclaim its role as a pioneer in IT.\nLastly, another challenge has been the divide between officials and contractors. One particularly painful moment came when a senior official publicly attributed the institution\u0026rsquo;s security problems to [sic] \u0026ldquo;stupidity by developers\u0026rdquo;, a carefully chosen phrasing that, even if unintentional, was not appropriate and demoralising. As a contractor and developer, it stung. I make mistakes, I fix them, I learn. We are humans, we all do. Growth happens when we support each other, not when we shift blame. When mutual respect and systemic thinking are lacking, it becomes increasingly difficult to stay motivated and engaged. At the same time, if we truly want to improve quality and security, perhaps it is time we move away from blaming individuals and start engaging in a bit of introspection (after all, the institution is responsible for hiring!). This includes taking a critical look at structural issues. Maybe the hiring process deserves scrutiny? But what about the recruitment office selection mechanism? Long criticised for failing to meet the institution\u0026rsquo;s real recruitment needs (source)! If we want to build resilient teams, we should be open to improving our hiring, mentoring, and collaboration models. The challenge is to align systems and strategies so that we can build better things together, regardless of whether we are contractors or officials.\nLooking forward # While the issues I have described here only reflect my own experience, they are by no means unique to it. Similar patterns of fragmentation, misalignment, and underutilisation of internal talent can be observed across many different public institutions. These challenges are often systemic, rooted in legacy structures, risk-averse mindsets, and the tension between political expectations and technical realities. Recognising this does not excuse the problems but it does suggest that meaningful change will require collective effort, shared learning, and a willingness to reimagine how we build, govern, and sustain digital public infrastructure across the board. You think that sounds too optimistic? I still believe it is possible, and I hope to see public institutions move more decisively in that direction.\nThis article was published in February 2026 and immediately removed after less than an hour. I actually thank the person who alerted me about it. I reworked it and published it again, hopefully for good this time. The views expressed in this post are my own and do not necessarily reflect those of my employer or any institution I am affiliated with. This reflection is based on personal experience and observations. I used a very old refurbished server hosted in my basement to fix the typos of this text using different open-source LLM, using Ollama and Open-WebUI. ","date":"11 February 2025","externalUrl":null,"permalink":"/2025/retrospective-2024/","section":"Posts","summary":"","title":"Retrospective 2024","type":"posts"},{"content":"","date":"11 February 2025","externalUrl":null,"permalink":"/tags/thesis/","section":"Tags","summary":"","title":"Thesis","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/algorithm/","section":"Tags","summary":"","title":"Algorithm","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/complexity/","section":"Tags","summary":"","title":"Complexity","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/information-theory/","section":"Tags","summary":"","title":"Information Theory","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/mathematics/","section":"Tags","summary":"","title":"Mathematics","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/php/","section":"Tags","summary":"","title":"Php","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/random/","section":"Tags","summary":"","title":"Random","type":"tags"},{"content":"","date":"18 January 2024","externalUrl":null,"permalink":"/tags/randomness/","section":"Tags","summary":"","title":"Randomness","type":"tags"},{"content":" I often advocate for a straightforward yet effective rule: the shortest solution that delivers the desired result is usually the best. This approach, favoring concise algorithms, not only ensures efficiency but also reduces maintenance cost and bug susceptibility. Intriguingly, this practical principle finds its theoretical counterpart in data compression algorithm, data analysis and machine learning through the Minimum Description Length (MDL) and the Kolmogorov Complexity. These concepts delve deep into the essence of data representation and algorithmic efficiency.\nThe MDL principle is an invaluable tool. It is grounded in the concept of succinctly capturing information and is essential in balancing model complexity with its explanatory power. The ideal model, according to MDL, is one that minimizes the combined description length of the model and the data. This principle is not only pivotal in guiding model selection but also reflects the deeper mathematical underpinnings of Kolmogorov complexity.\nKolmogorov complexity is about the shortest possible description of an object within a given computational model. It focuses on the simplest, most concise representation of data that a computer can use to reconstruct the original object. However, it is crucial to understand that the Kolmogorov complexity is, just like the Halting problem, inherently uncomputable. This means that even if we stumble upon the shortest possible program that replicates a specific output, there\u0026rsquo;s no definitive method to prove that there isn’t a shorter program capable of achieving the same result. This uncomputability aspect of Kolmogorov complexity adds an extra layer of fascination. It underscores a fundamental limitation in our ability to fully comprehend data representation\u0026rsquo;s simplicity, highlighting the provisional nature of our knowledge in data analysis and machine learning.\nContrary to what Mortal Kombat fans might think, Kolmogorov complexity isn’t named after a final boss but after the renowned Russian mathematician Andrey Kolmogorov, Kolmogorov complexity offers a unique perspective on assessing data complexity. It diverges from traditional metrics by focusing on information content rather than sheer size. This post is a very quick and dirty introduction to what Kolmogorov complexity is, starting with its foundational principles and progressing to practical examples. Don\u0026rsquo;t forget to check out the disclaimer at the end of the post.\nLet\u0026rsquo;s introduce Kolmogorov complexity with the notion of random. What is the meaning of a random string? Let\u0026rsquo;s consider the following 64-character example strings, and evaluate together their perceived randomness:\n1111111111111111111111111111111111111111111111111111111111111111 1234567890123456789012345678901234567890123456789012345678901234 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069 The 64-character strings and their corresponding PHP code are used purely for illustrative purposes to demonstrate the principles of Kolmogorov complexity. It is worth noting that these examples are intentionally simplistic and not intended to represent optimal or real-world scenarios. The choice of 64 characters serves as a convenient length for demonstration, making the concept approachable and understandable, even though in practical applications, the length and complexity of strings might significantly vary. Furthermore, while PHP may seem verbose in these instances, it is chosen for its simplicity and accessibility, especially for those not deeply versed in programming. The key takeaway is not the length of the PHP code per se, but the underlying idea of Kolmogorov complexity: the search for the simplest possible description or program that can generate a given output. Real-world applications of Kolmogorov complexity often involve much longer strings and more intricate computations, where the efficiency and conciseness of the description become markedly more pronounced and impactful. At a glance, the first string 1111111111111111111111111111111111111111111111111111111111111111 does not look like a random string. It can be succinctly described as \u0026ldquo;64 1\u0026rsquo;s in a row\u0026rdquo;, therefore it has low Kolmogorov complexity. This can be demonstrated in PHP. The length of the PHP code is 25 characters, significantly shorter than 64. This substantial difference in length not only generates the entire string but also highlights its high compressibility rate, thereby underscoring its very low randomness.\necho str_repeat(\u0026#39;1\u0026#39;, 64); // 25 characters The second string 1234567890123456789012345678901234567890123456789012345678901230 appears to be random and complex at first glance. However, this string is a repetitive sequence of the digits from 0 to 9. Much like the first string, there\u0026rsquo;s no much random in it and its Kolmogorov complexity is low. it can be described succinctly as \u0026ldquo;the sequence 0 to 9 repeated 7 times and trimmed to 64 characters\u0026rdquo;. The length of the PHP code is 48 characters, which is shorter than 64, also hightlighting its high compressibility rate and therefore its low randomness.\necho substr(str_repeat(\u0026#39;1234567890\u0026#39;, 7), 0, 64); // 48 characters Here, the PHP code generates the string by repeating the sequence 1234567890, effectively constructing the 64-characters string. The simplicity of this PHP code demonstrates that the string, despite appearing random and complex, has a relatively low Kolmogorov complexity due to its underlying repetitive pattern. This example, along with the previous ones, illustrates how Kolmogorov complexity is not merely about the visual complexity or length of a string, but rather about how succinctly the string can be described or generated. The concept of randomness in Kolmogorov complexity is closely tied to the absence of such describable patterns.\nIn the third key smashed example string 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069, initially seems to have high Kolmogorov complexity. It does not lend itself to a simple algorithmic description and therefore appears incompressible and algorithmically random. The PHP code to generate this string, which includes the original string itself, spans 72 characters, exceeding the original string\u0026rsquo;s length. When the code to reproduce a string is longer than the original string itself, it indicates a very low compressibility rate. This means the string cannot be compressed further, thus suggesting its high level of randomness.\necho \u0026#39;7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069\u0026#39;; // 72 characters While all three strings have the same probabilistic chance of being randomly selected, their complexities vary. This illustrates how randomness in Kolmogorov complexity is tied to the ability to describe patterns succinctly. This paradox highlights that randomness transcends probability, linking instead to the presence or absence of patterns and the succinctness of their descriptions. The shorter the description required, the less random the string is considered, as seen with the first two strings. Conversely, a string requiring a more extensive explanation, due to lack of regular patterns, is deemed more random, as with this very last example.\nThe Kolmogorov complexity is not just about the subject itself but also about the language and tools used for its description. Different programming languages or descriptive frameworks might have varying levels of conciseness for the same concept. For instance, what is succinctly expressed in one language might be more verbose in another.\nThis can be found in the formal definition of Kolmogorov complexity:\n$$ K_f(x) = \\min \\lbrace |p|: f(p) = x \\rbrace $$Interpreted, this formal definition states: The Kolmogorov complexity $K$ of a string $x$, relative to a Turing machine $f$ (a programming language), is the length of the shortest program $p$ that outputs $x$ when run on $f$.\nAn intriguing aspect of Kolmogorov complexity lies in its inherent uncertainty. This uncertainty stems from the possibility that a shorter description for a given string may be discovered in a near or far future. Since the Kolmogorov complexity is uncomputable, there\u0026rsquo;s no definitive way to prove that a shorter description does not exist.\nKnowing this, we can safely say that Kolmogorov complexity establishes an upper limit of complexity but not a lower one. When we write a program to generate a particular output, this program serves as definitive evidence that the sequence\u0026rsquo;s Kolmogorov complexity is, at most, equal to the length of that program. However, this does not imply a minimum level of complexity for the sequence. There is always the possibility that a shorter program capable of producing the same sequence exists. Therefore, the true Kolmogorov complexity of a sequence remains simply unknown, with the potential for more concise representations yet to be discovered.\nThe complexity assigned to data today might change as our understanding and technological capabilities evolve. This means that while Kolmogorov complexity offers a valuable framework for assessing data complexity, its nature is provisional. The complexity of a string reflects our current limitations and understanding, reminding us that our grasp of data complexity is always subject to revision and improvement. From this perspective, a string is random if it is incompressible, meaning it cannot be described by a shorter program. Conversely, a string is compressible if it can be described by a shorter program.\nFormally, this can be defined as: $$ K_f(x) \\geq |x| $$This means the Kolmogorov complexity relative to a Turing machine $f$ of a supposedly incompressible string $x$ is always greater than or equal to the length of the string itself. In other words, the Kolmogorov complexity of a true random string is always greater than or equal to its length. This is because the random string $x$ cannot be described by a shorter program.\nTo illustrate this, take the third example string 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069, initially seems highly complex. However, this string is actually the SHA-256 hash of Hello World!. Knowing this, the string can be succinctly described as \u0026ldquo;the SHA-256 hash of \u0026lsquo;Hello World!\u0026rsquo;\u0026rdquo;; reducing significantly its randomness and complexity. The length of the PHP code is now 36 characters, which is shorter than 64.\necho hash(\u0026#39;sha256\u0026#39;, \u0026#39;Hello World!\u0026#39;); // 36 characters The MDL principle and Kolmogorov complexity together offer profound insights into the very nature of information. MDL provides a practical methodology for model selection in data analysis and machine learning, focusing on the balance between simplicity and explanatory power. On the other hand, Kolmogorov complexity contributes a theoretical foundation, underscoring the importance of succinctness and efficiency in information representation. This includes applications in fields like data compression and number theory. The interplay between these two concepts highlights the critical importance of considering both the chosen model and the language used for complexity assessment. As we delve further into the intricacies of data and computation, grasping these principles thoroughly becomes ever more crucial. These principles enhance our ability to effectively grasp and interpret the essence of information within our rapidly evolving digital landscape.\n\u0026hellip;, isn\u0026rsquo;t it? To go further into these topics, I highly recommend exploring the foundational ideas and detailed insights offered in the following papers and resources which I used as references for this post:\nA Brief Introduction to Kolmogorov Complexity from Michal Koucky An Introduction to Kolmogorov Complexity and Its Applications from Ming Li The Minimum Description Length Principle from Peter D. Grünwald Kolmogorov complexity - a primer from Jeremy Kun Kolmogorov complexity from Brilliant Randomness, Information Theory, and Kolmogorov Complexity from Ananda Montoly I\u0026rsquo;m just an IT professional with a deep fascination for these kind of concepts that resonates while writing code, sometimes without knowing that they are formally defined. My aim with this post is to share my enthusiasm and understanding of Kolmogorov complexity and the MDL principle, hoping to spark interest in others. While I strive for accuracy, I encourage readers to seek out more detailed and expert resources if they wish to delve deeper into these intriguing subjects. ","date":"18 January 2024","externalUrl":null,"permalink":"/2024/understanding-kolmogorov-complexity/","section":"Posts","summary":"","title":"Understanding Kolmogorov Complexity","type":"posts"},{"content":"It\u0026rsquo;s been a while since I last took the time to write here. 2023 has proven to be a particularly interesting year, filled with numerous projects and a wealth of learning opportunities. Throughout the year, I\u0026rsquo;ve contributed to 38 open-source projects, resulting in 357 merged pull requests.\nstatistics made using oss-contribs I am quite pleased with the volume of contributions I\u0026rsquo;ve made. There\u0026rsquo;s been a significant increase in merged PRs since I began contributing to NixOS, a Linux distribution I strongly recommend exploring if you haven\u0026rsquo;t already.\nOne of my most notable achievements in 2023 was the introduction of a new PHP builder for the Nix package manager (NixOS/nixpkgs#225401) after a couple of months of work. Initiated on the 9th of April and merged on the 14th of September, this builder aims to simplify the deployment and distribution of PHP applications in Nix, it a reproducible way. Moreover, it allows for the construction of applications with specific PHP versions, extensions, and dependencies, paving the way for a more reliable method of delivering PHP applications in Nix. To accomplish this, I delved deeply into Nix, learning about its language and internals. A custom Composer plugin was developed, available at nix-community/composer-local-repo-plugin. Admittedly, I had hoped for a more straightforward solution, but this plugin currently stands as the best approach I\u0026rsquo;ve discovered.\nAnother significant result of my efforts was a one-line patch in Composer (the PHP package manager) that ensures stable and deterministic outputs. As a result, executing the command composer install twice will now produce identical vendor directories. The pull request for this change is available at composer/composer#11663. This work not only enhances overall PHP support but also aims to raise awareness within the PHP community about the critical importance of reproducibility and determinism, aspects often neglected by many developers.\nIn pursuit of this, I\u0026rsquo;ve contacted maintainers of popular PHP projects to include a composer.lock file in their repositories. This file, generated by Composer, specifies the exact version of dependencies used by a project. Composer uses it to ensure consistent dependency versions during installations, and the new Nix builder employs it to guarantee identical builds. Here are some of the projects where I\u0026rsquo;ve requested the addition of a composer.lock file:\nsebastianbergmann/phpunit#5576 phpro/grumphp-shim#23 bobthecow/psysh#767 PHP-CS-Fixer/PHP-CS-Fixer#7590 vimeo/psalm#10446 If you appreciate my open-source contributions and influence, I warmly invite you to consider sponsoring my work, this would greatly help me. During this year, I\u0026rsquo;ve been invited to gave a talk at the International PHP conference in Munich. The talk focused on the integration of Nix in the PHP ecosystem (Find the slides here).\nOverall, 2023 has been filled with positive experiences. I\u0026rsquo;ve had the pleasure of meeting for the first time wonderful people at SymfonyCon Brussels, as these photos attest.\nFrom right to left: Sebastian, Jordi, Stephan, Nils, Theo and Ondřej Finally meeting people I\u0026rsquo;ve interacted with through GitHub issues and pull requests was a highlight. The relational aspect of the conference was incredibly engaging, perhaps even more so than the talks themselves.\nToon and me 2023 was also a year of significant change for me. Alongside reducing my digital footprint by leaving Twitter and Reddit, I\u0026rsquo;ve quietly reevaluated the circles I engage with in real life. I\u0026rsquo;ve grown fond of using Lemmy and Mastodon, which I find to be excellent platforms.\nIn addition to my numerous projects and contributions, a noteworthy highlight of 2023 was my discovery of Typst. Typst is a tool that has completely transformed my document creation process. I\u0026rsquo;ve long been a user of LaTeX for its precision and control. However, Typst emerged as a game-changer, offering an intuitive, efficient, and flexible alternative. Its streamlined syntax and powerful features quickly made it my go-to tool, entirely replacing LaTeX for my needs. This shift not only sped up my workflow but also opened up new possibilities for creativity and efficiency in my document creation. Its adoption is a testament to the continual evolution of my tools and practices, always seeking the best solutions to enhance productivity and quality.\nUnfortunately, the year didn\u0026rsquo;t conclude as positively as I had hoped. It is with profound sadness that I share my beloved furry and pointy friend Izumi is nearing the end of his journey here on Earth.\nCats has been part of my life since my childhood, when I was living with my parents, we had 2 or 3 cats living around, mostly house cats, we were in love with Siamese and their very distinctive character. When I moved in the first time, I was living alone, I was missing the presence of a cat, so I wanted to adopt one, but since the house didn\u0026rsquo;t had a garden, I didn\u0026rsquo;t do it. Then I moved into an appartement, still no garden. However, in 2014, a twist of fate led me to an advertisement for an Havana Brown. I visited the breeder out of mere curiosity, with no intention of bringing home a cat. The house was lively with dogs, cats and children. Amidst the chaos, I noticed a small, furry creature majestically lying on a cushion right in front of the fireplace, observing its surroundings in total indifference. When the owner placed the little one in my arms, Izumi gazed up at me, and in that moment, I knew I wouldn\u0026rsquo;t be returning home alone.\nIzumi, the first days at home Izumi was no ordinary cat. He was profoundly attached to me, following me everywhere, talking with me, sharing my bed (at least when I was single), and eagerly awaiting my return home, the bond between us was strong. He enjoyed car rides and could recognize familiar destinations. He was more than a pet. He was my shadow, my friend, my confident. He was always there in the most difficult moments of my life, his contagious wisdom was something I\u0026rsquo;ll never forget. Time has passed, I moved in and out and since then I moved into a house with a garden and what would be a house with a garden without at least two cats? So, I adopted Nakano, a friend for Izumi. After a week of grimacing, they became totally inseparable.\nIzumi and Nakano, the inseparables In mid-December, Izumi began to show signs of illness and lost weight drastically. I promptly took him to the vet, only to receive the heart-wrenching news that his kidneys were irreparably damaged. The shock and devastation hit me suddenly\u0026hellip; everything unfolded so quickly. The vet\u0026rsquo;s prognosis was grim, indicating that he wouldn\u0026rsquo;t see the new year. I was totally unprepared. Unprepared to see him in pain, unprepared to say goodbye. We were and still are devastated.\nHe underwent treatment at the vet for three days, connected to a drip, but his condition showed no signs of improvement. With a heavy heart, I decided to bring him home, to spend his last days in a familiar and loving environment. The uncertainty of how much time he has left weighs on me, it\u0026rsquo;s unfair, but I am committed to ensuring his remaining time is as comfortable and serene as possible.\nIzumi As I navigate the difficult waters of grief, I am reminded that the bond we shared with Izumi was one of life\u0026rsquo;s true gifts. He was not just cherished from the very beginning but also a profound source of wisdom, joy, and an immeasurable amount of love. His affection was a constant, comforting presence, weaving through each day, enriching every moment we spent together. While the future is uncertain and the pain of loss cuts deep, I carry forward the love he so freely gave. As this year closes, I brace for a season less bright without his light, yet I hold onto the hope and resilience that his love instilled in me. Here\u0026rsquo;s to the journey we shared, to the love that will forever remain, and to the paths yet to be discovered in the new year. Maybe, just maybe, they\u0026rsquo;ll be a little kinder, a little gentler, with the memory of Izumi\u0026rsquo;s unwavering love lighting the way, as a shinning star.\nOn the afternoon of the last day of the year, Izumi gently passed away in my arms, purring peacefully while looking at me just like the very first time\u0026hellip;\nThe last photo of Izumi (2013.03.11 - 2023.12.31) Rest in peace, gentle companion of my way, In Elysian fields, where surely you stray. Your spirit remains with me, never does it flee, Izumi, my friend, in my heart eternally. And in a realm where all spirits are free, I hold onto the hope, we will meet again, just wait and see. ","date":"23 December 2023","externalUrl":null,"permalink":"/2023/retrospective-2023/","section":"Posts","summary":"","title":"Retrospective 2023","type":"posts"},{"content":"","date":"1 January 2022","externalUrl":null,"permalink":"/tags/flakes/","section":"Tags","summary":"","title":"Flakes","type":"tags"},{"content":"2022 has just started and I\u0026rsquo;ll take the opportunity to summarize what happened in 2021.\nI will use different binoculars or point of view, here they are:\nOpen-source: Stuff related to open-source contributions Work: Stuff related to work Random: Stuff related to Nixos This post might be a bit longer than usual, fear not and hang on tight!\nOpen-source # marcosh/lamphpda # In my previous post, I briefly wrote about [Functional programming and PHP 8][0]. The delay previous post and this one has been very long most probably because I continued learning functional programming by myself.\nOne of my personal happiest achievement in 2021 was to understand the fundamentals and basics of [monads][88] (or hopefully I believe I understand them).\nUnderstanding monads is a goal that I had in mind since quite a long time, without having the time to really understand them.\nThere\u0026rsquo;s a lot of literature and videos about monads on the Internet, and now that I understand them a bit better, I can safely say that there is actually not any single tutorial that I would recommend to anyone willing to learn them, without actually scaring them.\nDo you remember the infamous definition: \u0026ldquo;A monad is just a monoid in the category of endofunctors\u0026rdquo; ?\nMe neither!\nAnd as if that wasn\u0026rsquo;t enough yet, once you figure them out, you lose the ability to explain them! It seems that [Douglas Crockford][2] was right!\nAnyway, if you really dare to understand them a bit better, I found [this youtube video][4] from [Brian Beckman][6] very nice.\nObviously, watching tutorials and videos helps but the best way to understand them is to dive into a project using monads\u0026hellip; or contribute to a projects implementing monads with your favorite programming language. And that\u0026rsquo;s precisely what I did!\nI started looking for a PHP package implementing monads, there are many. After analyzing them, I decided to go with [marcosh/lamphpda][7] from [Marco Perone][8].\nI chose this package because Marco is involved into functional programming (FP), PHP and has a strong background in mathematics. Besides his great teaching skills and patience, he understand not only the code, but most of the mathematical background needed for implementing monads. He\u0026rsquo;s also the organiser of [Functional Fest][10], a group of FP enthusiasts hosting regular conferences with awesome guests and speakers.\nI started by creating [a couple of pull-requests][12] and using the package in my own projects.\nI used monads for handling Doctrine repository queries in Symfony and in the end, created an open-source package that everyone can use. You can find everything in [loophp/repository-monadic-helper][14].\nThe next task that I\u0026rsquo;m planning to do to keep on learning, is to refactor [loophp/tin][48] using [marcosh/lamphpda-validation][50], a validation package based on [marcosh/lamphpda][7].\nloophp/collection # My other project [loophp/collection][16] is still being actively maintained, and I was quite surprised when I saw that the project was about to reach the five hundred stars milestone, just before New Year\u0026rsquo;s Eve !\nAnd we did it, just in time !\nThe version 6 is currently stable and there is already a couple of things going on for the next major release, the version 7. Besides the usual new features, optimizations and bugfixes, the most important change for me is that I got rid of PHPSpec and completely replaced it with [PHPUnit][18], see the monster [PR][20].\nI will not compare the frameworks here, I\u0026rsquo;ll leave it to the readers of this blog. From now on, I will now use PHPUnit by default in all my projects.\nSwitching to PHPUnit allowed me to completely refactor some tests. Testing is now faster and clearer. However in order to do that, I had to make sure that it was possible to compare two types of iterables.\nHowever, there is currently no PHPUnit assertions to assert that two iterables are the same. This is why [loophp/phpunit-iterable-assertions][22] was written. This is a PHPUnit plugin which provides new assertions to assert that two iterables are the same.\nAsserting that two iterables are the same means that for each item in both iterables, key and value are the same. Also, the iterables should have the same amount of items.\nCreating such a PHPUnit plugin requires the use of a very special iterator, a [ClosureIterator][90]. The ClosureIterator iterator is also the heart of [loophp/collection][16]. I hate duplicated classes and code, so I created a very simple package [loophp/iterators][24] containing the \u0026ldquo;missing\u0026rdquo; PHP iterator and a couple of others. That package is now a dependency of [loophp/collection][16] and [loophp/phpunit-iterable-assertions][22], no more duplicated code!\nWhile writing that package, I found something very cool that I want to share.\nEvery PHP developers are (or should be?) aware that SPL Generators are not \u0026ldquo;rewindable\u0026rdquo;. Once they are consumed, it\u0026rsquo;s not possible to loop over them once again. And sometimes it would be very useful if we could!\nThink about making database queries, in order to go easy on the memory and instead of shoving the whole resultset containing millions of record in an array, you use an Generator, yielding result by result upon user request, through a loop. Sadly, you can only iterate it once. If you want to iterate a second time, you\u0026rsquo;ll have to make a new query. Which is very bad.\nOne way to fix that would be to cache results in a local cache and use it. This means the caching implementation must be done in \u0026ldquo;userland\u0026rdquo;. Using custom code for that means that it will most probably have an impact on performance. Imagine it could be done in PHP, natively!\nEnter [CachingIterator][26], and underrated native PHP iterator.\nThanks to this core iterator, I built a very fast and stateless [IteratorAggregate][28] that uses an existing iterator, of any kind and do the caching.\nIn order to compare the performance of that very special iterator, I did benchmarks with [phpbench/phpbench][30] against [azjezz/psl][32], a state-of-the-art PHP package aiming to ease PHP developers against all the kind of inconsistencies in PHP. It provides many good things and is actively maintained.\nAnd the benchmarks are amazing, it\u0026rsquo;s blazing fast!\nComparing caching iterators [SimpleCachingIteratorAggregate][40]: Iterator keys are ignored [CachingIteratorAggregate][44]: Iterator keys are not ignored [azjezz/psl iterator implementation][34]: Iterator keys are not ignored Of course, results have to be mitigated because the [azjezz/psl iterator implementation][34] implements a userland stateful iterator implementing [Countable][36] and [SeekableIterator][38] interfaces and thus, does a bit more than [my current implementation][40] which is based on [Generator][42]\u0026hellip; which is also stateful, but directly handled by PHP and not in userland.\nI guess you know that, unlike PHP arrays, an iterator can have any kind of type for keys. Which means that you can use not only int or string but really any kind of type like bool, array or even other object.\nKnowing that, the [SimpleCachingIteratorAggregate][40] ignores the keys while the [CachingIteratorAggregate][44] does not. And the numbers are talking. The later implementation is more than twice slower than the first one, but still almost twice faster than [azjezz/psl][32].\nWhen I discovered this, I contacted [Saif Eddin Gmati][46] the [azjezz/psl][32]\u0026rsquo;s creator, and since then, he improved his own version making it from thirty times to twice slower, a tremendous improvement. He also gave me some tips for my own iterators, thanks to him !!!\nWOPI # Recently, I\u0026rsquo;ve been asked to build a Symfony bundle to allows users to edit office documents online, such as having a full featured document editor embedded in a backend.\nFortunately for me, it turns out that there is some kind of standard protocol for that: [WOPI][52] by\u0026hellip; Microsoft! (Never though I\u0026rsquo;d write this word on my blog).\nAfter a long period of studying the protocol, having contact with the [Collabora Online][62] developers, and tests, a couple of packages has been released:\n[champs-libres/wopi-lib][54]: A standard and framework agnostic PHP library to facilitate the implementation of the WOPI protocol. [champs-libres/wopi-bundle][56]: A bundle providing routes and glue code between Symfony and a WOPI connector. [drupol/wopi-app][106]: A Symfony application for demo, available at [https://wopi-app.herokuapp.com/][104]. As those package are the first in the PHP world, I was invited to talk about these new things during [the COOL Days][64]. It was a very nice experience.\nMiscellaneous # The other day while working with Symfony, I noticed that the Symfony container was not creating aliases for services having interface(s).\nThat is indeed the default behavior and at first sight, it seems logic. We don\u0026rsquo;t want to have the container full of aliases that we won\u0026rsquo;t never use. However, I like the idea of having aliases of my services so I could inject them based on the parameter name, everywhere and without effort.\nI was so curious that I opened [a proposal on Symfony][58] and created a proof of concept bundle [loophp/service-alias-autoregister-bundle][60]. The thread has been very interesting and it opened my eyes.\nI doubt that this bundle will ever be used now, but I\u0026rsquo;ll leave it on Github, maybe it might give ideas to some other people later.\nOn another subject, I haven\u0026rsquo;t participated to [Advent Of Code][94] because of some many things going on at the same time. However, I followed it actively. I believe that even without participating it is a very good exercise to read the challenges and the different solutions. For my part, I followed [Larry Garfield][96] and [Bartosz Milewski][98]. Larry was using PHP with a complete functional approach while Bartosz used Haskell. It was super interesting to see the approach of both developers and their solutions to each challenge. Find their Advent Of Code repository [here][100] and [here][102] respectively. Hats off!\nWork # Life\u0026rsquo;s at work has been also affected and working from home is the default rule for now on.\nDespite that, we made quite a bunch of nice things, especially this one:\nOne of the first, if not THE first, open-source presentations at the European Commission is now on Github! Built with open-source edition tools (LaTeX and more)👉https://t.co/BCInvs9KHu\n\u0026mdash; DIGIT 🇪🇺 (@EU_DIGIT) November 12, 2021 This session has been given at work and published on Github in open-source at [ecphp/session\u0026ndash;composition-and-inheritance][66]. Anyone can now contribute to the content of the presentation.\nThere will be more and more initiative like this one in the future thanks to\nWe are pleased to announce the latest achievement, @EU_Commission’s Open Source Strategy. From now on, it will be easier to publish our code as #OpenSource. We can now share bug fixes with upstream projects. Shorter time and less paperwork!#ThinkOpen👉https://t.co/TMPrRfpebC pic.twitter.com/2Q393cWqT5\n\u0026mdash; DIGIT 🇪🇺 (@EU_DIGIT) December 8, 2021 The future at European Commission is bright and I\u0026rsquo;m looking forward to it!\nRandom # This blog # In October, I switched from Disqus to [Giscus][92], a comments system powered by GitHub Discussions. Let visitors leave comments and reactions on your website via Github.\nI love the Github simplicity and as soon as I saw this amazing project, I switched to it. It\u0026rsquo;s lighter and faster. Sad things, I lost all the existing comments made with the previous comments system.\nMy laptop # It\u0026rsquo;s been now a couple of month that I\u0026rsquo;m using [Nixos][68] as a daily driver.\nAfter being more than 10 years running [Gentoo][70], I decided to give a try to something else.\nThe main reason is that my laptop, a \u0026ldquo;good old\u0026rdquo; Lenovo x260, was extremely slow on Gentoo. I couldn\u0026rsquo;t find why but I think it was related to the default Gentoo kernel which is not really tailored for desktop but merely for servers\u0026hellip; and to be completely honest, after a couple of bad experiences while recompiling the kernel, I was a bit fed up.\nSo, I was about to order a new Lenovo X13 Gen 2 when I tried Nixos\u0026hellip; and I\u0026rsquo;m still using my \u0026ldquo;good old\u0026rdquo; laptop today. And even if I change my mind and want to buy the Lenovo X13 gen 2\u0026hellip; it\u0026rsquo;s no more available in Belgium.\nIt turns out that I\u0026rsquo;m definitely in love with Nixos. It\u0026rsquo;s clean, clear and damn fast.\nLearning Nixos and the Nix language is not an easy thing because the documentation is sadly not the best part of the distro, but once you get the hang of it, it\u0026rsquo;s amazing.\nEverything is done on Github, in one single repository: [NixOS/nixpkgs][86].\nI started to hack my first package \u0026ldquo;Symfony CLI\u0026rdquo; for Nixos and I successfully, not without pain, submitted [my first Nixos PR][72]. And by the way, at the time the Symfony CLI command line tool was closed source and now [it has been open-sourced][74]!\nI also built a tool that I\u0026rsquo;m now using by default everyday: [loophp/nix-shell][76]. It provides a development environment for PHP, with all the required tools. You can choose with which version of PHP you want to work with from PHP 5.6 to 8.1, and a few seconds later, you\u0026rsquo;re ready to hack!\nSince Nixos and these tools are built with reproductibility in mind, the \u0026ldquo;flake.lock file\u0026rdquo; have to be updated from time to time. I created a project that allows you to let [Dependabot][78], a Github bot, update your project automatically through pull-requests. That project is used in all my projects having a [flake file][80], and are updated automatically, find it here: [loophp/flake-lock-update-workflow][82].\n[Flakes][80] is the big upcoming feature for Nixos, it\u0026rsquo;s not fully stable yet, but it\u0026rsquo;s pretty usable everyday. Just like a composer.lock file in a PHP application, flakes create a flake.lock file in a project. It allows users to be aligned with the software versions and make sure that anyone can reproduce the same environment anywhere.\nIn that state of mind, I published my laptop configuration at [drupol/nixos-x260][84]. If for some reason my laptop dies, I can spawn a new one with the same configuration in less than one hour. Of course, personal files would not be restored, but hopefully I do have backups somewhere else!\n2020 too # Dear readers,\nI wish you all a super nice and creative year, full of happiness, joy and\u0026hellip; coding!\n[0]: https://not-a-number.io/2021/functional-programming-and-php-8/ [2]: https://www.youtube.com/watch?v=dkZFtimgAcM [4]: https://www.youtube.com/watch?v=ZhuHCtR3xq8 [6]: https://twitter.com/lorentzframe [7]: https://github.com/marcosh/lamphpda [8]: https://marcosh.github.io/ [10]: https://www.functionalfest.it/ [12]: https://github.com/marcosh/lamphpda/pulls?q=is%3Apr+author%3Adrupol+ [14]: https://github.com/loophp/repository-monadic-helper [16]: https://github.com/loophp/collection [18]: https://phpunit.de/ [20]: https://github.com/loophp/collection/pull/227 [22]: https://github.com/loophp/phpunit-iterable-assertions [24]: https://github.com/loophp/iterators [26]: https://www.php.net/cachingiterator [28]: https://www.php.net/iteratoraggregate [30]: https://github.com/phpbench/phpbench [32]: https://github.com/azjezz/psl [34]: https://github.com/azjezz/psl/blob/2.0.x/src/Psl/Iter/Iterator.php [36]: https://www.php.net/seekableiterator [38]: https://www.php.net/countable [40]: https://github.com/loophp/iterators/blob/main/src/SimpleCachingIteratorAggregate.php [42]: https://www.php.net/generator [44]: https://github.com/loophp/iterators/blob/main/src/CachingIteratorAggregate.php [46]: https://github.com/azjezz [48]: https://github.com/loophp/tin [50]: https://github.com/marcosh/lamphpda-validation [52]: https://docs.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/online/ [54]: https://packagist.org/packages/champs-libres/wopi-lib [56]: https://packagist.org/packages/champs-libres/wopi-bundle [58]: https://github.com/symfony/symfony/issues/44184 [60]: https://github.com/loophp/service-alias-autoregister-bundle [62]: https://www.collaboraoffice.com/ [64]: https://www.collaboraoffice.com/community-news/developers-day-september-30th/ [66]: https://github.com/ecphp/session--composition-and-inheritance/ [68]: https://nixos.org/ [70]: https://gentoo.org/ [72]: https://github.com/NixOS/nixpkgs/pull/126356 [74]: https://symfony.com/blog/announcing-the-open-sourcing-of-the-symfony-cli [76]: https://github.com/loophp/nix-shell/ [78]: https://github.com/dependabot [80]: https://nixos.wiki/wiki/Flakes [82]: https://github.com/loophp/flake-lock-update-workflow [84]: https://github.com/drupol/nixos-x260 [86]: https://github.com/NixOS/nixpkgs [88]: https://en.wikipedia.org/wiki/Monad_(functional_programming) [90]: https://github.com/loophp/iterators/blob/main/src/ClosureIterator.php [92]: https://giscus.app/ [94]: https://adventofcode.com/2021 [96]: https://peakd.com/hive-168588/@crell/aoc2021-review [98]: https://twitter.com/BartoszMilewski [100]: https://github.com/Crell/aoc2021/ [102]: https://github.com/BartoszMilewski/AoC2021/ [104]: https://wopi-app.herokuapp.com/ [106]: https://github.com/drupol/wopi-app/\n","date":"1 January 2022","externalUrl":null,"permalink":"/2022/happy-new-year/","section":"Posts","summary":"","title":"Happy new year!","type":"posts"},{"content":"","date":"1 January 2022","externalUrl":null,"permalink":"/tags/symfony/","section":"Tags","summary":"","title":"Symfony","type":"tags"},{"content":"","date":"1 January 2022","externalUrl":null,"permalink":"/tags/wopi/","section":"Tags","summary":"","title":"Wopi","type":"tags"},{"content":"","date":"13 July 2021","externalUrl":null,"permalink":"/tags/functional-programming/","section":"Tags","summary":"","title":"Functional Programming","type":"tags"},{"content":"PHP 8.0 has been released since half a year now and 8.1 is just around the corner.\nMy day to day version of PHP is 7.4 and I like it. It has very nice features and I really like the performance improvements that were made.\nHowever, it\u0026rsquo;s a week now that I\u0026rsquo;m working on a project using PHP 8 and I started to use the new features.\nThis blog post will explain the stuff that I discovered during that journey.\nSince two years now, I\u0026rsquo;m working on a project of mine: loophp/collection.\nIt started because I wanted to have a better understanding on having custom collection in a project, but also to understand the lazy concept that we can meet here and there.\nI wrote a [blog post][10] about it, also gave a talk during the AFUP Days, find the talk here and the slides here.\nAfter two years into functional programming with PHP, I noticed that loophp/collection was using basic and common concepts and I wanted to abstract them in a small library that could be used in any project which doesn\u0026rsquo;t not necessary require the use of a custom Collection. This is how I started to write FPT (Functional Programming Toolbox).\nThe goal of that very specific library is to provide a stateless classes of functional programming primitives, tailored in and for PHP.\nloophp/collection is heavily using currying applications in order to avoid creating local variables and optimize things to the maximum.\nCurrying is the process of converting a function that takes multiple arguments into a function that takes them one at a time. Each time the function is called it only accepts one argument and returns a function that takes one argument until all arguments are passed.\nHowever, it turns out that it\u0026rsquo;s not that easy to satisfy every use case when designing them.\nBefore PHP 8 # Let\u0026rsquo;s take a very basic example with the core PHP function explode.\nexplode is a binary/ternary function which has two required parameters (separator, string) and one optional parameter (limit).\nExample of usage:\nexplode(\u0026#39;:\u0026#39;, \u0026#39;a:b:c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] explode(\u0026#39;:\u0026#39;, \u0026#39;a:b:c\u0026#39;, 2); // [\u0026#39;a\u0026#39;, \u0026#39;b:c\u0026#39;] Let\u0026rsquo;s say now that we would like to make a curried version of it.\n// Create a curried version of core PHP function \u0026#34;explode\u0026#34; // (optional parameters are not even taken in account) $explode = FPT::curry()(\u0026#39;explode\u0026#39;); // We can use it just like the regular core function. $explode(\u0026#39;:\u0026#39;, \u0026#39;a:b:c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] // Or we can create a new intermediary function, this is a \u0026#34;curried\u0026#34; function. $explodeWithColon = $explode(\u0026#39;:\u0026#39;) $explodeWithColon(\u0026#39;a:b:c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] The concept of currification of a function is a very powerful concept.\nI think this a very important concept in functional programming, if not the most important.\nAt first it doesn\u0026rsquo;t seems very useful, but the more you use it, the more you\u0026rsquo;ll like it and understand the benefits.\nAnother example with array_map:\n// Define a simple callback. $add1 = fn (int $value): int =\u0026gt; $value + 1; // Create a curried version of core PHP function \u0026#34;array_map\u0026#34; // (optional parameters are not even taken in account) $array_map = FPT::curry()(\u0026#39;array_map\u0026#39;); // Create a new function which takes an array as input. $arrayAdd1 = $array_map($add1); // Add 1 to each item. $arrayAdd1([1,2,3]); // [2, 3, 4] Using such concept has some benefits:\nEasier composition of new functions, Don\u0026rsquo;t Repeat Yourself Reusability, Promote [function-first, data-last][12] concept, Foster [tacit programming (point-free)][11] and [ETA-reduction][22] (I guess I could add more benefits and expand them with a couple of lines of explanation, but this is not the purpose of this blog post)\nLet\u0026rsquo;s build another example where I\u0026rsquo;m going to highlight the limitations of using currification with PHP before version 8.\nThe idea is to create simple callbacks that stiched together creates a new function to filter out even numbers from a list of numbers.\nBasically, it\u0026rsquo;s a filter application and [array_filter][14] should do the job.\n// Define a simple callback $odd = fn (int $value): bool =\u0026gt; 1 === $value % 2; // Create a curried version of core PHP function \u0026#34;array_filter\u0026#34; // (optional parameters are not even taken in account) $array_filter = FPT::curry()(\u0026#39;array_filter\u0026#39;); // Create a new function which takes an array as input. $filterOdd = $array_filter($odd); // This won\u0026#39;t work. Unfortunately, such example won\u0026rsquo;t work because array_filter\u0026rsquo;s signature is array_filter(array, callable): array. The first argument must be an array, the second a callable.\nA way to fix this would be to do the following:\n// Define a simple callback $odd = fn (int $value): bool =\u0026gt; 1 === $value % 2; // Create a custom curried version of core PHP function \u0026#34;array_filter\u0026#34; // (optional parameters are not even taken in account) $array_filter = fn (callable $filter) =\u0026gt; fn (array $array) =\u0026gt; array_filter($array, $filter); // Create a new function which takes an array as input. $filterOdd = $array_filter($odd); // Filter out even numbers $filterOdd([1,2,3]); // [1, 3] As we cannot use FPT::curry(), we have to rewrite the curried $array_filter function.\nSometimes parameters needs to be injected from the right to the left, sometimes from the left to the right and sometimes they need to be injected in a complete different way.\nImagine how many custom curried functions we would need to write if we want to cover all the cases! It\u0026rsquo;s simply not realistic. (On top of that, we would have to also handle the required and optional parameters, and it would be an impossible task to cover all the use cases.)\nAnd this is why [PHP libraries implementing curry applications][16], you will often find CurryLeft and CurryRight to partially solve that problem.\nOne way to fix it would be to create an extra function that would flip the parameters of a function as such:\n// Define a simple callback $odd = fn (int $value): bool =\u0026gt; 1 === $value % 2; // Generic flip/reverse all parameters of a n-ary callable. $flip = fn (callable $callable): Closure =\u0026gt; fn (...$params): mixed =\u0026gt; $callable(...array_reverse($params)); // Create a curried version of core PHP function \u0026#34;array_filter\u0026#34; // (optional parameters are not even taken in account) $array_filter = FPT::curry()($flip(\u0026#39;array_filter\u0026#39;), 2); // The parameter 2 must be added here. // Create a new function which takes an array as input. $filterOdd = $array_filter($odd); // Filter out even numbers $filterOdd([1,2,3]); // [1, 3] This will work but using a generic $flip function having a variadic parameter $params prevent the automatic detection of the amount of parameters to use in FTP::Curry(), this is the reason why we have to add it manually.\nThis is not the best solution according to me because the relevant code is becoming too much verbose. To some extent, it\u0026rsquo;s also not the best performance wise.\nAfter PHP 8 # Since the arrival of PHP 8, a bunch of new features has reshuffled the cards and opens up bright new perspectives.\nOne of this features is named parameters. Basically, you\u0026rsquo;ll be able to call any PHP function where provided parameters can be in different orders.\nIf we take the example of array_filter with PHP 7.4, you must provide an array then only the callable.\nWith PHP 8 and the \u0026ldquo;named parameters\u0026rdquo; feature, it is possible to first provide the callable and then the array as such:\n$odd = fn (int $value): bool =\u0026gt; 1 === $value % 2; $input = [1,2,3]; array_filter(callback: $odd, array: $input); // [1, 3] Thanks to that amazing feature, it is now possible to provide a new Curry application which is a bit more generic and fit for practically all use-cases.\nWith that \u0026ldquo;named parameters\u0026rdquo; feature, such a new curry application could provide the following features and user experience:\n// Create a curried version of core PHP function \u0026#34;explode\u0026#34;. $explode = FPT::curry()(\u0026#39;explode\u0026#39;); // Regular use. $explode(\u0026#39;-\u0026#39;, \u0026#39;a-b-c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] // Regular use with named parameters in the proper order $explode(separator: \u0026#39;-\u0026#39;, string: \u0026#39;a-b-c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] // Curried use with named parameters in the proper order $explode(separator: \u0026#39;-\u0026#39;)(string: \u0026#39;a-b-c\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] // Regular use with named parameters in a different order $explode(string: \u0026#39;a-b-c\u0026#39;, separator: \u0026#39;-\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] // Curried use with named parameters in a different order $explode(string: \u0026#39;a-b-c\u0026#39;)(separator: \u0026#39;-\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;] In this example, the optional parameters are not taken in account, but we could!\nIndeed, some PHP functions have a different amount of parameters and required parameters.\nWith explode, it has two required parameters and three parameters in total, which means that one parameter is optional and most probably has a default value.\nOur new Curry function need to be able to deal with that because such things are very common in PHP.\n// Create a curried function of \u0026#34;explode\u0026#34; which must have 3 parameters $explode = FPT::curry()(\u0026#39;explode\u0026#39;, 3); // Regular use. $explode(\u0026#39;-\u0026#39;, \u0026#39;a-b-c\u0026#39;, 2); // [\u0026#39;a\u0026#39;, \u0026#39;b-c\u0026#39;] // Regular use with named parameters in the proper order $explode(separator: \u0026#39;-\u0026#39;, string: \u0026#39;a-b-c\u0026#39;, limit: 2); // [\u0026#39;a\u0026#39;, \u0026#39;b-c\u0026#39;] // Curried use with named parameters in the proper order $explode(separator: \u0026#39;-\u0026#39;)(string: \u0026#39;a-b-c\u0026#39;)(limit: 2); // [\u0026#39;a\u0026#39;, \u0026#39;b-c\u0026#39;] // Regular use with named parameters in a different order $explode(limit: 2, string: \u0026#39;a-b-c\u0026#39;, separator: \u0026#39;-\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b-c\u0026#39;] // Curried use with named parameters in a different order $explode(limit: 2)(string: \u0026#39;a-b-c\u0026#39;)(separator: \u0026#39;-\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b-c\u0026#39;] What about \u0026ldquo;partial\u0026rdquo; application ? # Usually when we talk about currying, we talk about partial as well.\nThe \u0026ldquo;partial\u0026rdquo; application is the cousin of the \u0026ldquo;curry\u0026rdquo; application.\nBasically it\u0026rsquo;s almost the same application except that Currying takes exactly one input, whereas partial application takes two (or more) inputs.\nIn FPT, there is no such partial application. It\u0026rsquo;s done within the curry application.\nWhy? Because of [variadic parameters][13]!\nThe FPT::curry() application works just like the regular and \u0026ldquo;by-the-book\u0026rdquo; curry application, but thanks to variadic arguments, it\u0026rsquo;s more flexible.\nIt let us use more than one parameter at a time and thus, mimic the behaviour of the partial application.\n// Create a curried function of \u0026#34;explode\u0026#34; which must have 3 parameters $explode = FPT::curry()(\u0026#39;explode\u0026#39;, 3); // Create a intermediary \u0026#34;partial\u0026#34; function. $newExplode = $explode(limit: 3, separator: \u0026#39;-\u0026#39;); $newExplode(\u0026#39;a-b-c-d-e\u0026#39;); // [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c-d-e\u0026#39;] And PHP 8.1 then? # Lately and in every mainstream programming languages, we can see that the trend is slowly moving towards functional programming.\nAnd PHP follow that trend, baby step by baby step.\nWe can see that there\u0026rsquo;s a couple of [RFCs][20] that are coming and are definitely functional programming oriented.\nThe last one is in date is [Partial function application][15] which was sadly not adopted. Another one here: [First class callable syntax][19] And another one: [Pipe operator][18] and the last one (already in PHP 8.0!) with the [match expression][17].\nPHP 8.1 is around the corner and I guess that the future of PHP has bright days, especially if more functional programming features is going to added!\nMore functional programming in PHP means a stricter typed code, a bump into reusability, lesser code to write, better concepts, paradigms and design patterns where the foundations has been proved theoretically by mathematics.\nConclusion # It\u0026rsquo;s been a week that I\u0026rsquo;m working with PHP 8 and I just don\u0026rsquo;t want to look back already.\nThe FPT library is being updated to only support [PHP 8][21] and it\u0026rsquo;s going well so far.\n37 files changed, 233 insertions(+), 689 deletions(-)\nUsing these new stuff from PHP 8 allowed me to remove a bunch of code and I can\u0026rsquo;t wait to do that in my other projects!\n[10]: https://not-a-number.io/2021/afup-interview/ [11]: https://en.wikipedia.org/wiki/Tacit_programming [12]: https://www.javierchavarri.com/data-first-and-data-last-a-comparison/ [13]: https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list [14]: https://php.net/array_filter [15]: https://wiki.php.net/rfc/partial_function_application [16]: https://packagist.org/?query=curry [17]: https://wiki.php.net/rfc/match_expression_v2 [18]: https://wiki.php.net/rfc/pipe-operator-v2 [19]: https://wiki.php.net/rfc/first_class_callable_syntax [20]: https://wiki.php.net/rfc [21]: https://github.com/loophp/fpt/pull/12 [22]: https://wiki.haskell.org/Eta_conversion\n","date":"13 July 2021","externalUrl":null,"permalink":"/2021/functional-programming-and-php-8/","section":"Posts","summary":"","title":"Functional programming and PHP 8","type":"posts"},{"content":"","date":"13 July 2021","externalUrl":null,"permalink":"/tags/partial-application/","section":"Tags","summary":"","title":"Partial-Application","type":"tags"},{"content":"","date":"13 July 2021","externalUrl":null,"permalink":"/tags/typing/","section":"Tags","summary":"","title":"Typing","type":"tags"},{"content":"I will soon give a talk at AFUP regarding the loophp/collection library that I built.\nI\u0026rsquo;ve been asked to make an interview and I had to reply to some questions.\nThis blog post is the english translation of this interview.\nWhen we read \u0026quot;Lazy Collection\u0026quot;, we think \u0026quot;Doctrine Collection\u0026quot;. Could you tell us more why your library loophp/collection is different?\nThe package doctrine/collections is one of the reason I started to get interest into collections. However, the real trigger was a pull request from Joseph Silber on the Laravel framework, le 5 Août 2019. I carefully analysed and tested it and I started to write my own library, mainly to to learn, test and have a better understanding on the new concepts, I also improved some of them.\nThat said, it\u0026rsquo;s true, collections libraries, there are many and at every sauce, and curry sauce is quite uncommon!\nThe library provided by Doctrine is mainly used by Doctrine. The result of a SELECT SQL query are ofen wrapped with an instance of that collection.\nThis allows, among some other things, to easily apply filtering, sorting functions and so on. This is very practical because the result of a query is an object, an instance of the collection, and therefore there is an easy way to see the methods which are attached to it, for example, with the IDE and thus to manipulate the data.\nTo come back to your original question now, doctrine/collections is not lazy and therefore very different from loophp/collection.\nEach method call is executed instantly regardless of the size of the initial data set. Without counting the layer which manages the expressions, we could practically reduce this library to a simple array manipulation utility.\nAnd so yes, there is therefore a fundamental difference between doctrine/collections and loophp/collection.\nExample, following a request from a service or a database, we retrieve in the collection $collection millions of digital identifiers.\n$results = $collection -\u0026gt;filter(fn (int $int) =\u0026gt; 0 === $int % 2) // Filter even identifiers -\u0026gt;map(fn(int $int) =\u0026gt; 'document' . $int . '.pdf') // Rename to filename -\u0026gt;filter(fn(string $doc) =\u0026gt; file_exists('/doc/' . $doc)) // Filter unexistent files -\u0026gt;map(fn(string $doc) =\u0026gt; file_get_contents($doc)); // Fetch the file content foreach ($results as $v) {} // Iterate the results This snippet will:\nBefore starting the foreach loop,\nTraverse the collection to filter it based on its parity,\nCreate a temporary results array,\nTraverse the array to rename into filenames,\nCreate a temporary results array,\nTraverse the array to filter it based on the file existence,\nCreate a temporary results array,\nTraverse the array to fetch the file contents,\nCreate a final temporary resulting array.\nIterate.\nNow, let\u0026rsquo;s do the same with a lazy collection instance.\nDo nothing before starting the foreach loop,\nAs soon as the iteration starts...,\nIf the current element is even, then rename it,\nif the file exists, then fetch its content,\nSend the current result to the user.\nIterate.\nThe fundamental difference is clearly highlighted here. With a traditional collection, the data collection will be traversed several times, and intermediate variables will be created while with a lazy collection, the data will only be traversed once and no intermediate variable will be created.\nTo put it simply, a lazy code will be more lenient with the use of allocated memory than with a traditional code.\nTo conclude, a traditional collection will favor a consecutive execution while a lazy collection, a transversal execution.\nIt is thus among others this technique which is used in loophp/collection.\nThe result of one or more operations is executed/compiled/performed/call-it-whatever-you-want only when we iterate over the results, never before (except for a few exceptions out of context).\nSo that\u0026rsquo;s why the adjective lazy takes on its full meaning, everything is always done at the last moment, a bit like me when I had to study, always at the last minute!\nHence also the fact that regardless of the volume of initial data, the library will only take care of a small part at a time and will stop only when it has finished going through them.\nFinally, to quickly get back to Doctrine, maybe one day there will be a way to inject the possibility of using another collection library... who knows?\nWe at AFUP love curry, sweet, smoked ... sorry? What? Ah! Is curry a style of writing code? Can you explain to us what this style is?\nI love curry too, both in my dishes and in the code, if not more!\nThe term comes from the name of the American mathematician Haskell Curry, yes, Haskell like the programming language!\nThe following definition explains it very well: The curryfication is the transformation of a function with multiple arguments to a function with one argument (unary function) which returns a function on the rest of the arguments.\nLet\u0026rsquo;s take a trivial example: the implode () function. This function is called binary and we must succeed in transforming it into a function called unary.\nBut how is this possible? To be carried out, this function will always need 2 arguments!\nThe curryfication of this function would therefore amount to creating a new function unary which admits the first argument $separator, which in turns, returns a function which admits the second argument $strings and which in turns returns the final result. Example:\n$implode = fn(string $separator) =\u0026gt; fn(array $strings) =\u0026gt; \\implode($separator, $strings); And voila! We can now easily create as many unary functions as we want. For example, we want a function that implode with a hyphen or a comma:\n$implodeWithDash = $implode('-'); $implodeWithComma = $implode(','); Which can be used like this:\n$input = ['a','b','c']; $implodeWithDash($input); // a-b-c $implodeWithComma($input); // a,b,c That said, nothing prevents us from also using our new $implode function like a traditional one:\n$implode(';')(['g','h','i']); // g;h;i The advantage of this technique invented in the 70s (not so old!) makes it easier to compose operations developed using several other functions. It also makes it easier to rewrite code, write less code as well as write less imperative and more declarative code, more functional programming oriented.\nNow, to come back in the context that matters to us today, namely the lazy collections and more especially loophp/collection.\nI have used this technique almost everywhere. Indeed, when you pass arguments in the class constructor, there is a good chance that these arguments will be kept in memory via properties. And so, in order to reduce the memory footprint and reduce the size of the code, I spiced up my code using the curryfication.\nIt taught me a lot of things and the greatest gift was being interested in functional programming, it opened me up eyes on a myriad of fabulous concepts. This is how I started learning the Haskell language, and I was able to put into practice concepts that are generally used in functional languages with contribution in the PHP code, and in particular in loophp/collection.\nImplicitly, I was more efficient in my way of programming, of using the function-first, data-last technique or to discover tacit programming (or point-free-style).\nThe use of these techniques allowed me to be very strict at the typing level and thus facilitate the static analysis.\nPol, you are Belgian: can you tell us about the community of developers in Belgium? Do you have the equivalent of AFUP, opportunities to meet?\nIndeed, I am Belgian with Italian origin and I consider myself a European. It\u0026rsquo;s probably my work environment at the European Commission which has accentuated this way of seeing things. From what I remember I already felt it like that from a young age, my parents did their job well.\nAt the start of my career, I got involved a lot in the Drupal community for which I do not contribute any longer. I went to the four corners of the planet to attend conferences and workshops.\nVery recently and for multiple reasons, I reoriented my career in order to focus on a more corporate and professional use of PHP, without Drupal. I do not regret my choice, except that I miss my old colleagues, especially in this atypical time.\nBelgium is full of PHP devs and generally they are never without a job! Many of them work at the European Commission, there is a lot of activity around Drupal. Coming from these regions, I know almost all of them and I greet them warmly!\nFor the gender distribution, the world of development seems to be a world of men, the only female developers I know can be counted on the fingers of one hand, I greet them also at the same time!\nFrom a strictly personal point of view, I have never felt any discomfort from anyone regarding the gender, I have the impression that so few women are present because of old ways and customs. Changes in mentalities are still to be made to get out of the preconceived patterns of the past. Even if a lot of effort has been made, the water will still have to flow under the bridges, to erase the prejudices and deconstruct in some heads that women, just like men, can be what they want and not only good at the tasks that have always been assigned to them since the dawn of time. And of course, this is also true for men who wish to get into trades mainly represented by women such as nurses, nursery nurses and so on.\nRegarding a community similar to AFUP, I only know PHP Benelux and I attend meetings regularly. I must admit that I am very envious of the effervescence and communities that I can see in your country.\nAnd finally, about 6 years ago and I decided to relocate and I completely stopped traveling and getting involved so much to try in order to devote myself to my renovation projects.\nSince then, I slowly take the fold, hence my submission of a presentation or I thank you already for having it chosen, I can\u0026rsquo;t wait to present it to you all.\n","date":"7 April 2021","externalUrl":null,"permalink":"/2021/afup-interview/","section":"Posts","summary":"","title":"AFUP interview","type":"posts"},{"content":"","date":"7 April 2021","externalUrl":null,"permalink":"/tags/interview/","section":"Tags","summary":"","title":"Interview","type":"tags"},{"content":"","date":"7 April 2021","externalUrl":null,"permalink":"/tags/iterator/","section":"Tags","summary":"","title":"Iterator","type":"tags"},{"content":"","date":"7 April 2021","externalUrl":null,"permalink":"/tags/php-community/","section":"Tags","summary":"","title":"Php-Community","type":"tags"},{"content":"","date":"7 April 2021","externalUrl":null,"permalink":"/tags/prime-numbers/","section":"Tags","summary":"","title":"Prime Numbers","type":"tags"},{"content":"","date":"7 April 2021","externalUrl":null,"permalink":"/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"","date":"3 September 2020","externalUrl":null,"permalink":"/tags/algorithms/","section":"Tags","summary":"","title":"Algorithms","type":"tags"},{"content":"","date":"3 September 2020","externalUrl":null,"permalink":"/tags/benchmarking/","section":"Tags","summary":"","title":"Benchmarking","type":"tags"},{"content":"","date":"3 September 2020","externalUrl":null,"permalink":"/tags/generators/","section":"Tags","summary":"","title":"Generators","type":"tags"},{"content":" It all started from a book # I was reading the Open Source book from Bartosz Milewski\u0026rsquo;s \u0026lsquo;Category Theory for Programmers\u0026rsquo; when I saw something about Prime numbers:\nA more interesting example is a coalgebra that produces a list of primes. The trick is to use an infinite list as a carrier. Our starting seed will be the list [2..]. The next seed will be the tail of this list with all multiples of 2 removed. It\u0026rsquo;s a list of odd numbers starting with 3. In the next step, we\u0026rsquo;ll take the tail of this list and remove all multiples of 3, and so on. You might recognize the makings of the sieve of Eratosthenes.\nIn Python language, it would be written as such:\ndef naturals(n): yield n yield from naturals(n + 1) def sieve(s): n = next(s) yield n yield from sieve(i for i in s if i % n != 0) for i in sieve(naturals(2)): print(i) # 2, 3, 5, 7, 11, 13, 17, 19, ... How beautiful it is, isn\u0026rsquo;t it ?\nI really like the simplicity of this algorithm, which is 2000 years old.\nIt\u0026rsquo;s crazy to think that such an algorithm and finding a formula to find Prime numbers is always on the wildest thoughts of every scientist in the world.\nOh you didn\u0026rsquo;t get the memo ? Let me remind it to you then\u0026hellip; you can win 1 million dollars if you found the solution to that problem !\nFinding how Prime numbers are distributed across Naturals is one of the Millenium Prize problems, if you find it too easy, you can pick another one. Cheers.\nHow about in PHP ? # I just did a huge refactoring in loophp/collection and I know that PHP is not the best language for this thing, but I wanted to try, you know, just to check if this is possible and compare it with the Python syntax.\nAt first, I had no idea on how to do it at first. I was stunned by the beauty of this algorithm and surprised to have never seen it before.\nA quick look on Github has led me to some inspiration, and I started to code something and only after two days of searching, I came up with this:\n\u0026lt;?php function primesGenerator(\\Iterator $iterator): \\Generator { yield $primeNumber = $iterator-\u0026gt;current(); $iterator = new \\CallbackFilterIterator( $iterator, fn(int $a): bool =\u0026gt; $a % $primeNumber !== 0 ); $iterator-\u0026gt;next(); return $iterator-\u0026gt;valid() ? yield from primesGenerator($iterator): null; } function integerGenerator(int $init = 1): \\Generator { while (true) { yield $init++; } } $primes = primesGenerator(integerGenerator(2)); foreach ($primes as $p) { var_dump($p); // 2, 3, 5, 7, 11, 13, 17, 19, ... } It\u0026rsquo;s not as nice as Python, but it does the job. Unfortunately, it fails quite rather quickly when XDebug is enabled.\nBenchmarking # I also started to investigate how I could optimize the algorithm and made further research on it.\nIt turns out that this is erroneously called the \u0026ldquo;Sieve of Eratosthenes\u0026rdquo;. It should have been called the \u0026ldquo;Sieve of Trial Division\u0026rdquo;.\nThat algorithm as it is now, is very suboptimal, because it\u0026rsquo;s not \u0026ldquo;postponed\u0026rdquo;. Any candidate number need only be tested by Primes not above its square root. Implementing this will give an huge speedup and/because it\u0026rsquo;ll greatly minimize the stack usage.\nIn order to check the efficiency of this algorithm compared to a better version, I scaffolded a benchmarking tool.\nAs most of my work is Open Source, I quickly spawned a Github repository and created some benchmarks, using the great PHP Bench.\nI implemented three different algorithms, they are almost the same with one difference:\nPrimes1: Simple Sieve of Trial Division (source) Primes2: Sieve of Trial Division + Postponed (first try) (source) Primes3: Sieve of Trial Division + Postponed (second try) (source) +-------------+--------------+--------------+------------+------------+-------+ | benchmark | subject | mean | mem_peak | mem_real | diff | +-------------+--------------+--------------+------------+------------+-------+ | PrimesBench | benchPrimes1 | 32,100.196μs | 2,130,696b | 4,194,304b | 1.22x | | PrimesBench | benchPrimes2 | 31,221.970μs | 2,133,376b | 4,194,304b | 1.19x | | PrimesBench | benchPrimes3 | 26,274.643μs | 2,156,096b | 4,194,304b | 1.00x | +-------------+--------------+--------------+------------+------------+-------+ Primes1 is the basic algorithm based on CallbackFilterIterator where the filter callback is:\nstatic fn (int $a): bool =\u0026gt; (0 !== ($a % $primeNumber)) Basically this is just a sieve of trial division.\nPrimes2 is the same as Primes1 but the filter callback is updated to:\nstatic fn (int $a): bool =\u0026gt; (($primeNumber ** 2) \u0026gt; $a) || (0 !== ($a % $primeNumber)) There are two conditions in this callback:\nAny candidate number ($a) need only be tested by Primes not above its square root. The rest of the division of $a by the prime number is different from zero. Primes3 implements a custom CallbackFilterIterator where the accept method is overridden with the same filter callback as in Primes2.\nTo my amazement, the algorithm Primes3 is the fastest. I still don\u0026rsquo;t get why it\u0026rsquo;s faster than Primes2, but I guess I will found out sooner or later.\nIt would be nice to add more algorithms and see how they behave.\nIf you feel like helping me and do a deep dive, feel free to clone the repo and try it out by yourself, you\u0026rsquo;ll see, it\u0026rsquo;s fun !\n","date":"3 September 2020","externalUrl":null,"permalink":"/2020/prime-numbers-generation/","section":"Posts","summary":"","title":"Prime numbers generation","type":"posts"},{"content":"","date":"10 August 2020","externalUrl":null,"permalink":"/tags/collections/","section":"Tags","summary":"","title":"Collections","type":"tags"},{"content":"","date":"10 August 2020","externalUrl":null,"permalink":"/tags/iterators/","section":"Tags","summary":"","title":"Iterators","type":"tags"},{"content":"","date":"10 August 2020","externalUrl":null,"permalink":"/tags/lazy-collection/","section":"Tags","summary":"","title":"Lazy Collection","type":"tags"},{"content":"A year ago, I started to write a lazy collection library for PHP.\nI haven\u0026rsquo;t written a specific article about it despite the fact that I would have wanted to, mostly by lack of time.\nAlmost a year ago and 318 commits later, I published the release 2.0.0 last week.\nIt all started a year ago, when I came across a pull request made against the Laravel framework.\nWriting a lazy collection library was something that I had in mind, and that pull request has revived my motivation to write one. After understanding what was happening in that pull request, I started to write my own library.\nThere were already some collection libraries in PHP, but I wanted to do something more complete, fully tested and typed, with a good documentation.\nI did countless iterations because I was not happy of the result and I felt that I could improve and optimize things.\nWriting such library also put me on the path of functional programming even more, and I also lost quite a lot of time learning new things from that amazing field.\nSo far, writing this package has been my greatest source of personal learning in the programming world. It opened my eyes to a lot of things that I had no idea before.\nI suggest to the readers to also read this post from Joseph Silber, the author of the Laravel pull request, it\u0026rsquo;s a great and probably the best article about lazy collections.\nThis post is not about how to use my library, but merely about the oddities that I wasn\u0026rsquo;t expecting to find while coding it.\nI have summarized here only a few, there are more, but these are the 3 that I recall the most.\nOddity #1 # There are some question on StackOverflow on how to \u0026ldquo;dedup\u0026rdquo; (deduplicate) an array. Basically it means: \u0026ldquo;How to remove duplicated values from an array\u0026rdquo;.\nThere are many ways to do that, the most trivial example is with array_unique().\n\u0026lt;?php $input = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;b\u0026#39;]; $filtered = array_unique($input); // [ // 0 =\u0026gt; \u0026#39;a\u0026#39;, // 1 =\u0026gt; \u0026#39;b\u0026#39;, // 2 =\u0026gt; \u0026#39;c\u0026#39;, // 4 =\u0026gt; \u0026#39;d\u0026#39;, // ] There is also another fancier way that you might use, by issuing twice the array_flip() function.\n\u0026lt;?php $input = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;b\u0026#39;]; $filtered = array_flip(array_flip($input)); // [ // 3 =\u0026gt; \u0026#39;a\u0026#39;, // 5 =\u0026gt; \u0026#39;b\u0026#39;, // 2 =\u0026gt; \u0026#39;c\u0026#39;, // 4 =\u0026gt; \u0026#39;d\u0026#39;, // ] We can directly notice that the keys are different, but the values are the same as the previous example.\nWhat is happening here?\nLet\u0026rsquo;s break down the calls and print the arrays in between:\n\u0026lt;?php $input = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;b\u0026#39;]; $filtered = array_flip($input); // [ // \u0026#39;a\u0026#39; =\u0026gt; 3, // \u0026#39;b\u0026#39; =\u0026gt; 5, // \u0026#39;c\u0026#39; =\u0026gt; 2, // \u0026#39;d\u0026#39; =\u0026gt; 4, // ] $filtered = array_flip($filtered); // [ // 3 =\u0026gt; \u0026#39;a\u0026#39;, // 5 =\u0026gt; \u0026#39;b\u0026#39;, // 2 =\u0026gt; \u0026#39;c\u0026#39;, // 4 =\u0026gt; \u0026#39;d\u0026#39;, // ] The first call to array_flip() will exchange keys with values and vice versa. As you may have noticed, there are multiple times the letter a, at index 0 and 3. array_flip() will then use the latest known key for letter a in the input array: 3.\nThe same process is applied for each remaining array values.\nFrom there, we can deduce that:\n\u0026lt;?php $input = [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;b\u0026#39;]; $filteredWithArrayFlip = array_values(array_flip(array_flip($input))); $filteredWithArrayUnique = array_unique($input); // We can deduce that: // $filteredWithArrayFlip === $filteredWithArrayUnique; Ok, all of this are great but it doesn\u0026rsquo;t bring any added values to PHP, and on top of that, there\u0026rsquo;s a lot of chance that using array_values(), then twice array_flip() will be slower than just using array_unique().\nFurthermore, those functions are made for arrays, there is no support for other iterable types like Traversable, Iterators and Generators.\nWith loophp/collection, you can use any kind of iterable types, by default. In the following examples, I will use a Generator, because it\u0026rsquo;s convenient in this particular example.\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;flip(); // Loop over it foreach ($collection as $key =\u0026gt; $value) { // \u0026#39;a\u0026#39; =\u0026gt; 3 // \u0026#39;b\u0026#39; =\u0026gt; 5 // \u0026#39;c\u0026#39; =\u0026gt; 2 // \u0026#39;d\u0026#39; =\u0026gt; 4 } // Or just convert it into an array (the same as iterator_to_array($collection)) $array = $collection-\u0026gt;all(); // [ // \u0026#39;a\u0026#39; =\u0026gt; 3, // \u0026#39;b\u0026#39; =\u0026gt; 5, // \u0026#39;c\u0026#39; =\u0026gt; 2, // \u0026#39;d\u0026#39; =\u0026gt; 4, // ] If you do the flip() operation twice, what would be the result? Let\u0026rsquo;s try\u0026hellip;\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;flip() -\u0026gt;flip(); // Loop over it foreach ($collection as $key =\u0026gt; $value) { // 0 =\u0026gt; \u0026#39;a\u0026#39; // 1 =\u0026gt; \u0026#39;b\u0026#39; // 2 =\u0026gt; \u0026#39;c\u0026#39; // 3 =\u0026gt; \u0026#39;a\u0026#39; // 4 =\u0026gt; \u0026#39;d\u0026#39; // 5 =\u0026gt; \u0026#39;b\u0026#39; } // Or just convert it into an array (the same as iterator_to_array($collection)) $array = $collection-\u0026gt;all(); // [ // 0 =\u0026gt; \u0026#39;a\u0026#39; // 1 =\u0026gt; \u0026#39;b\u0026#39; // 2 =\u0026gt; \u0026#39;c\u0026#39; // 3 =\u0026gt; \u0026#39;a\u0026#39; // 4 =\u0026gt; \u0026#39;d\u0026#39; // 5 =\u0026gt; \u0026#39;b\u0026#39; // ] WOW ! (That was my first reaction.) #Facepalm (That was my second reaction)\nI\u0026rsquo;ve always been used to use regular array in PHP and predict the result and I wasn\u0026rsquo;t expecting such a result, at first.\nAnd it turns out that this behavior is absolutely logic, I just wasn\u0026rsquo;t used to it yet.\nYou can notice that flipping twice a lazy collection returns the original collection, completely unaltered!\nThink of a lazy collection as a stream, elements are not evaluated all at once, but one by one.\nThis is something that someone using a lazy collection should pay attention to and this is also a good test to see if a library is really lazy or not.\nOddity #2 # As you all may know, keys in arrays are either integers or strings.\nI don\u0026rsquo;t know if you ever needed such things in your project, but sometimes it would be nice to be able to use any kind of type as keys in an array.\nIt is possible in PHP since version 5.1, by using the \\SplObjectStorage class.\nHowever, it is still not possible with regular arrays, and it will not be possible anytime soon.\nWhen using a lazy collection library, using any kind of keys is possible.\n\u0026lt;?php $input = static function () { yield [\u0026#39;a\u0026#39;] =\u0026gt; \u0026#39;a\u0026#39;; yield new \\StdClass() =\u0026gt; \u0026#39;b\u0026#39;; yield true =\u0026gt; \u0026#39;c\u0026#39;; }; $collection = Collection::fromIterable($input()); foreach ($collection as $k =\u0026gt; $v) { // $k = [\u0026#39;a\u0026#39;], $v = \u0026#39;a\u0026#39; // $k = StdClass, $v = \u0026#39;b\u0026#39; // $k = true, $v = \u0026#39;c\u0026#39; } This collection library let you use any kind of type for keys: scalar, objects, arrays,\u0026hellip; anything!\nThis library could be a valid replacement for \\SplObjectStorage but with much more features.\nTo some extent, this way of working opens up new perspectives and new paradigms.\nAnother ways of handling data, different ways to think about their structure and how to mangle them.\nSee this particular thread #31761 on the Laravel project, there is also some good information there.\nOddity #3 # Have you thought about how to sort a lazy collection when it contains duplicated keys ?\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;sort() -\u0026gt;all(); // [ // \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;, // \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;, // \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;, // \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;, // ] At first sight, it looks like the sort() is a degenerative operation. It seems that it has lost some values during the process. The input had 6 items, the output has 4. But this is wrong.\nActually, the problem comes from the all() operation. The all() operation is basically a shortcut to iterator_to_array().\nWhen converting the collection into an array, values having same keys are lost during the process.\nIn order to circumvent the issue, you can normalize the result. Normalizing the collection will replace keys with integers, without duplicates.\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;sort() -\u0026gt;normalize() -\u0026gt;all(); // [ // 0 =\u0026gt; \u0026#39;a\u0026#39;, // 1 =\u0026gt; \u0026#39;a\u0026#39;, // 2 =\u0026gt; \u0026#39;b\u0026#39;, // 3 =\u0026gt; \u0026#39;b\u0026#39;, // 4 =\u0026gt; \u0026#39;c\u0026#39;, // 5 =\u0026gt; \u0026#39;d\u0026#39;, // ] This is a bit better, but we\u0026rsquo;ve lost the keys during the process. Is there a way to retrieve the result, without loosing any information ?\nThis is obviously possible by just looping over the collection object:\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;sort(); foreach ($collection as $key =\u0026gt; $value) { // \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39; // \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39; // \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39; // \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39; // \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39; // \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39; } But there is another alternative, probably better:\n\u0026lt;?php $input = static function(): \\Generator { yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; yield \u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;; yield \u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;; yield \u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;; yield \u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;; }; $collection = Collection::fromIterable($input()) -\u0026gt;sort() -\u0026gt;wrap() -\u0026gt;all(); // [ // 0 =\u0026gt; [\u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;], // 1 =\u0026gt; [\u0026#39;a\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;], // 2 =\u0026gt; [\u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;], // 3 =\u0026gt; [\u0026#39;b\u0026#39; =\u0026gt; \u0026#39;b\u0026#39;], // 4 =\u0026gt; [\u0026#39;c\u0026#39; =\u0026gt; \u0026#39;c\u0026#39;], // 5 =\u0026gt; [\u0026#39;d\u0026#39; =\u0026gt; \u0026#39;d\u0026#39;], // ] By using the wrap() operation at the end, we make sure to not lose any values when converting into a regular array.\nWhen you use the sort() operation, it relies on the ArrayIterator::uasort() underneath. But the sort() operation has all the logic to wrap all values prior and then unwrap them once they are sorted.\nThat was something hard to figure out at first, which in the end seemed completely logic.\nWhat\u0026rsquo;s next? # Now that I\u0026rsquo;m acquainted with that non-exhaustive list of oddities, I still have some work to do.\nWhat I\u0026rsquo;m trying to achieve with loophp/collection is to focus on the algorithms.\nloophp/collection contains a list of Operation and Transformation classes.\nThose classes are basically classes wrapping a function that does something on the original collection. Operations returns a Generator, Transformation returns usually a simple value.\nMy todo list for the next major version of the library:\nGet rid of Transformation and use Operation exclusively (work in progress in PR #12) Try to reach a better typing coverage, Provide a better documentation with real life examples of use for each Operation. ","date":"10 August 2020","externalUrl":null,"permalink":"/2020/lazy-collection-oddities/","section":"Posts","summary":"","title":"Lazy collection oddities","type":"posts"},{"content":"My job title is Senior analyst but it means all and nothing at the same time.\nAs a highly curious individual, I am passionate about my work in Information Technology and enjoy discovering new aspects of the field. Currently, I am working at European Commission in Brussels, where I am always eager to tackle new and exciting challenges. Twenty years after completing my bachelor\u0026rsquo;s degree in Computer Sciences, I decided to return to school during the Covid pandemic and to pursue a master\u0026rsquo;s degree in the same field at UMons University. My thesis is about \u0026ldquo;Reproducibility in Software Engineering\u0026rdquo; can be found at https://doi.org/10.5281/zenodo.12666898.\nI consider myself a rational thinker with a Bayesian outlook: I usually form my views based on the available evidence and readily update them when new facts emerge. When I encounter something unfamiliar, I tend to favour Occam\u0026rsquo;s razor, starting with the explanation that requires the fewest assumptions while recognising that the simplest explanation is not necessarily the correct one. When presented with an unfamiliar claim, I usually ask what evidence supports it, not out of distrust, but out of intellectual curiosity and a genuine desire to understand. I value factual, verifiable information while remaining mindful of uncertainty, assumptions and the possibility that I may be wrong. At the same time, I do not judge people by their personal beliefs, identities, orientations or even their choice of keyboard layout\u0026hellip; as long as they recognise that Lenovo makes the best laptops in the world !\n2 of my superpowers are anosmia and hyperacusis: I cannot smell a thing, but I can hear noises that nobody else seems remotely bothered by. The former can be remarkably useful in many situations, especially on public transport, while the latter can be rather overwhelming\u0026hellip; especially on public transport ! Mother Nature clearly assembled this sensory package without much of a plan, but one learns to work with what one is given ! Add an INTP-A personality type and a healthy appreciation for sarcasm, and you get a reasonably accurate picture of how I experience the world.\nAs a Linux and FreeBSD enthusiast, I have worked as a full-stack developer with over a decade of experience in PHP. My journey with Drupal began as a hobby, and I progressed to being a contributor, service provider, and eventually, a core maintainer.\nIn 2019, after careful consideration and a desire for new challenges, I made the decision to resign as a Drupal core maintainer and shifted my career focus towards working with Symfony, a popular PHP web application framework. This transition has allowed me to concentrate on creating framework-independent packages, broadening the scope of my work and fostering innovation in the field of software development.\nMy passion for functional programming has also led me to become an avid user and contributor to the NixOS operating system. NixOS is a unique, Linux-based operating system built on top of the Nix package manager, which offers several advantages, such as customizable configurations and a strong focus on reproducibility. By contributing to the NixOS community, I strive to enhance the system\u0026rsquo;s capabilities and help make it an even more powerful and flexible solution for developers and users alike. Recently, I have been promoted NixOS committer. The NixOS repository being one of the most active repository on Github, it is a great honor for me to be part of it.\nIf you are interested in following my work or staying up-to-date with my latest projects and contributions, I invite you to check out my profiles on Packagist, Drupol\u0026rsquo;s Github, Loophp\u0026rsquo;s Github and code.europa.eu. These platforms showcase my commitment to developing high-quality, versatile software solutions and my ongoing involvement in the open-source community, where collaboration and knowledge-sharing are highly valued.\nMy love for STEM is rooted in a deep fascination for Mathematics, especially numbers and how nature utilizes them. Data visualization is another passion of mine, with my favorite works coming from Jason Davies and Mike Bostock. I also hold great admiration for the late Nick Berry\u0026rsquo;s blog.\nI envision my ideal workplace as one that fosters open-source projects and is filled with passionate, open-minded, non-paranoid and friendly teammates.\nAlthough I harbor no regrets regarding my career choices, reflecting on the possibility of starting anew presents an interesting thought experiment. If given the chance to restart my career, I would undoubtedly immerse myself in the study of Mathematics and Information Technology, and work in a university. Both disciplines share a deep connection that is particularly evident in programming, where mathematical concepts underpin numerous computational processes. By delving deeper into these fields, I could further enhance my programming skills and uncover novel approaches to problem-solving. There is something truly special about the atmosphere in a university. The vibrancy of intellectual curiosity, the sense of community, and the camaraderie among both students and faculty members create an environment that fosters growth and collaboration. I cannot help but feel nostalgic for those days when I was immersed in academia, surrounded by the energy and enthusiasm of those committed to the pursuit of knowledge.\nBesides my work and the geek stuff, I am currently fulfilling a childhood dream, I am learning music and piano ! I love photography and I learned by myself most of the secrets of a reflex camera, just for fun. I do swim a lot and I also really like riding my mountain bike. Biking is also one of the reason why I am an heavy user and contributor of OpenStreetMap since more than a decade. When I am not at work, I can often be found wandering around at home in joggers and an old T-shirt.\nLastly, I must mention my cat Apollo and remember the late Izumi and Nakano. With Izumi even having a mention in Drupal core, thanks to a patch I submitted some time ago.\nPlease feel free to reach out and connect with me, my public key fingerprint is: 85F3 72DF 4AF3 EF13 ED34 72A3 0AAF 2901 E804 0715.\n","date":"8 April 2020","externalUrl":null,"permalink":"/about/","section":"Pages","summary":"","title":"About","type":"page"},{"content":"","date":"8 April 2020","externalUrl":null,"permalink":"/bookshelf/","section":"Pages","summary":"","title":"Bookshelf","type":"page"},{"content":"","date":"8 April 2020","externalUrl":null,"permalink":"/projects/","section":"Pages","summary":"","title":"Projects","type":"page"},{"content":"","date":"6 April 2020","externalUrl":null,"permalink":"/tags/covid/","section":"Tags","summary":"","title":"Covid","type":"tags"},{"content":"It\u0026rsquo;s been now more than two weeks that I\u0026rsquo;m teleworking\u0026hellip; and I\u0026rsquo;m fine, really.\nThis blog post will explain how I live this situation and its outcome, according to me.\nI\u0026rsquo;ve been begging for teleworking since I started working at European Commission. For some contractual reasons, it is not allowed for contractors. Europe is leading the trends on many things, but not on that subject sadly. Despite that, I\u0026rsquo;ve been loving my work very much. Working at the European Commission is great and so far it\u0026rsquo;s the best experience I ever had.\nHowever, I remember when I started working, teleworking was allowed under very exceptional circumstances.\nIt allowed me to start my working day earlier and not necessarily finish earlier, it allowed me to work in trainers, it allowed me to enjoy the places here around during the week, it allowed to eat healthier food, it allowed me to do sports after work\u0026hellip; and right now my mountain biking Strava statistics are exploding compared to previous year.\nStrava statistics I always considered teleworking as a win/win situation.\nFirst for my employer because people usually start their day earlier and they usually finish at the same time, so it usually makes more than eight hours per day. Second for me because (and that\u0026rsquo;s the main reason) I don\u0026rsquo;t waste hours in transportation.\nA decade ago, working from home may have seemed like a something impossible\u0026hellip; but today, it\u0026rsquo;s most probably the best thing we can do to our beloved Mother Earth.\nIt took a pandemic to let us to work from home. How sad is this, isn\u0026rsquo;t it ?\nWho led the digital transformation? Maybe that this virus was a signal sent by the Earth saying: \u0026ldquo;Hey Human, you went too far with me. It\u0026rsquo;s my turn to send you something really nasty ! Eat this b*****s !\u0026rdquo;\nJust like in any situation, there\u0026rsquo;s always a good side in a bad situation.\nDo you imagine how the Human lifestyle is now compared to before the crisis ?\nPeople taking their vehicles for nothing and everything, traffic jams, travelling anywhere for paltry sum, cruises, smoking and throwing out cigarette butts everywhere, general overproduction and overconsumption, meat production, nuclear plants, Donald Trump\u0026hellip; and so much more.\nPlease check the following video from Steve Cutts which summarize in a satiric way the way we live on this planet.\nDo you imagine the amount of pollution, noise, dirt, travel that was done before compared to the current situation ?\nAnd now ? Almost all of that went away, we keep the bare minimum.\nAnd despite that, we can still live decently ! On a personal point of view, I really enjoy this moment and this kind of \u0026ldquo;Back to basics\u0026rdquo; lifestyle.\nDon’t get me wrong here. I have no intention whatsoever here of making light of this globally infectious crisis or of the widespread fear, pain, chaos and hysteria that it has so effortlessly brought about all over the place. But just as any coin has two sides and every cloud a silver lining, I\u0026rsquo;m sharing with you all some personal observations here that will remind you that all is most certainly not as bleak as it seems here regardless of what those who profit greatly from fearmongering (politicians, news media etc\u0026hellip;) are making it appear.\nFor you see, while there are most certainly those amongst us who see a crisis situation as something to be feared, regretted, or worth losing sleep over\u0026hellip; there are also those of us who see it as a great opportunity, however unlikely, it might appear to be so in the heat of the moment.\nSo yes, every single time I\u0026rsquo;ve been out lately, I\u0026rsquo;ve rejoiced the calm, the cleanliness and the better quality air. It\u0026rsquo;s crazy how enjoyable a city can be without cars and without all this surrounding noise and pollution.\nCOVID19 and impact on air pollution So yeah, unbelievable as it may appear to be at first, the virus seems to have done a damn fantastic job of bringing humanity together in unimaginably unprecedented ways. People are helping each other out in ways that have never as much as been conceived of before. Some are donating money, food, masks and there’s even this one guy who is assisting humanity by freely gifting people the entire toolkit for 3D printing ventilators.\nThere are also great initiatives that are coming out like in China, where they are talking about permanently banning animals trading. The YALE university offered a free course \u0026ldquo;The Science of well being\u0026rdquo; through Coursera. There are others courses now free of charge on other platforms as well (EDX, Khan Academy). Some Internet provider in Belgium are giving up on Internet quotas and offering other free advantages.\nThere’s something even greater happening under the surface here that’s massively missing everyone’s attention at the moment regarding Nature. Maybe Earth has found itself an opportunity to heal itself. And that\u0026rsquo;s, that it hasn\u0026rsquo;t really even had for ages now.\nEndangered animals continue to resurface all over again, fishes (be aware of fakes!) return to bring back life into Venice, and rare birds begin flocking back to beaches all over Peru.\nWe are the witnesses of a huge, global and unprecedented surge of love, unity, togetherness and positivity, and it took a colossal crisis to bring out the very best of us. Again, how sad is this.\nThat said, I do miss my family for sure and Jitsi greatly helped us to see each other during this hopefully unique period.\nBesides my family, I also miss a couple of other small things. I miss the Saturday local bio market, the local library, the local swimming pool and the local tool shops.\nThe only living being that are a bit unhappy are my cats. They seemed to be a bit worried and upset in their quietness of having all of us every day at home, watching their every moves!\nFinally, it is crazy to admit but only takes but a little effort to see as to what this pandemic is truly meaning: The emergency of an entirely new way of thinking, eating, (tele)working, being, living and thriving.\nThe greatest threat to our civilization right now is not the pollution, the global warming or Donald Trump (albeit?)\u0026hellip; Instead it is our very collective thought pollution that makes everything else look downright inconsequential in comparison. For dark, fearful, angry, frustrated, depressed and all kinds and manners of negative thoughts wreak havoc on our poor planetary consciousness every single day, which in turn get all kinds and varieties of diseases, illnesses, calamities and other sorts of evils to show up within both our individual lives, as well as within our shared collective reality experiences.\nRemember that sometimes the true picture of reality is quite the exact opposite of that which gets depicted to you. But therein lies our greatest opportunity to develop better discernment, so that we too may one day be able to separate the wheat from the chaff and the truth from the lie for that matter.\nIt is then mandatory to re-centralize our essentials, to wake up!\nTo achieve that, people, companies, organizations needs to show the path to follow.\nWhat if the European Commission was the first ? :)\nInspirations:\nYoutube European Commission Twitter Reddit Reddit ","date":"6 April 2020","externalUrl":null,"permalink":"/2020/covid19-teleworking-and-the-other-side-of-the-coin/","section":"Posts","summary":"","title":"COVID19, teleworking and the other side of the coin","type":"posts"},{"content":"","date":"6 April 2020","externalUrl":null,"permalink":"/tags/society/","section":"Tags","summary":"","title":"Society","type":"tags"},{"content":"","date":"6 April 2020","externalUrl":null,"permalink":"/tags/telework/","section":"Tags","summary":"","title":"Telework","type":"tags"},{"content":"","date":"6 April 2020","externalUrl":null,"permalink":"/tags/work/","section":"Tags","summary":"","title":"Work","type":"tags"},{"content":"","date":"6 April 2020","externalUrl":null,"permalink":"/tags/work-from-home/","section":"Tags","summary":"","title":"Work From Home","type":"tags"},{"content":"","date":"9 September 2019","externalUrl":null,"permalink":"/tags/conferences/","section":"Tags","summary":"","title":"Conferences","type":"tags"},{"content":"","date":"9 September 2019","externalUrl":null,"permalink":"/tags/library/","section":"Tags","summary":"","title":"Library","type":"tags"},{"content":"When I was a student, it was easy to remember when holidays were coming. Now that I\u0026rsquo;m working since more than a decade, it\u0026rsquo;s harder to remember and distinguish those period sometimes!\nThat said, I have to say that the pace at work is different and this is how I remember that I should take some days off.\nWorking in a multi cultural environment means that people are going back to their roots for holidays.\nAnd that means that there are less people available at the office.\nHowever, on my side and since the last blog post in April, the word \u0026ldquo;holidays\u0026rdquo; was kind of meaningless !\nWhy no more blog post # In June, I\u0026rsquo;ve started to work in a new team with new colleagues, a completely different project, different office, different location and a completely different atmosphere and state of mind.\nI will be more focusing on PHP development rather than Drupal, and it\u0026rsquo;s a good thing.\nOf course, I will continue to maintain my modules and the maintenance of Drupal 7, but I won\u0026rsquo;t be an active contributor as I used to be during past years.\nIn just two months, we delivered our first successful project based on Symfony/API Platform and the client is so far super happy.\nSo quite a lot of changes in my professional environment lately and I\u0026rsquo;m already very glad of the outcome.\nHowever\u0026hellip; # I haven\u0026rsquo;t left aside my creativity when it comes to development, and here are the packages I\u0026rsquo;ve been making lately.\nPHP OS Info PHP Launcher PHP Collection Composer Packages Belgian national number faker PHP OS Info # Get information of the current operating system where PHP is running on.\nThere are many packages that does that already but most of them are based on the use of the variable PHP_OS that contains the operating system name PHP was built on.\nHowever, PHP_OS might be sometimes not very accurate, then using php_uname() might be a better fit for detecting the operating system, we only use it as a fallback.\nPHP OS Info uses php_uname() and a static list of existing operating systems, and then from there, tries to deduct the operating system family.\nThe project has been already adopted by the Acquia BLT project and vaimo/composer-patches.\nPHP Launcher # This library let you launch a file or a resource with the your default OS application.\nI actually needed this small library while making the GraphViz exporter in PHPTree.\nPHP Collection # Collection is a functional utility library for PHP.\nIt\u0026rsquo;s similar to other available collection libraries based on regular PHP arrays, but with a lazy mechanism under the hood that strives to do as little work as possible while being as flexible as possible.\nCollection leverages PHP\u0026rsquo;s generators and iterators to allow you to work with very large data sets while keeping memory usage as low as possible.\nFor example, imagine your application needs to process a multi-gigabyte log file while taking advantage of this library\u0026rsquo;s methods to parse the logs. Instead of reading the entire file into memory at once, this library may be used to keep only a small part of the file in memory at a given time.\nOn top of this, this library:\nis immutable, is extendable, leverages the power of PHP generators and iterators, uses S.O.L.I.D. principles, doesn\u0026rsquo;t depends or require any other library or framework. Except a few methods, most of methods are pure and return a new Collection object.\nThis library has been inspired by the Laravel Support Package and Lazy.js.\nComposer packages # Composer Packages is a Composer plugin for getting information about installed packages in your project.\nIt could be very useful for anyone who wants to build a package discovery system, crawling the filesystem is then not needed.\nThanks to Bob den Otter, it has been adopted from the beginning by the Bolt community for the bolt/core project.\nBelgian national number faker # Belgian national number generator using fzaninotto/faker.\nI guess there are nothing to say here :-)\nAnd now ? # I will continue to focus on my own projects, going to prepare myself for the next EUFOSSA hackathon organized by the European Commission, on the 5 and 6 of April (the first one was about Symfony).\nI\u0026rsquo;m also pushing on the PHP CS Fixer project for some changes, I hope they will get in very soon.\nAlso, the projects drupol/php-conventions and drupol/drupal-conventions are still actively maintained and since PSR-2 has been deprecated in favor of PSR-12, those packages has already been updated.\n","date":"9 September 2019","externalUrl":null,"permalink":"/2019/summer-vacations-are-over/","section":"Posts","summary":"","title":"Summer vacations are over?","type":"posts"},{"content":"","date":"9 September 2019","externalUrl":null,"permalink":"/tags/travel/","section":"Tags","summary":"","title":"Travel","type":"tags"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/automation/","section":"Tags","summary":"","title":"Automation","type":"tags"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/composer/","section":"Tags","summary":"","title":"Composer","type":"tags"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/console/","section":"Tags","summary":"","title":"Console","type":"tags"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/robo/","section":"Tags","summary":"","title":"Robo","type":"tags"},{"content":"","date":"21 April 2019","externalUrl":null,"permalink":"/tags/task-runner/","section":"Tags","summary":"","title":"Task Runner","type":"tags"},{"content":"It\u0026rsquo;s been 2 months now that I left aside my regular work with Drupal 8 and switched back to Atomium development for Drupal 7.\nI will soon publish another post on all the new stuff that has been made there, but for now, I will focus on a side project I\u0026rsquo;ve been doing.\nStarted as a proof-of-concept a couple of weeks ago, Taskman is tasks runner based on Robo, extendable at will through YAML files.\nIt has been inspired by what\u0026rsquo;s already existing so far, but not tied to Drupal or whatsoever.\nHistory # Taskman is a tasks runner written in PHP, for PHP. It\u0026rsquo;s based on Robo, a PHP framework widely used in many communities.\nRobo is a console application that list all the available commands that a user can run. Those commands contains tasks that are executed one after the other.\nWhen shipping a Robofile.php file in your projects, Robo will provide new commands based on what\u0026rsquo;s inside it.\nI invite you to read the documentation if you want to know more on how to extend it or use it as a framework, just like Taskman does.\nThe only downside of Robo is that you need to code if you want to provides commands and tasks.\nThe goal of Taskman is to remove this annoyance and let user defines custom commands in YAML.\nOf course, as Taskman is based on Robo, custom commands using PHP could still be created and used.\nAs YAML is quite friendly, it\u0026rsquo;s rather convenient to define new commands, it\u0026rsquo;s fast and easy.\nUsage # To use Taskman in your project today, two steps are required:\ncomposer require phptaskman/core --dev Then, create a file taskman.yml.dist that contains your custom commands:\ncommands: hello-world: - ls -la - touch example.md - ls -la - rm example.md - ls -la Now, when you run:\n./vendor/bin/taskman Your custom command should be available:\nTaskman dev-master Usage: command [options] [arguments] Options: -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output -n, --no-interaction Do not ask any interactive question --simulate Run in simulated mode (show what would have happened). --progress-delay=PROGRESS-DELAY Number of seconds before progress bar is displayed in long-running task collections. Default: 2s. [default: 2] -D, --define=DEFINE Define a configuration item value. (multiple values allowed) --working-dir=WORKING-DIR Working directory, defaults to current working directory. [default: \u0026#34;/home/pol/dev/git/taskman/core\u0026#34;] -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: hello-world Run a task. help Displays help for a command list Lists commands Taskman includes a mechanism to automatically detects configuration files in the dependencies of your project.\nThat means that you could have a PHP package that contains only a YAML file with your custom commands, Taskman will find it automagically.\n(Almost) real life example # Let\u0026rsquo;s say that your project ship with a file: taskman.yml.dist containing:\ndirectories: build: \u0026#34;build\u0026#34; tests: \u0026#34;tests\u0026#34; log: \u0026#34;logs\u0026#34; commands: create-directories: - mkdir -p ${directories.build} - mkdir -p ${directories.tests} - mkdir -p ${directories.log} This YAML files provides a single command that contains variables.\nIf for some reason those variables are not the one you expect, you can still override them manually.\nTo override manually those variables, you have to create a file taskman.yml which should not be committed to your project and ideally added to .gitignore.\nThat file could be:\ndirectories: tests: \u0026#34;${directories.build}/tests\u0026#34; log: \u0026#34;${directories.build}/logs\u0026#34; It\u0026rsquo;s also possible to define more advanced commands, but the documentation is not yet ready.\nTesting framework # I\u0026rsquo;ve always been using PHPSpec for unit testing, here Taskman is a kind of plugin for Robo, so I\u0026rsquo;ve decided to use Codeception, mostly for functional tests.\nAs I don\u0026rsquo;t want to do tests for the Robo plugin stuff (it\u0026rsquo;s already done in Robo), simple and functional tests using Codeception was a good choice, I really enjoyed doing it.\nI really liked the ease of testing console application, see it by yourself:\n\u0026lt;?php declare(strict_types = 1); $I = new FunctionalTester($scenario); $I-\u0026gt;wantTo(\u0026#39;Check if the executable is found.\u0026#39;); $I-\u0026gt;amInPath(\\realpath(__DIR__ . \u0026#39;/fixtures/test0\u0026#39;)); $I-\u0026gt;runShellCommand(\u0026#39;composer install --ansi -n --no-progress --no-scripts --no-dev --no-suggest\u0026#39;); $I-\u0026gt;canSeeFileFound(\u0026#39;../../../_output/vendor/bin/taskman\u0026#39;); $I-\u0026gt;runShellCommand(\u0026#39;../../../_output/vendor/bin/taskman\u0026#39;); During the making of these, I also noticed that Composer doesn\u0026rsquo;t allow you to symlink the package source inside it.\nWhile trying to get around this by writing my own composer plugin, I found this socialengine/composer-symlinker which is exactly doing what I was looking for, this really helped me for the tests.\nFuture development # I have quite a few ideas to improve Taskman, but as they are not yet mature, I cannot really implement them.\nOne of the first idea was to get rid of the Taskman executable (./vendor/bin/taskman) and use exclusively the Robo executable (./vendor/bin/robo).\nAfter some discussions with Greg Anderson, it would be possible to do it using CGR, but I still need to look deeper into it.\n","date":"21 April 2019","externalUrl":null,"permalink":"/2019/taskman-a-friendly-tasks-runner/","section":"Posts","summary":"","title":"Taskman, a friendly tasks runner","type":"posts"},{"content":"","date":"7 April 2019","externalUrl":null,"permalink":"/tags/api-platform/","section":"Tags","summary":"","title":"Api-Platform","type":"tags"},{"content":"","date":"7 April 2019","externalUrl":null,"permalink":"/tags/eufossa/","section":"Tags","summary":"","title":"Eufossa","type":"tags"},{"content":"During the first weekend of April 2019, a hackathon was held in Silverquare Triomphe venue in Brussels.\nThe organizer, the European Commission, and a community of carefully selected developers participated to a hackathon in an amazing place.\nThe goal of having such an amount of skills contained in one single place, is to participate to the EU-FOSSA hackathon that the European Commission organised and funded.\nNicolas Grekas, Fabien Potencier and Mario Campolargo The event # EU-FOSSA stands for EU-Free and Open Source Software Auditing project, a project which is managed by the European Commission\u0026rsquo;s Directorate General for Informatics, the DIGIT.\nThe EU-FOSSA project is organising in parallel a bug bounty for the PHP Symfony software. Hackers can get rewards of up to EUR 15.000 for critical bugs they find. There is even a 20% bonus added to the prize if the hackers provide a fix for the bug they report.\nWhile the security was the focus during this weekend, API Platform and Symfony framework was the main topic of this first successful hackathon.\nThe European Commission pulled out all the stops for this event, every participant received a very nice welcome gift composed of (take a breath):\nA Raspberry Pi version 3B, A case for it (the best one I\u0026rsquo;ve seen so far) A very nice PHP elephant - thanks Nicolas Grekas ! 2 t-shirts A few badges and stickers for swag Welcome pack, photo by Robert Czarny The participants # During two days, participants coming mostly from Europe, Morocco, Russia and even US and Cuba, were having a complete programme with meetings, goals and tasks.\nThose 50 selected developers were personally invited a month before the event and most of them were PHP heads, driving the PHP world and shaking the trends since a couple of years.\nI will take the opportunity to personally thanks all the organizers, it was perfect. I was and I am glad to be part of this.\nNeedless to say that I was extremely happy to have a talk with people that I knew for years, as a Github or Slack pseudonyms, or even through composer install command logs!\nGroup photo, photo by Michael Cullum The goals # Basically, the task was to browse the Symfony\u0026rsquo;s issue queue, pickup an issue, then ensure that the issue gets fixed and closed. Often, those issues are linked to a pull request, so knowing the Symfony framework and obviously PHP was a must during these two days.\nOn my side, I worked on 4 issues. I closed 1 issue and submitted one PR. I started a second one but I wasn\u0026rsquo;t able to reproduce the reported issue, so the issue was closed. I started a third one but I couldn\u0026rsquo;t reproduce what was reported, then the original reporter replied and we closed the issue. The last one was the same.\nEach issue being worked during the hackathon was tagged with the tag: \u0026ldquo;⭐ EUFOSSA Hackathon\u0026rdquo;, have a look at how much issue were taken care of.\nThe first issue I worked on was quite controversial because apparently it came back quite a few times and nobody never agreed on how to fix it. But after some back and forth discussions with Hamza Amrouche, Nicolas Grekas, Fabien Potencier and Grégoire Pineau, we finally agreed on something.\nThen, Nicolas G. and Fabien P. made the review and the PR was merged, in less than an hour.\nTo be honest, I rarely seen such a reactivity in Open Source, I like it very much.\nThe venue # Silversquare Triomphe is situated near the new Chirec hospital, near the ULB, and at 900 meters away from the Etterbeek station.\nIt\u0026rsquo;s the old Levis (clothes) building, a huge building where all the floors were completely \u0026ldquo;refactored\u0026rdquo; to become a co-working place.\nThe place has been designed by Lionel Jadot, a belgian interior designer.\nI was feeling quite at home it the building, it was warm, cosy and welcoming.\nDespite the fact that the floor was pretty busy and what I particularly liked is the fact that it was very quiet, conducive for working. Sound isolation panels were everywhere, properly integrated in the decoration, completely part of it.\nAs I was with my colleagues: Vitor Da Costa, Diogo Vargas and last but not least, my wingman Robert Czarny, we started to work in a booth, surrounded by cork wood barks.\nPerfectly balanced and focused, as it should be. Then some of us moved on the sofa placed on the stairs. Sounds weird ? Check the photos album :-)\nWe couldn\u0026rsquo;t find the time to feel hungry and didn\u0026rsquo;t feel the need to go out for anything, we had very good meals and drinks, it was awesome.\nYummy food! The numbers # On Sunday late afternoon, we were invited to a meeting, the last one, for the closing remarks.\nIn less than 48 hours, around 80 issues were closed and around 80 PRs were merged.\nIn less than 48 hours, we achieved around 2 months of work. Can you imagine?\nSymfony\u0026rsquo;s hackathon insight Working on something through Github, emails or even chat is great, but hackathon is definitely more efficient.\nDespite the fact that it requires a lot of energy, every single person that was there was quite pleased, a lot of smiles, a lot of good energy and vibes in the whole building.\nThe outcome # This is the first hackathon since quite a long time, I was usually doing hackathons during Drupalcon.\nThis first hackathon will be remembered as my first entry in the Symfony world where my first PR was merged, hopefully not the last.\nThen, I had the chance to talk with Fabien in my car, while I was driving back to my home, as I was passing by the station, I gave him a lift.\nI asked him a couple of questions regarding the new Symfony\u0026rsquo;s HttpClient and the adoption of PSRs. It was quite an interesting discussion.\nMonday morning # I came to work with a bright smile on my face, exhausted but my motivation batteries charged to the maximum, I can\u0026rsquo;t wait to work with this amazing framework again and with this very nice community.\nThanks and see you probably to the next one!\nUseful links # Matthias Pigulla\u0026rsquo;s blog post My photos album Twitter #FOSSHackathons hashtag Maxime Veber\u0026rsquo;s (@Nek-) photos album Yanick Witschi\u0026rsquo;s (@Toflar) blog post BeMyApp photos album ","date":"7 April 2019","externalUrl":null,"permalink":"/2019/first-eu-fossa-hackathon-about-security-php-symfony-and-api-platform/","section":"Posts","summary":"","title":"First EU-FOSSA Hackathon about security, PHP, Symfony and API Platform","type":"posts"},{"content":"","date":"7 April 2019","externalUrl":null,"permalink":"/tags/hackathon/","section":"Tags","summary":"","title":"Hackathon","type":"tags"},{"content":"","date":"7 April 2019","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/composition/","section":"Tags","summary":"","title":"Composition","type":"tags"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/data-structure/","section":"Tags","summary":"","title":"Data Structure","type":"tags"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/final/","section":"Tags","summary":"","title":"Final","type":"tags"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/inheritance/","section":"Tags","summary":"","title":"Inheritance","type":"tags"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/oop/","section":"Tags","summary":"","title":"Oop","type":"tags"},{"content":"I\u0026rsquo;ve been contributing to a couple of trending php libraries recently and during the analysis and the making of the patches, noticed that many libraries were using PHP not in the way I was used to.\nMany of those libraries are having \u0026lsquo;final\u0026rsquo; classes.\nWhy using final classes everywhere, what is the advantage? As I\u0026rsquo;m not using final classes in my own projects, am I wrong since the beginning? This article will try to bring an explanation to this.\nJust like Marco Pivetta (@ocramius) or Tomas Votruba wrote on their respective blogs, this article will basically explain the use of the final keywords.\nLibraries like PHP Infection, PHPSpec, PHP-CS-Fixer are using final classes almost everywhere.\nWhen you use the word final for a class, it means that your class will not be able to extend another one.\nThat means that you forbid anyone to create a class that extend your class.\nThe goal of creating classes is to use the amazing inheritance mechanism, why would we forbid that ?! At first, that sounds stupid, but in the end, it\u0026rsquo;s not that bad.\nBy doing so, you enforce users to use a proper dependency injection mechanism if they really need to use the parent class.\nSince a couple of months, I\u0026rsquo;m starting use more and more composition over inheritance.\nComposition is in the end much more flexible than inheritance and dependency injection is a valid way to compose a class.\nHowever, there is a simple solution if you really need to extends a final class.\nAs you cannot extend a final class, the only way is to inject the final class as argument in the constructor of your class.\nIf I want to use it in my own class, as I cannot extend it, the only way to use it is to inject it in the constructor.\nThen, I can chose to expose or not some of it\u0026rsquo;s methods, a bit like the proxy pattern.\nOn the other hand, using this construction method could be a way to fill the gap on how to have a class extending multiple objects.\nIn my article about How to use PHP Traits I wrote a bit about it the fact that it is not possible to inherit from multiple classes at the same time\u0026hellip; using inheritance.\nWhen you have a good composition mechanism, this is fully possible.\nLet\u0026rsquo;s say we have two classes:\nand\nIf you want to create a new class that potentially could use methods from Foo and Bar:\nFirst, create an interface for each parent classes, this step is optional but greatly encouraged.\nand\nThen, create your custom class:\nThen, that\u0026rsquo;s it ! You\u0026rsquo;ll be able to use methods from objects Foo and Bar in your own custom class, and expose some of them if needed.\nThat said, inheritance is not something to throw away.\nInheritance is something to use, but keep in mind that if you want an ultimate flexibility, composing your classes with dependency injection mechanism is the key.\nYou might end-up writing more code but in the end, you\u0026rsquo;ll have a better control on your classes and what to expose or not to the public.\n","date":"21 February 2019","externalUrl":null,"permalink":"/2019/php-composition-and-inheritance/","section":"Posts","summary":"","title":"PHP, composition and inheritance","type":"posts"},{"content":"","date":"21 February 2019","externalUrl":null,"permalink":"/tags/value-objects/","section":"Tags","summary":"","title":"Value Objects","type":"tags"},{"content":"","date":"27 December 2018","externalUrl":null,"permalink":"/tags/benchmark/","section":"Tags","summary":"","title":"Benchmark","type":"tags"},{"content":"","date":"27 December 2018","externalUrl":null,"permalink":"/tags/graph-theory/","section":"Tags","summary":"","title":"Graph Theory","type":"tags"},{"content":"Hopefully for most of us, holidays are here. A special time for resting and enjoy quality time with the family, but also for thinking.\nEven if I\u0026rsquo;m not attached to any religion, doing a Christmas tree is a kind of tradition\u0026hellip; cats really loves it :-)\nWhile decorating the tree, it got me thinking about tree based data structure. I used to play with trees into a previous project with Neo4J and I remember that I loved it.\nAnd even if I have vague souvenirs about trees and data structure from university, I started to re-investigate into graphs and trees.\nA bit of theory # The term \u0026ldquo;tree\u0026rdquo; was coined in 1857 by the British mathematician Arthur Cayley.\nIn mathematics, and, more specifically, in graph theory, a tree is an undirected graph in which any two vertices are connected by exactly one path. Every acyclic connected graph is a tree, and vice versa.\nJust like in Nature, there are different types of trees for data structure and the various kinds of data structures referred to as trees in computer science have underlying graphs that are trees in graph theory, although such data structures are generally rooted trees.\nA rooted tree may be directed either making all its edges point away from the rootn (in which case it is called an arborescence, branching, or out-tree), when its edges point towards the root (in which case it is called an anti-arborescence or in-tree).\nA rooted tree itself has been defined as a directed graph.\nI\u0026rsquo;m just giving here a small introduction, you can find more details on this on Wikipedia.\nExamples # Here\u0026rsquo;s a very simple data representation using a tree.\nAnother example of tree 12 nodes, degree 11 (each node has maximum 11 children], 11 leaves and height is 1.\nThis tree is full, every nodes other than the leaves has the same number of children.\nAnother example of tree 12 nodes, degree 3, 8 leaves, height is 2.\nThis tree is complete, every level, except possibly the last, is completely filled, and all nodes are as far left as possible.\nThere are many configuration possible for storing data in a tree, here\u0026rsquo;s another one.\n12 nodes, degree 1, 1 leaf, height is 11. This tree is a degenerate (or pathological) tree is where each parent node has only one child node.\nAs you can see, graphs have its own vocabulary and classification.\nA tree can be summarized with one simple definition (from this amazing article)\nA tree is a collection of entities called nodes. Nodes are connected by edges. Each node may or may not contains some data, and it may or may not have a child node. The first node of the tree, usually at the top, is called the root node.\nTree traversal # In computer theory and algorithms, one of the most important facet of trees is the way we read them. As a tree is a 2 dimensional data structure, we cannot read it from the top to the bottom like we would do it in a simple list, data are organized hierarchically.\nThat said, we must find strict ways to \u0026ldquo;traverse\u0026rdquo; them.\nThere are 4 well known tree traversal algorithms:\nIn Order (Depth first) Pre Order (Depth first) Post Order (Depth first) Breadth first (Breadth first) Usually those traversal algorithms are made for binary trees (2-ary trees), trees having maximum 2 children per node.\nFind all the details and more on Wikipedia.\nAbout the library # The purpose of this post is not about trees theory but about a library I\u0026rsquo;ve been working on called: PHPTree.\nIt allows you to manipulate trees, to export and import them.\nPHPTree is gentle with memory thanks to PHP Iterator(Yield, ArrayObject), I tried to use them as much as possible.\nTree types # Currently, the library provides 5 different types of objects, maybe some other trees will be implemented later, depending on my availability.\nNode: A simple base class that can be added to another one or be used as a parent for other children.\nN-ary node: It extends the Node class and allows you to cap the number of children a node can have. A K-ary or N-ary tree is tree in which each node has no more than N children. This tree does the heavy lifting for you when adding nodes.\nValue node: extends the N-ary node and allows you to attach a value to the node.\nKeyValue node: extends the Value node and allows you to attach a key and a value to the node.\nTrie node: extends the KeyValue node, a Trie tree node. (see example)\nTree traversal algorithms # PHPTree also implements the 4 well known tree traversal algorithms with some extra.\nMany of these algorithms are made to work with 2-ary trees (binary trees), in PHPTree, they are working for all kind of trees.\nI think this is something new, I was not able to find any equivalent on the internet.\nExample with a binary tree # Let this binary tree (2-ary tree):\nAnother example of tree be traversed with the In-Order algorithm, the result would be:\nO, G, P, C, Q, H, R, A, S, I, T, D, U, J, V, root, W, K, X, E, Y, L, Z, B, M, F, N Example with another tree # Let this tree (4-ary tree):\nAnother example of tree be traversed with the In-Order algorithm, the result would be:\nU, V, E, W, X, Y, F, Z, A, G, H, I, J, B, K, L, root, M, N, C, O, P, Q, R, D, S, T The InOrder tree traversal is usually made for binary trees, PHPTree has standardized the algorithm and it can work with any type of trees.\nTree exporters # PHPTree gives you the opportunity to export trees in multiple formats:\nTo text To ascii (just for fun) To PHP array To Graph Here\u0026rsquo;s an example of how this graph is exported:\nTo text # [PHPTree [is [fast [to] [manipulate]] [and [trees] [data]]] [a [fun [structure]] [library]]] To ascii # ├─ PHPTree └─┐ ├─┐ │ ├─ is │ └─┐ │ ├─┐ │ │ ├─ fast │ │ └─┐ │ │ ├─┐ │ │ │ └─ to │ │ └─┐ │ │ └─ manipulate │ └─┐ │ ├─ and │ └─┐ │ ├─┐ │ │ └─ trees │ └─┐ │ └─ data └─┐ ├─ a └─┐ ├─┐ │ ├─ fun │ └─┐ │ └─┐ │ └─ structure └─┐ └─ library To PHP array # \u0026lt;?php $tree = [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;PHPTree\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;is\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;fast\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;to\u0026#39;, ], 1 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;manipulate\u0026#39;, ], ], ], 1 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;and\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;trees\u0026#39;, ], 1 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;data\u0026#39;, ], ], ], ], ], 1 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;a\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;fun\u0026#39;, \u0026#39;children\u0026#39; =\u0026gt; [ 0 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;structure\u0026#39;, ], ], ], 1 =\u0026gt; [ \u0026#39;value\u0026#39; =\u0026gt; \u0026#39;library\u0026#39;, ], ], ], ], ]; To Graph # Graph is a class from the package graphp/graph of Christian Lück, so I won\u0026rsquo;t be able to show it here.\nHowever, this is thanks to it that we can export trees into images or dot files thanks to Graphviz and it\u0026rsquo;s PHP package graphp/graphviz.\nTree importers # PHPTree also provides 2 importers:\nFrom text From PHP array The text exporter and importer can be very useful to store/retrieve a tree into/from a database.\nTree modifiers # A modifier is an object that modify a tree and return a new modified tree.\nLet this tree:\nAnother example of tree Be modified with the Reverse modifier:\nAnother example of tree Code examples # I posted on gist the code that I used to generate the trees in this post, feel free to test them as well.\nJust for fun, I also made 2 trees with 10000 nodes to visually explain the difference between a tree of degree 2 and 3:\nTree with degree 2 and 10000 nodes Tree with degree 3 and 10000 nodes Conclusion # Building this library helped me understand in depth the advantage of using Iterators and Yield in my projects.\nBesides the fact that doing this library was really fun, some parts were extremely hard, especially the tree traversal algorithms.\nLet me know if you\u0026rsquo;re going to use it and how! Feedback is very welcome.\n","date":"27 December 2018","externalUrl":null,"permalink":"/2018/phptree-a-fast-tree-implementation/","section":"Posts","summary":"","title":"PHPTree, a fast tree implementation","type":"posts"},{"content":"","date":"27 December 2018","externalUrl":null,"permalink":"/tags/tree/","section":"Tags","summary":"","title":"Tree","type":"tags"},{"content":"","date":"27 December 2018","externalUrl":null,"permalink":"/tags/trie/","section":"Tags","summary":"","title":"Trie","type":"tags"},{"content":"","date":"30 October 2018","externalUrl":null,"permalink":"/tags/coding/","section":"Tags","summary":"","title":"Coding","type":"tags"},{"content":"Recently, I\u0026rsquo;ve been busy rewriting small PHP libraries like ValueWrapper, HTMLTag, PHPNgrams, DynamicObjects, PHPartition, PHPermutations and Memoize.\nI mostly rewrote them because of multiple things I wanted to do:\nUse SOLID principle: The Single Responsibility Principle Automatically generate and publish the library documentation using APIgen Improve the tests quality by using PHP Infection Improve the class hierarchy design when using a PHP trait and remove some limitations. This article will explain what are traits and will try to propose, without pretension, a better way to write them.\nLet\u0026rsquo;s start with the definition of a trait.\nTraits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.\nWhen designing a software or a library, we are often busy thinking on how to make it work properly and how it could do the job as expected. This is already a good part of the job. When it comes to designing the library and it\u0026rsquo;s classes organisation, it\u0026rsquo;s another world that sometimes can take as much time as the real implementation.\nHow to reduce and minimize code duplication, How to make sure that the inheritance hierarchy is optimal, Which design pattern to use, etc etc Sometimes, it\u0026rsquo;s possible that you\u0026rsquo;d wish your class to inherit from multiple classes, but unlike in Python (and probably some other languages), it\u0026rsquo;s not possible in PHP (Yet?).\nOf course, inheritance with multiple classes can be hard to work with, it adds complexity and has issues like the Diamond problem.\nThe \u0026ldquo;diamond problem\u0026rdquo; (sometimes referred to as the \u0026ldquo;deadly diamond of death\u0026rdquo;) is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of C?\nBut obviously, PHP is not concerned by this.\nIntroduced in PHP 5.4, using traits is a way to solve this. Basically, it allows developers to reuse horizontally the same code across independent and different classes hierarchies.\nIt seems to be an amazing discovery, but it\u0026rsquo;s nothing new, this concept is used in languages like Scala and Perl.\nA trait is a good way to provide new features to a class, it\u0026rsquo;s a good way, but it has drawbacks.\nLet\u0026rsquo;s see with a basic example.\nIn the following example, we want to create a trait that compute the greatest common divisor of 2 integers.\n\u0026lt;?php declare(strict_types = 1); trait GreatestCommonDivisor { /** * Get the divisors of a given number. * * @param int $num * The number. * * @param int $start * The number to start from. * * @return int[] * The divisors of the number. */ public function factors(int $num, int $start = 2): array { $return = [1, $num]; $end = ceil(sqrt($num)) + 1; for ($i = $start; $i \u0026lt; $end; $i++) { if (0 !== $num % $i) { continue; } $return[$i] = $i; $return[$num/$i] = $num/$i; } asort($return); return array_values($return); } /** * Get the greatest common divisor. * * @param int ...$x * The numbers. * * @return int * The greatest common divisor. */ public function gcd(...$x): int { $x = array_map([$this, \u0026#39;factors\u0026#39;], $x); $intersect = array_intersect(...$x); return end($intersect); } } This trait can be used in any classes just by adding:\n\u0026lt;?php declare(strict_types = 1); class Foo { use GreatestCommonDivisor; } This will add the 2 methods to your class and you\u0026rsquo;ll be able to call them.\n\u0026lt;?php declare(strict_types = 1); $foo = new Foo(); $factors = $foo-\u0026gt;factors(10); $gcd = $foo-\u0026gt;gcd(10, 15); At this point, one may raise 2 questions.\nThe first one is obvious, what about name collisions ? What if the class that uses this trait has already methods having the same names ?\nThere is a way to avoid name collisions:\nuse \\your\\namespace\\GreatestCommonDivisor { GreatestCommonDivisor::gcd as traitGcd; } Then, in that case, if your class has already got a gcd() method, you won\u0026rsquo;t have naming collisions and you\u0026rsquo;ll be able to use the method traitGcd().\nThe second question is, what if I only want to expose the gcd() method and not the other one(s) ?\nIn this particular case it\u0026rsquo;s not a big deal, but if you want to create a library using a trait, there are chances that you would like to expose only the relevant methods.\nUnfortunately, there is no way to restrict the visibility of methods defined in a trait. Of course, you could wrap your trait in an new object, then wrap that object in another new trait\u0026hellip; but I think you agree with me, it\u0026rsquo;s messy.\nThis issue raise another set of issues. Using traits usually gives you more work. Why ?\nAs the visibility of methods cannot be changed, you\u0026rsquo;ll have to test all the methods, individually.\nTesting private or protected methods could be cumbersome and in some cases, it\u0026rsquo;s better to test public methods which internally uses those methods.\nA way to avoid those situations is to use traits in a different way, based on an object.\nSee the following example, it\u0026rsquo;s the same as the first example, but rewritten.\nFirst we are going to create a single class.\n\u0026lt;?php declare(strict_types = 1); class GreatestCommonDivisor { /** * Get the divisors of a given number. * * @param int $num * The number. * * @param int $start * The number to start from. * * @return int[] * The divisors of the number. */ public function factors(int $num, int $start = 2): array { $return = [1, $num]; $end = ceil(sqrt($num)) + 1; for ($i = $start; $i \u0026lt; $end; $i++) { if (0 !== $num % $i) { continue; } $return[$i] = $i; $return[$num/$i] = $num/$i; } asort($return); return array_values($return); } /** * Get the greatest common divisor. * * @param int ...$x * The numbers. * * @return int * The greatest common divisor. */ public function gcd(...$x): int { $x = array_map([$this, \u0026#39;factors\u0026#39;], $x); $intersect = array_intersect(...$x); return end($intersect); } } Then a trait\n\u0026lt;?php declare(strict_types = 1); trait GreatestCommonDivisor { /** * Get the greatest common divisor. * * @param int ...$x * The first number. * * @return int * The greatest common divisor. */ function gcd(...$x): int { return (new GreatestCommonDivisor())-\u0026gt;gcd(...$x); } } You can find the online code at: https://3v4l.org/LCmNp\nWhat are we doing here ?\nBasically, the GreatestCommonDivisor object is wrapped in a trait, and the trait exposes only the method needed.\nWhen this trait will be used, in any object you want, it will only provide 1 method and nothing else.\nTo summarize this post:\nEven if traits seems to be wonderful, use them with parsimony, at the last resort, All the traits that you create should wrap an inner class that does the job properly, Reduce or don\u0026rsquo;t do logic in your traits, Do not overload traits with a lot of methods, try to keep in mind that \u0026ldquo;1 trait = 1 method\u0026rdquo;, Carefully select which methods you want to expose in your traits, Unit test your objects and not your traits. ","date":"30 October 2018","externalUrl":null,"permalink":"/2018/how-to-use-the-php-traits/","section":"Posts","summary":"","title":"How to use the PHP traits?","type":"posts"},{"content":"","date":"30 October 2018","externalUrl":null,"permalink":"/tags/solid/","section":"Tags","summary":"","title":"Solid","type":"tags"},{"content":"","date":"30 October 2018","externalUrl":null,"permalink":"/tags/traits/","section":"Tags","summary":"","title":"Traits","type":"tags"},{"content":"","date":"15 July 2018","externalUrl":null,"permalink":"/tags/career/","section":"Tags","summary":"","title":"Career","type":"tags"},{"content":"","date":"15 July 2018","externalUrl":null,"permalink":"/tags/drupal/","section":"Tags","summary":"","title":"Drupal","type":"tags"},{"content":"","date":"15 July 2018","externalUrl":null,"permalink":"/tags/european-commission/","section":"Tags","summary":"","title":"European Commission","type":"tags"},{"content":"I started to use Drupal ~13 years ago. It was the end of life of version 4.5 at the time.\nAs I love photography, I first tried to use Drupal to publish my photos. I remember at the time, the struggle to integrate Gallery2 and Drupal… aaah time flies.\nAs always, I was motivated to learn it. The community was huge, active and responsive… and on the top of that, it’s a product out of my beloved country. To be honest, I gave up many times by lack of time, but also because my PHP knowledge was not really high. I felt that there was a great potential but I was frustrated to not be able to handle it properly.\nDrupal 5 came out, then 6 and I started to do small websites for friends (we all started like this, isn\u0026rsquo;t it ?) and then for small customers here and there, etc etc.\nFosdem 2009, for the first time I stumble upon Dries and I even have a picture with him, I asked him a couple of questions, I was so happy to meet him in person!\nFrom that time I started to attend most of the Drupal events in my area… then in Europe… then in the USA, I went from Munich to Portland, met amazing people and have amazing souvenirs.\nThen my career took a wrong turn and I had to give up Drupal before starting again just before the release of the long-awaited Drupal 7. During 2 years, I did some Drupal sites for customers in my area and also started to customize the sites with custom modules.\nThat wrong turn turns out to be actually one of the best thing that happened in my career. I had the chance to be recruited by a consultancy company and I started to do Drupal not only for my pleasure but for work as well.\nDuring this amazing first Drupal job, I had the chance to meet my first mentor and now friend Pierre Buyle, a real living encyclopedia. He helped me to complete my lack of Drupal knowledge. From there, I started to write modules on my own. First for public companies, then as open-sourced contrib module. At the moment I started to write modules, I found it so enjoyable that I completely gave up site-building, even nowadays, I don\u0026rsquo;t remember when is the last I did some site-building.\n10 years later, I wrote ~30 custom and open-sourced modules and I’m still enjoying my work, my colleagues and all the good things that working with Drupal can bring. I gave conferences in Paris, London, Portland, Brussels\u0026hellip;\nI think working in such a big community and project is a motivation booster and opens a nice new career perspective for a developer.\nHowever, those who know me personally are probably aware that I had to stop travelling these last years for personal reasons. This is why I\u0026rsquo;ve been a bit \u0026ldquo;out-of-sync\u0026rdquo; with Drupal 8 and I still need to catch up many things. So many things have changed\u0026hellip; and I accumulated so many technical debts!\nSo, Drupal 8 came out and I still need to catch up the ongoing train. I succeeded to convert some of my old modules to it and so far so good, there is nothing to say, I like it very much.\nI\u0026rsquo;m now working as a consultant for the European Commission, I’m mostly working on OpenEuropa, which is the new version of NextEuropa, but based on Drupal 8.\nOne year ago, before OpenEuropa even existed, I’ve been given the task to write a new theme that is going to be the base for all current and future Drupal 7 sites at European Commission. I was not so keen at first but I knew that the theme layer in Drupal 7 and 8 (yes, the theme layer in Drupal 8 needs some changes!) has room for improvements.\nSo, I wrote Atomium and Registry on steroids with the help of my colleagues and the community. I wrote also Language Selection Page for Drupal 7 and Drupal 8, and Administration Language Negotiation (as a POC first), now both of them are used on the First Minister site, on the Belgian Monarchy site and now for OpenEuropa at European Commission.\nBesides Drupal and as you can probably see on my blog, I like to learn things related to Sciences and sometimes write PHP packages that helps me understand the theory, like PHPermutations and PHPartition.\nI also like to learn new frameworks, recently I’ve learned Symfony 4 and made an online application: SNCBAlerts (a twitter account and a Telegram bot) this funny application is only hosted on Github and automatically deployed by Heroku as soon as I commit/push something.\nIn the context of work, I wrote pCAS for authenticating users against a CAS server. It can be used by Drupal 7, Drupal 8 and some users are using it internally with their software in Laravel.\nI also like to push the boundaries of Drupal 7 as far as possible. I wrote packages that are used everyday by our continuous integration workflow. I explain those in details in this blogpost.\nI also like to experiment and push the boundaries of my own knowledge in PHP by doing packages like Anonymize or DynamicObjects. I think those libraries are not used by anyone but they helped me to discover and understand a huge amount of new things.\nWhy I applied for the Drupal 7 maintainership? # As you may know now, I applied for being a maintainer of Drupal 7.\nDrupal 7 is still there, even if the trends is decreasing and I’m a bit tired of the lack of responsiveness in the queue and statements like “Drupal 7 is dead, use Drupal 8”.\nEven this statement is technically true, in the real life, there are still a lot of people and companies that are using it.\nSo, my goal is to revive the forgotten Drupal 7 and to be responsive and an active maintainer for it.\nI want to take care of it for the time being and to provide support for it.\nI\u0026rsquo;ll be available on the usual Slack channels or on IRC under the name of @drupol, feel free to have a chat, I speak English, French, Dutch and Italian.\nMy priorities during with this new role are:\nReview and test patches that are waiting, with a priority to the patches that are backported from Drupal 8, Backport new patches, Complete and update the Drupal 7 inline Documentation (PHPDoc, etc etc), Update the code style. I\u0026rsquo;d like to introduce a couple of new things as well:\nUpdating PHP function declarations by updating parameters types, Improve and optimize the theming layer, Make Drupal pass PHPCS, update the coding standard, more to come here very soon\u0026hellip; ","date":"15 July 2018","externalUrl":null,"permalink":"/2018/how-did-i-fall-into-drupal/","section":"Posts","summary":"","title":"How did I fall into Drupal","type":"posts"},{"content":"","date":"15 July 2018","externalUrl":null,"permalink":"/tags/personal/","section":"Tags","summary":"","title":"Personal","type":"tags"},{"content":"","date":"10 July 2018","externalUrl":null,"permalink":"/tags/hooks/","section":"Tags","summary":"","title":"Hooks","type":"tags"},{"content":"","date":"10 July 2018","externalUrl":null,"permalink":"/tags/preprocess/","section":"Tags","summary":"","title":"Preprocess","type":"tags"},{"content":"Last year, I wrote with the help of my colleagues, a new theme for Drupal 7: Atomium.\nThat theme needed to break with the habits from the past and implements new concepts while giving more flexibility to the end-user. As those concepts were pretty new for most of the people using it, I\u0026rsquo;ve been asked to give training to some teams.\nDuring the trainings, I usually explain in 2 hours, almost a year of research and development, so, you guessed it, it\u0026rsquo;s impossible to explain everything from the ground in the details.\nWhen I did the last training, I wanted to do something easier, this is how I came up with a new idea\u0026hellip;\nBackground # Late February 2018, I\u0026rsquo;m preparing a training for a team that is going to use Atomium version 2.7 at the time.\nThe team I was going to train was composed of mostly developers, so I decided to do something a bit more in-depth.\nAtomium is obviously composed of templates, but also of an heavy layer of code that alter the Drupal theme registry, this is usually the part that people never understand, but this is the most important one.\nI had the idea to move out that part of the code into a module and make it available to the whole community without forcing people to use Atomium. This is how Registry on steroids has been created. I first started it alone, then Andreas Hennings joined the team. Thanks to him for his amazing knowledge of PHP and Drupal.\nLet\u0026rsquo;s dive # Before diving into the main subject, let\u0026rsquo;s refresh our memory on how the Drupal theme layer works.\nThe Drupal theme registry is, according to me, one of the most important piece in Drupal. It contains all the theme hooks declared in the system. Each of these theme hooks have a definition that contains crucial information. One of the most important piece of information is the phase callbacks. Before going there, be aware that Drupal 7 is able to render an HTML component in two different ways:\nUsing a template Using a render function Drupal 7 processes the variables that are sent in the templates and/or through a render function in two phases:\nThe preprocess phase The process phase Each of those phase contains a list of callbacks that are executed one after the other. The process phase is not used that much in the community. The Drupal 7 fork, Backdrop decided to get rid of it. Anyway, one of the most important role of the Drupal theme registry is to collect those callbacks automatically and sort them in a particular order, for each theme hook.\nThe order is the following for the preprocess phase:\ntemplate_preprocess() template_preprocess_HOOK() [MODULE]_preprocess() [MODULE]_preprocess_HOOK() [THEME_ENGINE]_preprocess() [THEME_ENGINE]_preprocess_HOOK() [PARENTS_THEME]_preprocess() [PARENTS_THEME]_preprocess_HOOK() [THEME]_preprocess() [THEME]_preprocess_HOOK() And the same for the process phase:\ntemplate_process() template_process_HOOK() [MODULE]_process() [MODULE]_process_HOOK() [THEME_ENGINE]_process() [THEME_ENGINE]_process_HOOK() [PARENTS_THEME]_process() [PARENTS_THEME]_process_HOOK() [THEME]_process() [THEME]_process_HOOK() There is no limit in the callbacks, but there is no trick, the more callbacks you have the slower it will be to process them all.\nIn addition to automatically detect the callbacks, it is possible to manually add, delete or reorder phase callbacks through a specific hook: hook_theme_registry_alter(), see an example in the Display Suite module.\nA hidden feature # Rendering a theme hook in Drupal can be done in different ways:\nUsing the theme() function Using a render array Let\u0026rsquo;s define a theme hook in my custom module, in the file mymodule.module:\nfunction mymodule_theme() { return array( 'marquee' =\u0026gt; array( 'variables' =\u0026gt; array( 'text' =\u0026gt; '', ), 'template' =\u0026gt; 'marquee', ), ); } We\u0026rsquo;ve just defined an HTML component marquee with one variable: text and it will be using a template marquee.tpl.php, the template file must be created in the theme you are using. In my case, I\u0026rsquo;m using the core theme \u0026lsquo;seven\u0026rsquo;. I know that using a core theme is not a good practice, but in this case, it\u0026rsquo;s easier to explain all of this.\nTo render it, we can use the theme() function:\n$html = theme( 'marquee', array( 'text' =\u0026gt; 'The marquee HTML component', ) ); The result is:\n\u0026lt;!-- THEME DEBUG --\u0026gt; \u0026lt;!-- CALL: theme('marquee') --\u0026gt; \u0026lt;!-- BEGIN OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; \u0026lt;marquee\u0026gt;The marquee HTML component\u0026lt;/marquee\u0026gt; \u0026lt;!-- END OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; You may have noticed that I have enabled the theme debug of Drupal in order to show which template is used to render my marquee component.\nNow let\u0026rsquo;s say that we want to create some preprocess callbacks:\nIn the custom module: mymodule_preprocess_marquee(\u0026amp;$variables, $hook) In the theme: seven_preprocess_marquee(\u0026amp;$variables, $hook) Once you flush the cache, Drupal will detect those callbacks and add them in the theme registry, in the proper phase callbacks stack, in this case, the preprocess phase.\nNow, there\u0026rsquo;s a kind of secret feature, not really a secret, but rather an undocumented feature.\nThere is a way to create variants of my component in a very easy way, just by extending the name of the component like this: marquee__variant1\n$html = theme( 'marquee__variant1', array( 'text' =\u0026gt; 'The marquee HTML component - variant 1', ) ); The output of this will be:\n\u0026lt;!-- THEME DEBUG --\u0026gt; \u0026lt;!-- CALL: theme('marquee__variant1') --\u0026gt; \u0026lt;!-- FILE NAME SUGGESTIONS: * marquee--variant1.tpl.php x marquee.tpl.php --\u0026gt; \u0026lt;!-- BEGIN OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; \u0026lt;marquee\u0026gt;The marquee HTML component - variant 1\u0026lt;/marquee\u0026gt; \u0026lt;!-- END OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; You may notice that there is now a list of file name suggestions that has been built by Drupal automatically, based on the hook theme in use.\nLet\u0026rsquo;s update our example with something more explanatory\u0026hellip;\n$hook_theme = implode( '__', array( 'marquee', strtolower(date('F')), strtolower(date('l')), ) ); $html = theme( $hook_theme, array( 'text' =\u0026gt; 'The marquee HTML component', ) ); The result will be:\n\u0026lt;!-- THEME DEBUG --\u0026gt; \u0026lt;!-- CALL: theme('marquee__july__tuesday') --\u0026gt; \u0026lt;!-- FILE NAME SUGGESTIONS: * marquee--july--tuesday.tpl.php * marquee--july.tpl.php x marquee.tpl.php --\u0026gt; \u0026lt;!-- BEGIN OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; \u0026lt;marquee\u0026gt;The marquee HTML component\u0026lt;/marquee\u0026gt; \u0026lt;!-- END OUTPUT from 'themes/seven/marquee.tpl.php' --\u0026gt; You can also create preprocess that goes with it:\nIn the custom module: mymodule_preprocess_marquee__july__tuesday(\u0026amp;$variables, $hook) In the theme: seven_preprocess_marquee__july__tuesday(\u0026amp;$variables, $hook) Drupal includes a very nice and handy template file detection system by splitting the theme name at each __ (double underscores), starting from the right.\nIn this particular case, you could create 2 templates marquee--july--tuesday.tpl.php and another marquee--july.tpl.php, those templates will be automatically picked up by Drupal at the right time.\nEvery Tuesdays in July it will be: marquee--july--tuesday.tpl.php Every other days in July it will be: marquee--july.tpl.php Every other days it will be: marquee.tpl.php Pretty nice isn\u0026rsquo;t it ?\nRegistry on steroids # Let\u0026rsquo;s say that you\u0026rsquo;d like to have preprocess functions applied to specific templates: marquee--july--tuesday.tpl.php and marquee--july.tpl.php.\nNaturally, one may think that we could create a preprocess callback named:\nIn the custom module: mymodule_preprocess_marquee__july(\u0026amp;$variables, $hook) In the theme: seven_preprocess_marquee__july(\u0026amp;$variables, $hook) Unfortunately, Drupal will not execute those preprocess when rendering the marquee--july--tuesday.tpl.php but only when rendering marquee--july.tpl.php.\nThere is no phase callbacks inheritance in Drupal 7.\nAnd this is why Registry on steroids has been created!\nIt has been created to fill that gap and allow people to have an inheritance in the preprocess and process phase callbacks.\nThe issue #2563445 is about this, but I doubt it will be fixed one day unfortunately.\nRegistry on steroids Alter # If you install Registry on steroids, you will notice that it comes with one submodule.\nNow that you\u0026rsquo;re aware of what Registry on steroids is doing, that Alter submodule is basically a module that alter all the render arrays of Drupal. It update and extend the #theme property, based on the element value.\nExample with the region hook theme.\nDrupal doesn\u0026rsquo;t call theme('region', ...) to render a region, it\u0026rsquo;s using a render array, something that roughly look like this:\n$page = array( '#theme_wrappers =\u0026gt; array('html'), 'sidebar' =\u0026gt; array( '#theme_wrappers' =\u0026gt; array('region'), 'block1' =\u0026gt; array(...), 'block2' =\u0026gt; array(...), ), ); ROS Alter, will alter the array and will transform it into:\n$page = array( '#theme_wrappers =\u0026gt; array('html'), 'sidebar' =\u0026gt; array( '#theme_wrappers' =\u0026gt; array('region__sidebar'), 'block1' =\u0026gt; array(...), 'block2' =\u0026gt; array(...), ), ); By doing this simple modification, you could have different templates and preprocess per region:\n\u0026lt;!-- THEME DEBUG --\u0026gt; \u0026lt;!-- CALL: theme('region__sidebar') --\u0026gt; \u0026lt;!-- FILE NAME SUGGESTIONS: * region--sidebar.tpl.php x region.tpl.php --\u0026gt; \u0026lt;!-- BEGIN OUTPUT from 'modules/system/region.tpl.php' --\u0026gt; // REGION CONTENT HERE \u0026lt;!-- END OUTPUT from 'modules/system/region.tpl.php' --\u0026gt; This example is very basic, but ROS Alter does more than that, try it and you will see.\nIt is also possible to alter the list of suggestions with a hook, please read carefully the Registry on steroids Alter API file to understand how to implement and use it.\nFuture of Atomium # Now that Registry on steroids has a much better and upgraded mechanism to alter the Drupal theme registry, Atomium has been updated and it\u0026rsquo;s now much lighter.\nIn less than one week, the new Atomium branch 7.x-3.x will be updated and will be fully working with Registry on steroids.\nIn the end, Atomium will be a simple Drupal theme that uses templates instead of theme functions to render any Drupal element. The advantages of using templates instead of functions:\nYou can enable the theme debug of Drupal core and spot which template is used, anywhere in your page, you cannot do that when using functions to render element. You can extend templates really easily thanks to Registry on steroids Alter. You have a nice inheritance mechanism in the phase callbacks (preprocess/process) thanks to Registry on steroids. Strange things # During the making of Registry on steroids, I noticed weird things in the Drupal theme layer.\nI will explain here one of the weirdest thing, thing that I didn\u0026rsquo;t find why it\u0026rsquo;s done this way. I haven\u0026rsquo;t found a proper explanation yet, do not hesitate to let me know in the comment if you know why.\nAs you know now, there are two ways to render a theme hook:\nWith a template With a function The issue is that when using a function to render your hook theme, Drupal will skip some phase callbacks.\nHere\u0026rsquo;s the ordered list of preprocess callbacks that Drupal will execute if your theme hook is using a template:\ntemplate_preprocess() template_preprocess_HOOK() [MODULES_IF_ANY]_preprocess() [MODULES_IF_ANY]_preprocess_HOOK() [THEME_ENGINE]_preprocess() [THEME_ENGINE]_preprocess_HOOK() [BASE_THEME_IF_ANY]_preprocess() [BASE_THEME_IF_ANY]_preprocess_HOOK() [THEME]_preprocess() [THEME]_preprocess_HOOK() Now, if it\u0026rsquo;s using a function, here\u0026rsquo;s the list:\ntemplate_preprocess() template_preprocess_HOOK() [MODULES_IF_ANY]_preprocess_HOOK() [THEME_ENGINE]_preprocess_HOOK() [BASE_THEME_IF_ANY]_preprocess_HOOK() [THEME]_preprocess_HOOK() As you can see, some preprocess callbacks are skipped. All the callbacks ending with _preprocess basically, except template_preprocess() which is executed manually in the theme() function.\nCrazy isn\u0026rsquo;t it ?\nIn Atomium and Registry on steroids, we had to reproduce that behavior in order to not break existing contrib modules.\n","date":"10 July 2018","externalUrl":null,"permalink":"/2018/registry-on-steroids/","section":"Posts","summary":"","title":"Registry on steroids","type":"posts"},{"content":"","date":"10 July 2018","externalUrl":null,"permalink":"/tags/theme/","section":"Tags","summary":"","title":"Theme","type":"tags"},{"content":"","date":"10 July 2018","externalUrl":null,"permalink":"/tags/theme-registry/","section":"Tags","summary":"","title":"Theme Registry","type":"tags"},{"content":"","date":"19 February 2018","externalUrl":null,"permalink":"/tags/database/","section":"Tags","summary":"","title":"Database","type":"tags"},{"content":"","date":"19 February 2018","externalUrl":null,"permalink":"/tags/graph/","section":"Tags","summary":"","title":"Graph","type":"tags"},{"content":"","date":"19 February 2018","externalUrl":null,"permalink":"/tags/graph-database/","section":"Tags","summary":"","title":"Graph-Database","type":"tags"},{"content":"","date":"19 February 2018","externalUrl":null,"permalink":"/tags/neo4j/","section":"Tags","summary":"","title":"Neo4j","type":"tags"},{"content":"","date":"19 February 2018","externalUrl":null,"permalink":"/tags/numberphile/","section":"Tags","summary":"","title":"Numberphile","type":"tags"},{"content":"Since the last post about Neo4J, I had to work on some project not involving it unfortunately.\nHowever, being a regular user of Numberphile, I came across a specific video footage and I had the idea that we could find the solution to it using Neo4J.\nIn this video, Matt Parker discusses a puzzle problem involving square sums.\nThe video shows how to link a list of numbers from 1 to 15, such that adjacent numbers sums are perfect square numbers.\nI had a vague idea but I wasn\u0026rsquo;t sure, that the solution to this problem could be found using Neo4J.\nSo I started up Neo4J Desktop and started to play with CYPHER queries.\nI first created the list of nodes of type \u0026ldquo;Number\u0026rdquo;:\nFOREACH (n IN range(1,20) | CREATE (:Number {value: n}))\nThis query will create twenty nodes of type \u0026ldquo;Number\u0026rdquo; having a specific property \u0026ldquo;value\u0026rdquo;. That property value will go from 1 to 20.\nThe list of all the node of type Number Then, we need to find how to arrange those numbers so they match the puzzle explained in the Numberphile\u0026rsquo;s video.\nIn order to create the good relationships between those numbers, we have to transform the matching property \u0026ldquo;the sum of adjacent numbers is a perfect square number\u0026rdquo; into the Cypher Query Language.\nMATCH (n1:Number), (n2:Number)\nWe match two nodes, they can be the same or not, for now we don\u0026rsquo;t care.\nWHERE sqrt(n1.value + n2.value) % 1 = 0\nWhere the rest of the square root of the sum of the property value of those nodes is zero. Indeed, the rest of the division by 1 of the square root of a square number will always be an integer.\nAND id(n1) \u0026gt; id(n2)\nWhere those nodes are different from each other.\nMERGE (n2)-[:LinkedTo]-(n1)\nThen create the relationship \u0026ldquo;LinkedTo\u0026rdquo; if it doesn\u0026rsquo;t exist yet.\nRETURN *\nAnd return all the objects.\nThe list of all the node of type Number linked from 1 to 20 You can now clearly see if you sum up every every pair of adjacent nodes, it\u0026rsquo;s a perfect square number.\nIf you want to retry the experience with bigger figures, delete everything:\nMATCH (n) DETACH DELETE n\nAnd restart using numbers like\u0026hellip; 50!\nThe list of all the node of type Number linked from 1 to 50 It works fine, however I guess you\u0026rsquo;ve seen the issue\u0026hellip; Some nodes have more than two relationships.\nDo you think you could find the right Cypher query to prevent this ?\nIf yes, don\u0026rsquo;t hesitate to post it in the comments !\n","date":"19 February 2018","externalUrl":null,"permalink":"/2018/numberphile-and-neo4j-numbers-experimentations/","section":"Posts","summary":"","title":"Numberphile and Neo4J numbers experimentations","type":"posts"},{"content":"","date":"1 January 2018","externalUrl":null,"permalink":"/tags/cypher/","section":"Tags","summary":"","title":"Cypher","type":"tags"},{"content":"","date":"1 January 2018","externalUrl":null,"permalink":"/tags/dev/","section":"Tags","summary":"","title":"Dev","type":"tags"},{"content":"2018 is here. Happy new year !\n2017 was a productive year in every direction. Workwise , it was a blast. I joined an amazing team and we are doing very nice things all together.\nBut my brain is constantly sparkling and I\u0026rsquo;ve got plenty of new ideas. During the last months, I\u0026rsquo;ve explored new universes. Symfony, NodeJS, Opendata, Telegram bot API, Twitter API\u0026hellip; I\u0026rsquo;ve learned so much things in a so short time, it\u0026rsquo;s crazy how much behind we can be if we do not have side projects to let our creativity express itself. It\u0026rsquo;s now my job to try to push these new technologies and new tools at work, that is the most complicated part.\nLately, I\u0026rsquo;ve been playing a lot with Opendata, NodeJS, Wikidata, iRail\u0026hellip; As you may know, iRail provides Belgian railway (open)data and I was looking for a way to get trains stations and their lines. I ended up doing irail-api a NodeJS/NPM package and a custom tool in NodeJS based on it, using Leaflet and Websockets. That tool helped me to complete the Belgium station data on Wikidata. There are more than 600 stations, and I completed them last week. All the details of this in the Github issue.\nThanks to all of this, it\u0026rsquo;s now possible to retrieve, for each Belgian station, its associated train lines and its adjacent stations.\nIt\u0026rsquo;s a lot of data, a lot of contributions and there is no way to visualize properly the result, yet.\nIn order to test if I could use those data in a practical way, I built a small script that returns the list of stations that I would pass if I want to go from Station A to Station B. A BFS algorithm is used to find the path in between the two stations.\nThen a reply of this tweet from Christophe \u0026ldquo;ikwattro\u0026rdquo; Willemsen, a twitter friend of mine, lit the spark.\nyou should try @neo4j m8!\n\u0026mdash; Christophe Willemsen (@ikwattro) December 30, 2017 To be honest, I was curious because of its tweets and dedication to Neo4J since I know him but I never had the opportunity or the need to use it\u0026hellip; until now.\nNeo4J is a graph database management system developed by Neo4j, Inc. Described by its developers as an ACID-compliant transactional database with native graph storage and processing, Neo4j is the most popular graph database according to DB-Engines ranking. It is available in a GPL3-licensed open-source \u0026ldquo;community edition\u0026rdquo; Neo4j is implemented in Java and accessible from software written in other languages using the Cypher Query Language through a transactional HTTP endpoint, or through the binary \u0026ldquo;bolt\u0026rdquo; protocol. (source)\nGraphs, or Graphs theory, far from being a recent data handling development is actually nearly 300 years old and can be traced to Leonhard Euler, a Swiss mathematician. Euler was looking to solve an old riddle known as the Seven Bridges of Königsberg. Set on the Pregel River, the city of Königsberg included two large islands connected to each other and the mainland by seven bridges. The challenge was to map a route through the city that would cross each bridge only once while ending at the starting point. Euler realized that by reducing the problem to its basics, eliminating all features except landmasses and the bridges connecting them, he could develop a mathematical structure that proved the riddle impossible.\nToday’s graphs are based entirely from Euler’s design – with land masses now referred to as a \u0026ldquo;node\u0026rdquo; (or \u0026ldquo;vertex\u0026rdquo;), while the bridges are the \u0026ldquo;links\u0026rdquo; (also known as \u0026ldquo;relationships\u0026rdquo; or \u0026ldquo;edges\u0026rdquo;). One thing that’s great about graph databases however is that their end users don’t need to know anything about graph theory in order to experience immediate practical benefits. (source)\nSo, I downloaded the Neo4J community edition and I played with it. I did the tutorial that are provided by the installer and I was impressed, that the least I can say.\nHow did I never tried this before ?!\nTo learn it, I wanted to use the Belgian railway data, so, the first thing I did was to find a way to build and import all the data from iRail and Wikidata into Neo4J. The file I\u0026rsquo;m using is available on Gist, you can play with it if you want.\nThen, once this file has been imported in Neo4J, I was able to query the database using CQL, the Cypher query language, a query language invented by and for Neo4J.\nHereunder you will find the description of the queries, the CQL query and the result in Neo4J.\nOh and by the way, Big thanks to Christophe \u0026ldquo;ikwattro\u0026rdquo; Willemsen for its help for unblocking me with some queries!\nQueries # To get the list of all the stations and lines in the database:\nMATCH p=()--\u0026gt;() RETURN p The list of all the stations and lines in the database To get the list of stations attached to \u0026lsquo;Line 96\u0026rsquo; or \u0026lsquo;Line 97\u0026rsquo;:\nMATCH (station:Station)-[relationship:PART_OF]-\u0026gt;(line:Line) WHERE line.name IN [\u0026#39;Line 96 (Infrabel)\u0026#39;, \u0026#39;Line 97 (Infrabel)\u0026#39;] RETURN station, relationship, line The list of stations attached to Line 96 or Line 97 To get the shortest path \u0026ldquo;in nodes\u0026rdquo; from Quaregnon to Brussels-South:\nMATCH (s1:Station {name: \u0026#39;Quaregnon\u0026#39;}), (s2:Station {name: \u0026#39;Brussels-South/Brussels-Midi\u0026#39;}), path = allShortestPaths((s1)-[:ADJACENT_OF*]-(s2)) WITH path, nodes(path) AS stations MATCH (s1:Station)-[p1:PART_OF]-(l:Line)-[p2:PART_OF]-(s2:Station) WHERE s1 IN stations AND s2 IN stations RETURN stations, relationships(path), p1, p2, l The shortest path in nodes from Quaregnon to Brussels-South In Neo4J, the edges(or relationships) in between nodes are first class citizen and may have properties just like nodes. In this case, the relationship ADJACENT_OF has a property distance. The distance in between each station is displayed as relationship label and you may notice that the distance between Braine-Le-Comte and Halle is not the shortest. The is a path passing through more station but shorter.\n\u0026ldquo;let\u0026rsquo;s use a graph \u0026ldquo;to see\u0026rdquo; that\u0026hellip; that\u0026rsquo;s a purpose of a graph databases anyway !\nPaths between Braine-le-Comte and Halle On this graph, we can clearly notice that there is a better solution, a shorter path in terms of distance, than what Neo4J is giving me. It\u0026rsquo;s not a mistake actually.\nThe function allShortestPaths() will always return paths with the least nodes. But in our case, we have to take in account the distance property attached in relationships and find the path with the smallest distance, no matter how much nodes there are in the path.\nThe solution is to use another algorithm: Dijkstra.\nTo get the shortest path \u0026ldquo;in distance\u0026rdquo; from Quaregnon to Brussels-South:\nMATCH (from:Station{name:\u0026#39;Quaregnon\u0026#39;}), (to:Station{name:\u0026#39;Brussels-South/Brussels-Midi\u0026#39;}) CALL apoc.algo.dijkstra(from, to, \u0026#39;ADJACENT_OF\u0026#39;, \u0026#39;distance\u0026#39;) YIELD path AS path, weight AS weight WITH path, nodes(path) AS stations MATCH (s1:Station)-[p1:PART_OF]-(l:Line)-[p2:PART_OF]-(s2:Station) WHERE s1 IN stations AND s2 IN stations RETURN stations, relationships(path), p1, p2, l The shortest path in distance from Quaregnon to Brussels-South To get the list of all stations with only one adjacent station:\nMATCH (:Station)-[relationships:ADJACENT_OF]-(station:Station) WITH station, count(relationships) as rels WHERE rels = 1 RETURN station The list of all stations with only one adjacent station Conclusion # In addition to being beautiful, these graphs make it possible to interpret an amount of data that generally are hard to grasp while they are just tables and rows in a database.\nIf I wanted to do that with a regular relational database, it would have been impossible to have such a result without a huge amount of data preprocessing.\nImagine what we could do if we had an ultra complete Belgian railway dataset\u0026hellip; we could probably do things in a better way\u0026hellip;\nAnd if you start to think deeper about it, you will see that graphs are everywhere in your everyday life. They are a vital part of our online lives, powering everything from social media sites to the retail recommendations on e-shops, online dating sites\u0026hellip; and so much more.\nI really think that I will start to use it more and more,\nI guess overall interest in the graphs will continue to grow. The real-time nature of a graph database makes it an excellent platform for unlocking business value from data relationships, which simply can’t be carried out on traditional SQL or most NoSQL databases. The uses and applications for graph databases seem endless, and it’s exciting to consider what innovations they will continue to power as the world unlocks the value of data relationships. (source)\n","date":"1 January 2018","externalUrl":null,"permalink":"/2018/discovering-a-new-database-neo4j/","section":"Posts","summary":"","title":"Discovering a new database: Neo4J","type":"posts"},{"content":"","date":"1 January 2018","externalUrl":null,"permalink":"/tags/opendata/","section":"Tags","summary":"","title":"Opendata","type":"tags"},{"content":"","date":"1 January 2018","externalUrl":null,"permalink":"/tags/railway/","section":"Tags","summary":"","title":"Railway","type":"tags"},{"content":"","date":"1 January 2018","externalUrl":null,"permalink":"/tags/wikidata/","section":"Tags","summary":"","title":"Wikidata","type":"tags"},{"content":"","date":"17 December 2017","externalUrl":null,"permalink":"/tags/api/","section":"Tags","summary":"","title":"Api","type":"tags"},{"content":"","date":"17 December 2017","externalUrl":null,"permalink":"/tags/nodejs/","section":"Tags","summary":"","title":"Nodejs","type":"tags"},{"content":"","date":"17 December 2017","externalUrl":null,"permalink":"/tags/open-data/","section":"Tags","summary":"","title":"Open-Data","type":"tags"},{"content":"Younger, working in Brussels was not an option.\nI never had a deep love for that city, never had a deep love of traffic jam\u0026hellip; and never had love for public transportation like trains.\nDespite the fact that I love driving, I can\u0026rsquo;t bear staying in the car, stucked in the traffic jam, praying for the people in front of you to pass the next gear.\nTo be honest, I really love cars and especially driving techniques, but I hate so much traffic jam and I love so much my bicycle that I would prefer a World without car at all, and I\u0026rsquo;m dead serious when I write that.\nAnyway, this post is not about personal feelings and as promised in my previous article, it will not be about Drupal at all either.\nWhy # It\u0026rsquo;s been years that I take the train, twice per day, to go to work. From door to door, it takes me two hours, tip top. On average, four hours per day, lost in transportation.\n75% of that time is in the train\u0026hellip; it shouldn\u0026rsquo;t be so long, but the railway line 96 is subject to many delays. It\u0026rsquo;s the most problematic line in Belgium.\nThe operator SNCB and the transporation minister are aware of the issues\u0026hellip; But no actions seems to be taken since years.\nSimple customers that we are are unable to get our voices heard even after many online petitions. It looks like people from this part of the Belgium are forgotten and instead of being \u0026ldquo;right on track\u0026rdquo; (to quote the Infrabel moto) are sadly, \u0026ldquo;left on track\u0026rdquo; (Infrabel, please note this down for your next moto.).\nWhat # I usually work in the train, at least, when it\u0026rsquo;s possible.\nThese last days and once again, my patience was on the verge of vanishing and I needed to do something to show people how bad the train service in Belgium is.\nSo I started to think how I could provide people a service that could send notifications when there are trains delays. Of course, this would not solve the root issue, but maybe by showing how bad the service is, they will do something, who knows.\nWhere # Before thinking concretely to what I would do, I have to check if trains data are available.\nI was aware that SNCB was promoting their data openness since not so long ago\u0026hellip; but as usual they were doing it wrong, you have to register to get access to these.\niRail, a private application created by Pieter Colpaert is using those data and has it\u0026rsquo;s own API. There is no need to register, everything is open as in \u0026ldquo;Opendata\u0026rdquo;, and that\u0026rsquo;s how it should be.\nI invite to read the documentation of the iRail API and get yourself an idea with what you can do with those data, Pieter and it\u0026rsquo;s team did an amazing job, I particularly love the Hyperrail Android application.\nHow # I started to play with the API and it\u0026rsquo;s working super fine. I made an analysis on what are people expecting from these data, how to make the numbers, actually speak!\nThe goal is to be notified when there is a delay on my train. But my own train might not be someone else\u0026rsquo;s train\u0026hellip; so I needed to make a system that could work for everyone.\nWhat we need is a system that can be customized per user.\nFirst things first. # The iRail API provide information about stations, vehicle, departures. It doesn\u0026rsquo;t provides the delayed trains per se. Fortunately, in the returned data array of a departure, there is an member delay holding the delay in seconds.\nBut what is a delay ? What defines a train delay ? How to detect a train delay ? Given a time and date, until when should we consider a delay, a delay ? What is the validity lifespan of a delay ?\nZero if the train departure is on time, greater than zero if it\u0026rsquo;s delayed. Easy peasy lemon squeezy.\nTrains departures are associated to a station, so we need to do things in a particular order:\n1: Find every stations and iterate on each of them, 2: Find every departures of every station and iterate on each of them, 3: Filter out trains that are on time. Then, we need to sort the resulting dataset and do things with them.\nAfter some work, fighting a bit with Symfony 4 (Flex), and polishing the code\u0026hellip; I had a nice core that could send delays and alerts as Symfony events. The core system, the one that detects the delays and send the events is closed source for now, it still needs some time and love before thinking about opensourcing it. However, the Twitter and Telegram gateways are available on Github since the beginning.\nGateways # Gateways are plain Symfony bundles and they can be added or removed from the core app within a few seconds. I created two of them for sending messages to some platforms.\nCurrently, two gateways are working and Open Source.\nMore gateways are in the pipe for sure, but I first need to polish the core codebase before extending it further.\nTwitter # Twitter has been the first gateway I did. I\u0026rsquo;ve learned to use the Twitter API through the excellent Twitter library from Abraham Williams.\nA twitter bot has been created and I encountered the first issue: find it a name!\nI called it SNCB Alerts and after a few minutes it was online, Twitter already decided to shut it down. Why ? I reached the limit rate of the account and they were thinking I was spamming\u0026hellip; but I wasn\u0026rsquo;t!\nI re-enabled it and updated the delays threshold to 600 seconds (10 minutes), so, hopefully Twitter will not be spammed by smaller delays. It\u0026rsquo;s now up since the 6 of December and it posted 10000 tweets, almost no downtime is to be reported.\nTo be honest, I was a bit frustrated with this solution. I don\u0026rsquo;t like the fact that I had to select only some delays but I had no other choice on this platform. There are so many of them that they can\u0026rsquo;t be published on Twitter without having a bigger threshold.\nTelegram # Telegram is an instant messaging application available on mobile phones and has a very nice desktop interface.\nJust like many other platforms, it\u0026rsquo;s possible to create bots and its API is very nice and well documented.\nI started to use a Telegram API and then, after a while, switched to irazasyed/telegram-bot-sdk from Syed Irfaq which is actually much more advanced and mature. The first thing I did with the API was to create a public channel and have the bot shouting everything in there.\nI quickly noticed that there were so much information that it was impossible to get noticed properly, even using the search feature in Telegram. I had to find something else. I began to think about a real interactive bot that users could query in order to get customized alerts.\nSo, I wrote custom commands for the SNCB Alerts Telegram bot, and then, made it available to the public. Users are able to manage their own alerts within the chat interface, and are notified when an alert matches their chosen keywords.\nDeployments # The application is up since the 6th of December and almost no downtime has been reported.\nIt\u0026rsquo;s very hard to develop new features on it. Indeed, I can\u0026rsquo;t test properly the app because it\u0026rsquo;s relies on external services like Twitter and Telegram and thus, adding new features might sometimes break the app during a few minutes.\nAs soon as an update of the app is pushed on the repository, the deployment system behind it rebuild the application from the ground using composer. Once the app is built, and if there were no errors during building, the app is deployed seamlessly, without interruption.\nThe system behind all of this is Heroku, most of the features I\u0026rsquo;m using are free. It\u0026rsquo;s a very good and reliable system, however, I found it a bit expensive if one day I need more resources. We\u0026rsquo;ll see.\nGoodies # Being the developer the application, I\u0026rsquo;m also an active user of it. I noticed that it would be good to subscribe to notifications related to a particular train line. Unfortunately, that information is not provided by the train company neither by iRail, we have to find them by ourselves.\nAfter some discussion with Pieter from iRail, we decided to extensively use Wikidata.\nWikidata is a free and open knowledge base that can be read and edited by both humans and machines. It acts as central storage for the structured data of its Wikimedia sister projects including Wikipedia, Wikivoyage, Wikisource, and others. The content of Wikidata is available under a free license, exported using standard formats, and can be interlinked to other open data sets on the linked data web.\nAs every Belgium train station are in Wikipedia and thus Wikidata, I started to add line information to these stations.\nIn a couple of days, thousands of edits has been made and the result is amazing. It is now possible to query the Wikidata database and get the list of stations linked to iRail with line information.\nTo match a train from station X to station Y to a line, I\u0026rsquo;m using the following procedure:\n1: Find train lines associated to station X, 2: Find train lines associated to station Y, 3: Find the lines in common. Even if the iRail team tweeted about it, thanking me for what I\u0026rsquo;ve done, the work is not over yet. There are less or more 600 stations in Belgium and we still need to link some data to have a full coverage.\nWhat\u0026rsquo;s next # I first would like to continue my work on Wikidata, then working on improving overall application performance, reducing the memory footprint and invest some time in NodeJS.\nIndeed, I published my first package on npmjs.com. It\u0026rsquo;s a very basic NodeJS module made to query the iRail API. It\u0026rsquo;s using Javascript promises, something completely new to me, so new, that I\u0026rsquo;m still unable to fully grasp the advantages of it yet, I guess it\u0026rsquo;s just a matter of time before I\u0026rsquo;m starting to use them everywhere.\nA couple of surprises are on their way using that technology, more info in the next blog post!\n","date":"17 December 2017","externalUrl":null,"permalink":"/2017/playing-with-trains-opendata-symfony-and-nodejs/","section":"Posts","summary":"","title":"Playing with trains, Opendata, Symfony and NodeJS","type":"posts"},{"content":"","date":"17 December 2017","externalUrl":null,"permalink":"/tags/telegram/","section":"Tags","summary":"","title":"Telegram","type":"tags"},{"content":"","date":"17 December 2017","externalUrl":null,"permalink":"/tags/twitter/","section":"Tags","summary":"","title":"Twitter","type":"tags"},{"content":"","date":"10 November 2017","externalUrl":null,"permalink":"/tags/cas/","section":"Tags","summary":"","title":"Cas","type":"tags"},{"content":"","date":"10 November 2017","externalUrl":null,"permalink":"/tags/experiments/","section":"Tags","summary":"","title":"Experiments","type":"tags"},{"content":"","date":"10 November 2017","externalUrl":null,"permalink":"/tags/http-client/","section":"Tags","summary":"","title":"Http-Client","type":"tags"},{"content":"","date":"10 November 2017","externalUrl":null,"permalink":"/tags/psr/","section":"Tags","summary":"","title":"Psr","type":"tags"},{"content":"As I wrote in my previous post, the last months were pretty busy.\nAnd it\u0026rsquo;s still the case.\nI\u0026rsquo;ve been assigned new tasks at work and if you know me a bit now, you probably know that I like to do things properly.\nSo, the task I\u0026rsquo;ve been asked to do is to analyze and rewrite the custom authentication system of NextEuropa, the Drupal 7 platform used at the European Commission.\nIntroduction # To give a bit of context about NextEuropa, there are around 175 websites using it. One team to develop \u0026ldquo;the Core team\u0026rdquo; which I\u0026rsquo;m part of and one team to maintain it \u0026ldquo;the Core support team\u0026rdquo;.\n9 developers, from 29 to 44, we are aged on average around 38.2 years old.\nSome of us have different backgrounds, not necessarily in IT, not necessarily in PHP. Some of us have from 1 month to 12 years of \u0026ldquo;Drupal-ing\u0026rdquo; behind.\nWe can say that we are a bunch of passionate developers and even if sometimes we do not agree, we are in overall a very good and charming team.\nUnfortunately, even if sometimes coding and finding the best way to reach the goal and meet all the expectations is hard, dealing with all points of view and habits of the colleagues can be even more complex, but this is why work is called \u0026lsquo;work\u0026rsquo; I guess.\nAnd a part of the a developer\u0026rsquo;s job is to let others know why a decision in the development of a project has been made, but it\u0026rsquo;s also his job to explain why it wasn\u0026rsquo;t.\nIn the following projects, I mostly worked alone, and sometimes it was a bit hard to introduce new development concepts to my colleagues.\nBut it\u0026rsquo;s part of my job to let them know that we should use this tool because of this or that.\nAnyway, for those who might say: \u0026ldquo;Again a Drupal 7 post\u0026rdquo;, \u0026ldquo;Drupal 7 is dead, wake up!\u0026rdquo;, I would reply that I\u0026rsquo;m aware of it since a long time ago, so please, bear with me.\nThe thing is that we are still working with D7 at work\u0026hellip; and I have to accomodate. Nevertheless, I promise to my readers that the next blog post will not be about Drupal 7, nor Drupal 8.\nTechnical part # So recently, I\u0026rsquo;ve started to check out how was working the custom authentication in NextEuropa.\nBasically, the authentication is relying on a CAS server that authenticate the user credentials.\nNowadays, CAS authentication is not that widespread on the net, OpenID and oAuth has taken most of the seats.\nTechnically, it\u0026rsquo;s not hard to understand how it works, I will try to explain it.\nWhen a user wants to authenticate on NextEuropa, the user is redirected to the CAS server called ECAS, it\u0026rsquo;s a customized version of a CAS server, renammed ECAS. The redirection URL must contain a \u0026ldquo;service url\u0026rdquo; parameter. It will be needed to redirect the user to when the authentication is done.\nSo, when the user arrives on ECAS, he has to provide a valid username and password.\nWhen authenticated, ECAS redirect the user to the \u0026ldquo;service url\u0026rdquo; sent as parameter, but with a unique specific token in a GET parameter: ticket.\nAt this point the user is authenticated on ECAS, but not on the site he comes from.\nIn order to do that, the site will need to send an internal request(server side) to ECAS with the ticket received as a GET parameter.\nThis is a one-time token ticket and it can only be used once to authenticate the user.\nIf the internal request to authenticate the user has been successful, you can grant access to the user, he\u0026rsquo;s authenticated on both sides.\nSo, basically that\u0026rsquo;s it, it\u0026rsquo;s one of the way to use the CAS protocol. There are other ways, but I won\u0026rsquo;t go further here, maybe in another blog post.\nDevelopment # At the European Commission, when we start to develop something new, we like it to be reliable, maintainable, sustainable and testable.\nThat\u0026rsquo;s a lot, but with the latest years progress in PHP and all those libraries around, it\u0026rsquo;s fully possible.\nPrior doing this, we also like to check on the net if something similar could do the job properly.\nUnfortunately, in our case there were no library that could help us doing such a task.\nWe took the decision to write our own authentication library, that\u0026rsquo;s how EuLogin was born.\nI started to write EuLogin as a PoC to test if everything was ok.\nUnfortunately, I was unable to test the library properly because ECAS, for security reason, can only authenticate specific European Commission websites AND any site on http://127.0.0.1/, all the others are blocked for obvious security reasons.\nThe challenges around this project are:\nFind a way to test the library quickly without the need to setup a particular development environment. Let my colleagues hook into the development quickly, but just cloning the repository and without creating specific webserver configuration. Make it fully \u0026ldquo;testable\u0026rdquo; on Travis, at each commit. \u0026ldquo;But how to test a library that\u0026rsquo;s relying on an external service ???\u0026rdquo;\nThe idea is the following.\nHow about including a client app \u0026lsquo;Symfony demo client app\u0026rsquo; that can be started with the very useful internal web server of PHP.\nBy default, the url of the app would be http://127.0.0.1:8000/, this way I can test the ECAS authentication without updating our own personal dev environments.\nI can setup a very basic client application(or site) and I can authenticate on ECAS in just one minute.\nWhere pCAS is coming from # Days after days, I improved the library, then improved the demo client app, then reiterate that process many times\u0026hellip; until\u0026hellip;\nUntil I found out that the every components of library was so abstracted that it could fit for authenticate to any CAS server, not only to ECAS from the European Commission, by just updating the YAML config file.\nThis is how the EuLogin got renamed in pCAS.\nEmotional lift # Frustrated of not being able to test the library without an Internet connection, I started to think about a way to work on this, without being connected.\nJust like I did the client app \u0026lsquo;Symfony demo client app\u0026rsquo;, I did a server app \u0026lsquo;Symfony demo server app\u0026rsquo;.\nThe server app has to be started just like the client app.\nBy doing this, an Internet connection is no more needed to test the library and write proper tests.\nOf course, the server has to \u0026ldquo;mock\u0026rdquo; the behavior of a real CAS server and it was not hard to implement.\nDrupal integration # As NextEuropa is in Drupal 7, I needed to provide a proof of concept that pCAS could be integrated with it.\nI wrote a very simple Drupal 7 module\u0026hellip; and I was surprised that I had issue.\nSession # Drupal 7 is relying on the database to store the user session. pCAS is relying on files, the default.\nAs pCAS\u0026rsquo;s session component can be customized, I wrote a Symfony\u0026rsquo;s session service that uses the Drupal API for handling sessions.\nAnd voila!, you can find drupal7 Session Services(Packagist) and uses the Drupal session in pCAS, set and get session variables and share them with Drupal.\nLogging # Drupal 7 has its own very useful logging system through the watchdog API, but pCAS is using any PSR-3 logging system.\nThis is how I wrote drupal7 PSR3 Watchdog(Packagist).\nThis small bridge library to use Drupal\u0026rsquo;s watchdog as a logger in any PHP library, using PSR-3 standard.\nIt also provides an already made logger for Monolog, the \u0026ldquo;de-facto\u0026rdquo; standard library when it comes to logging in PHP.\nHTTP requests # Drupal 7 uses it\u0026rsquo;s own unique function to do HTTP requests, pCAS is relying on HTTPlug and uses PSR-7 everywhere.\nAt work, countless of discussions arises because of HTTPlug and its use. Understanding the basis of abstraction in developments is a key to understand its real value.\nIn NextEuropa, we\u0026rsquo;re trying \u0026ldquo;to eat our own dog food\u0026rdquo; and for many other reasons we try to avoid including external libraries, just what we need.\nInstead of relying on an external libraries like Guzzle, we could use Drupal\u0026rsquo;s internal function for doing requests\u0026hellip; unfortunately, it\u0026rsquo;s not using PSR-7 and thus, unusable in pCAS (and almost anywhere else by the way).\nSo, the idea was already in my head\u0026hellip; let\u0026rsquo;s build another bridge library that could use the Drupal\u0026rsquo;s internal function for requests and use PSR-7 for its Request and Response messages.\nThis is how I wrote drupal7 HTTP Client(Packagist).\nWhen it\u0026rsquo;s installed in Drupal 7 and if you use HTTPlug, then you do not need any external library to do HTTP requests.\nTo summarize # By doing all of this, I did something I wanted to do since a long time ago: learn the depths of Symfony and see how deep we can go.\nI\u0026rsquo;ve also learned Symfony Flex and I really enjoy it, it\u0026rsquo;s so clear, fast and clean \u0026hellip; I can\u0026rsquo;t think of any other framework to start new projects now.\n\u0026ldquo;green-development\u0026rdquo;, \u0026ldquo;eco-programming\u0026rdquo;; call it whatever you want, is very important and code re-usability is the key for an overall better code quality.\nAt work, reusability is a way to raise the average common knowledge across the team and allows us to focus on improving them step by step instead of going all azimut.\nIt forces us to improve our code and to contribute back to our beloved Open Source community.\n","date":"10 November 2017","externalUrl":null,"permalink":"/2017/reaching-and-overpassing-the-drupal-7-limits/","section":"Posts","summary":"","title":"Reaching and overpassing the Drupal 7 limits","type":"posts"},{"content":"","date":"10 November 2017","externalUrl":null,"permalink":"/tags/session/","section":"Tags","summary":"","title":"Session","type":"tags"},{"content":"","date":"20 September 2017","externalUrl":null,"permalink":"/tags/memoization/","section":"Tags","summary":"","title":"Memoization","type":"tags"},{"content":"","date":"20 September 2017","externalUrl":null,"permalink":"/tags/novelties/","section":"Tags","summary":"","title":"Novelties","type":"tags"},{"content":"These last months were busy.\nI mean, really busy.\nFirst, I have some important personal projects that are ongoing since years now that are about to be concluded. These projects takes less or more 70% of my free time since 2 years.\nThen, real regular work, it\u0026rsquo;s taking me also a lot of time. There is Atomium, the European Commission theme which is taking most of the time.\nAnd these last days were even more full of \u0026ldquo;busy-ness\u0026rdquo;.\nLet me tell you how I get there\u0026hellip; it\u0026rsquo;s a small story\u0026hellip;\nSo, 3 weeks ago, I was looking for performance improvements with Atomium. I wanted to get rid of useless loops by removing all hook_process_hook() calls.\nThese hooks were mainly used to process custom attributes added into some particular templates. As you may know, Drupal 7 provides default variables for attributes: attributes_array, title_attributes_array, content_attributes_array (see the API). This was ok for most of the templates we had, but there are some templates who requires specific attributes per item. Like, an items list, a table with rows and cells, etc etc.\nHow to deal with that ?\nThe first idea was to create a custom array that would contain all the attributes in the hook_preprocess_hook() call, then in the hook_process_hook(), a loop would have converted this array of array into an array of strings, ready to be included in its tag in the template.\nThis solution worked pretty well so far but it\u0026rsquo;s cumbersome and, as far as I saw at work, it confuses people\u0026hellip; but currently there are no other way in Drupal 7.\nThe problem with that is that you have at least 3 loops, one in the hook_preprocess_hook(), one in hook_process_hook() and one in the template, that\u0026rsquo;s a lot.\nAtomium is full of new concepts and I wanted to innovate again.\nThe idea I had was to create a single custom variable that would contains all the attributes. Those attributes would not be an array but an object that would have easy methods to add, remove and replace attributes values.\nSo here I was, coding a very basic Attribute object, with simple methods. I also created an Attribute container implementing \\ArrayAccess so it could automatically spawn attributes at will, just what I was looking for.\nImplementing the Attribute object was fun, but to be honest, it was even better when I started to create the Attributes container.\nWith a custom implementation of the PHP magic methods __get() and __set(), I\u0026rsquo;ve managed to create such a thing:\n$fooAttribute = $attributeContainer[\u0026#39;foo\u0026#39;]; Where the key foo would not exists prior and even would spawn the object $fooAttribute \u0026ldquo;automagically\u0026rdquo;.\nTechnically, I had no major issue while doing that and the only thing I can say is that it\u0026rsquo;s a pity that we cannot \u0026ldquo;autoload\u0026rdquo; classes in a Drupal 7 theme, but that\u0026rsquo;s not the main topic.\nSo, as a complete novelty in Drupal 7, I was introducing classes in Atomium, I also needed some tests. I don\u0026rsquo;t like writing tests. I asked my friend Antonio De Marco from Nuvole to help me in this task and he wrote the tests in Atomium.\nIt\u0026rsquo;s also him that introduced me the amazing peridot-php/Leo assertion library for tests.\nMy next idea was the following, why not use an external light and simple library to handle the generation of those attributes?\nI looked for one, but found none that would fits my needs, so I decided to write one. I wanted a very simple but effective library that could be used by anyone to generate any markup.\nI wrote TagAttributes based on the concepts of peridot-php/Leo and I learned so much things\u0026hellip; crazy !\nWhile doing the library on my own, I wanted to do things in the state of the art, a fully featured library that could generate tags, their attributes and their content without any troubles and of course\u0026hellip; fully tested\u0026hellip; and unfortunately I could not ask to Antonio to write the tests for me ;-)\nSo, I learned to use PHPSpec, and I wrote all the tests of the library using it. I really enjoyed it to, much better than what I was used to know.\nLeo and TagAttributes are using dynamically created methods and properties and some properties are functions, callbacks or better: Closures.\nAll these new programming concepts were bubbling in my head and thanks to TagAttributes, I\u0026rsquo;ve decided to externalize the library to create dynamic methods and properties into its own package: DynamicObjects.\nThere were a couple of libraries around playing with these PHP magic methods, but none were good or complete enough for what I was looking for. DynamicObjects allows you to create and manage objects methods and properties. It comes in two flavors, as a PHP Trait, or as a PHP Class that you can extend.\nDynamicObjects was working pretty fine and I decided to see if its integration in peridot-php/Leo is something easy.\nI requested feedback on the library but got none yet. So, this is \u0026ldquo;on-hold\u0026rdquo; for the moment.\nAs I restarted to take the train to go to work, I had some time ahead to work on this and I added some features. The first feature I added in DynamicObjects is the memoization:\nFrom Wikipedia:\nIn computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.\nI first started to include the functionality \u0026ldquo;as-is\u0026rdquo; in DynamicObjects and then, just like before, I made a package out of it: PHP Memoize.\nOf course there were packages that can do memoization, but not like I wanted to. As the memoization is using a cache to store its data, I wanted it to be able to use a standardized cache system: PSR-16.\nThe second feature I added, was inspired by Macroable, a PHP package that has the same purpose as DynamicObjects and written at the same time by a fellow colleague Freek Van der Herten at Spatie.\nI had the crazy idea to create a package that would convert a regular PHP class into an anonymous one, copying each of its public methods and properties into dynamic ones using DynamicObjects as hard dependency.\nThis is how I created the package: PHP Anonymize, also 100% tested with PHPSpec.\nIn less than 3 weeks, I\u0026rsquo;ve created 4 small different libraries and I don\u0026rsquo;t know what will be the outcome of these. Doing them was very important because it helped me keeping me busy learning new stuff related to my work. I\u0026rsquo;ve learned very nice concepts and I think it might open the doors to a new way of writing libraries, at least, for me. I\u0026rsquo;ve learned Leo, PHPSpec, the PHP Closures and its bindings, and so much more\u0026hellip;\nThis is exactly what I love in my work. There\u0026rsquo;s so much things to discover, to learn, to build, to share, to show, to rebuild, to use\u0026hellip; Some people are singing, dancing, painting, acting\u0026hellip; but for me, learning new work-related stuff and writing opensource softwares, are a way to express my creativity\u0026hellip; and as long as this will exists, I will never get fed up of what I do.\nSo\u0026hellip; what\u0026rsquo;s next ?\nWe\u0026rsquo;ll see\u0026hellip;\n","date":"20 September 2017","externalUrl":null,"permalink":"/2017/php-experimentations/","section":"Posts","summary":"","title":"PHP experimentations","type":"posts"},{"content":"","date":"20 September 2017","externalUrl":null,"permalink":"/tags/testing/","section":"Tags","summary":"","title":"Testing","type":"tags"},{"content":"The Drupal 7 theme layer has, and sometimes still is, been a nightmare to understand for me. In my modules, I\u0026rsquo;ve always tried to avoid this dark corner that are the theme hooks and inspire my code from what I see somewhere else.\nUntil now, it helped me so far pretty well, that\u0026rsquo;s the beauty of the Open Source.\nBut recently I\u0026rsquo;ve been given the task to build a new base theme for Drupal 7 and thus, to have a deep understanding on how the theme layer is working.\nBackground # Working at [European Commission](https://www.drupal.org/European Commission) with a team of fellow Drupalers, I\u0026rsquo;m in charge of designing a new Drupal 7 base theme.\nThe requirements were simple:\nprovide a very clean markup,\nbreak up with the old theme,\nbreak up with Bootstrap CSS framework,\nmust be very simple to extend using atomic design principles.\nThat was quite a challenge for me to imagine and write such a thing. I\u0026rsquo;m not a frontend guy\u0026hellip; and I don\u0026rsquo;t like so much designing user interfaces. I really like searching for algorithms, writing them, optimizing them\u0026hellip; but theming stuff was not my cup of tea. However, I knew that the theme layer in Drupal 7 is a mess and I decided that I should do something to help, and as I said: \u0026ldquo;I like to improve things\u0026rdquo;.\nHistory # Atomium name proposals So, I started to study how the most commonly themes were written and how they were designed. Zen, Mothership, Omega, Adaptive and Bootstrap were reviewed carefully during this process. I started to work on this the first week of February 2017, and the first commit was on the 28th of that same month.\nAtomium needed to break up with old theme\u0026rsquo;s habits. Prior explaining how we dealt with them, let\u0026rsquo;s explain what are the issues with the current theme layer.\nOh and by the way, the name \u0026ldquo;Atomium\u0026rdquo; has been chosen among a list that we\u0026rsquo;ve made at work with the colleagues, the photo on the left illustrate all the candidate names that we\u0026rsquo;ve come up with before choosing Atomium, suggested by a colleague. It fits perfectly for the project, it\u0026rsquo;s short, not too difficult to write in any language and\u0026hellip; it comes from Belgium :-)\nWhy # On of the complexity in the theme layer lies in the fact that Drupal allows you to define HTML components in a template file or in a function. And defining them is sometimes complex. The rendering workflow is something tricky and not so straightforward.\nDrupal 7 using standard install and Stark theme defines 152 HTML elements or commonly named \u0026lsquo;hook themes\u0026rsquo;. 132 of them are made out of PHP functions. The 20 leftovers are from templates. According to me, mixing templates and functions for rendering HTML is a bit messy. Each of these two methods has its own pros and cons.\nHTML should resides in template files and should be easy to extend.\nIn Drupal 7, you can extend, preprocess and process a template, but you can not extend a theme function, only overwrite it and preprocess, process it.\nSo, I tried to see how I could fix that in Atomium, how I could rewrite the \u0026ldquo;theme functions\u0026rdquo; into simple templates. Some of you might think \u0026ldquo;Why the hell this guy is looking after that ? Does this guy likes to suffer ?\u0026rdquo;. I just like to fix things properly :-)\nAlso because since Drupal 7.33, you can debug templates and see which one is used when rendering HTML components, and their corresponding templates suggestions, just by looking at the HTML source code\u0026hellip; This option is also configurable within the Atomium settings, see the screenshot below.\nBut prior fixing that, I needed to find a proper folders and files structure.\nStructure # Most of the themes are composed of template files, assets, preprocess and process functions. There is no conventions on how to order and sort these. There is no hierarchy, no structure, nothing.\nMost of the themes I reviewed are using the file template.php as a junk room where everything is dumped in there.\nThis has to change.\nBefore doing anything, the first thing to do was to implement a clean structure.\nWith the requirements in mind, I\u0026rsquo;ve managed to build the folder and files structure so it can be easily extended throughout a children theme.\nThen, once that was settled, I started to convert most of Drupal core theme functions into templates\u0026hellip; and that helped me to understand and improve even further the theme.\nAfter a couple of meetings with the colleagues, we\u0026rsquo;ve adjusted the folders and file naming conventions\u0026hellip; and we had something great.\nIn-depth mechanisms # The registry alteration workflow is based on Bootstrap theme with small modifications, clean HTML from Mothership and other themes I reviewed.\nA lot of customizations were done for each \u0026lsquo;hook themes\u0026rsquo;, now called \u0026lsquo;components\u0026rsquo;.\nIn order to test if Atomium was behaving correctly, my fellow italian colleague Antonio De Marco implemented a nifty way to test the rendering layer by overriding the global \u0026ldquo;theme_engine\u0026rdquo; variable and have a total control on what Drupal is rendering, just for testing purposes.\nThen, to help newcomers to dive into the theme, I\u0026rsquo;ve created three subthemes, one based on Bootstrap 4, one on Foundation, and the last one is a copy of Bartik but using the Atomium mechanisms.\nFeatures # As a base theme, Atomium will be empowering all European Commission websites built with Drupal. The final theme will be EC Europa Theme.\nPreprocessing and processing functions # Atomium has special features that makes it unique in the Drupal ecosystem.\nI think, but I can be wrong, that this is the only theme that provides such a working cascade of preprocess and process functions based on the theme hooks suggestions.\nIt means that if you call the hook theme \u0026lsquo;link\u0026rsquo; with some custom suggestions like:\n$mylink = theme('link__suggestion1__suggestion2', array(...));\nThe default behavior of Drupal is to only run the HOOK_preprocess_link() then stop.\nWith Atomium, the preprocess and process mechanisms of Drupal 7 will run the following functions, in order:\nHOOK_preprocess_link(\u0026amp;$variables, $hook)\nHOOK_preprocess_link__suggestion1(\u0026amp;$variables, $hook)\nHOOK_preprocess_link__suggestion1__suggestion2(\u0026amp;$variables, $hook)\nThis way, you may create functions that will be applied to a subgroup of theme hooks, just by giving them a relevant name.\nApparently there has been some updates in Drupal 8 regarding this and the issue needs to be backported to Drupal 7\u0026hellip; Let\u0026rsquo;s hope I can find some time to propose a patch for it so I could remove that logic from Atomium and all the themes could use this amazing feature.\nAttributes handling # Another feature added in Atomium is the automatic processing of attributes based on a simple variable name.\nLet\u0026rsquo;s say that you create in your preprocess a variable named: \u0026lsquo;something_attributes_array\u0026rsquo;.\nDuring the main Atomium preprocess function, there is a mechanism that will detect those variables based on the pattern \u0026lsquo;*_attributes_array\u0026rsquo; and then will process them through the \u0026lsquo;atomium_drupal_attributes()\u0026rsquo; function. Then, in the template, the variable \u0026lsquo;something_attributes\u0026rsquo; will be available as a string containing the attributes.\nThe function \u0026lsquo;atomium_drupal_attributes()\u0026rsquo; is a extended version of \u0026lsquo;drupal_attributes()\u0026rsquo;. By default, it will trim() and check_plain() the values, but also, if the key of an attribute is numeric, it will only display its value. Ex: 0 =\u0026gt; \u0026quot;data-closable\u0026quot; will be displayed: data-closable.\nThe other small difference with the original function is that the values in the \u0026lsquo;class\u0026rsquo; key will be sorted alphabetically.\nAssets # The Atomium theme settings In Atomium, inline javascript is stripped out of the HTML output and moved into a temporary file containing only that inline javascript. Then, that file is inserted in the page as a simple javascript file. This setting can be enabled or disabled through the settings page.\nMany CSS coming from Drupal core are stripped out as well, this setting can be configured through the theme info file.\nIt is also very simple to load a component CSS or JS file just by creating the file in the component directory, it will be loaded automatically. The file name convention is simple: [component].[js|css].\nAtomic design # The structure of Atomium allows you to split each component into its very own directory. In this way, you can organize your theme components in a clean way, without being cluttered with other stuff.\nAs components are render arrays, you can create components \u0026ldquo;composed of components\u0026rdquo; very quickly.\nThe idea behind Atomium is to follow an Atomic design pattern. I strongly suggest to read the documentation, it explains everything from the ground.\nClean markup # Atomium tries, in every way, to be as clean as possible when rendering its markup.\nSome default added classes has been removed, and most of the components rendered using a theme function has been converted using a template.\nAs every component is based on a template, we have to make sure that templates are without error and we are good to ship.\nNotable changes # In order to be compatible with most contrib modules, I tried not to do too much in Atomium\u0026hellip; and accept the fact that things needs to be improved in Drupal and not in the theme.\nbreadcrumb handling # During the development of this project, a lot of time has been put into analyzing how Drupal\u0026rsquo;s core functions were implemented and how to improve them for better customization.\nA good example of this is the breadcrumb generation, I had to do something.\nLet\u0026rsquo;s analyse how it\u0026rsquo;s currently done in Drupal and how I implemented it.\nThe default implementation is:\n\u0026lt;?php $variables[\u0026#39;breadcrumb\u0026#39;] = theme( \u0026#39;breadcrumb\u0026#39;, array( \u0026#39;breadcrumb\u0026#39; =\u0026gt; drupal_get_breadcrumb(), ) ); By default, Drupal uses the function drupal_get_breadcrumb() in its template_process_page() hook.\nThat function returns raw HTML. Thus, it\u0026rsquo;s almost impossible to alter the breadcrumbs links in an efficient way in a preprocess or process function.\nIn order to get a render array, we have to go deeper and rewrite functions accordingly.\ndrupal_get_breadcrumb() calls menu_get_active_breadcrumb(). This is actually, the function that returns the HTML.\nThere is no way to alter the result of that function as it returns an array of raw HTML links.\nUnfortunately, in order to change this behaviour, we have to create two extra functions in Atomium and change the way the breadcrumb is generated.\nHere\u0026rsquo;s how to generate the breadcrumb properly in the atomium_preprocess_page():\n\u0026lt;?php $variables[\u0026#39;breadcrumb\u0026#39;] = array( \u0026#39;#theme\u0026#39; =\u0026gt; array(\u0026#39;breadcrumb\u0026#39;), \u0026#39;#breadcrumb\u0026#39; =\u0026gt; atomium_drupal_get_breadcrumb(), ); atomium_drupal_get_breadcrumb() is an Atomium internal function written only for the breadcrumb handling. Instead of calling menu_get_active_breadcrumb(), it calls atomium_menu_get_active_breadcrumb() which is also a custom Atomium function that, instead of returning an array of raw HTML links, returns an array of render arrays.\nThis is why, in page.tpl.php, to render it, instead of writing:\n\u0026lt;?php print $breadcrumb; ?\u0026gt;\nYou have to use:\n\u0026lt;?php print render($breadcrumb); ?\u0026gt;\nAs you can see, the rendering process is at the very end of the Drupal\u0026rsquo;s chain of preprocess and process functions.\nAnd this allows customisations at will in preprocess and process functions because we only deal with render arrays in those functions.\nAfter seeing this in Atomium, a colleague of mine reported this very specific issue on drupal.org as well.\nContributing # Atomium is an European Commission Open Source project hosted on Github, you are free to contribute and submit pull requests if you think that something should be done in a different way.\nDon\u0026rsquo;t be afraid to drop me a line, I\u0026rsquo;m quite reactive !\nThe future # Since a couple of months, I took some distances from Drupal planet for personal reasons. I can\u0026rsquo;t wait to come back after my personal stuff are done.\nThe plan for the future is to maintain Atomium and improve it. I wish to have time to work on some particular issues that keeps me up at night.\nThe first issue is this one. Once that issue will be in, you\u0026rsquo;ll be able to use the TWIG engine in Drupal 7 and all its goodness. I\u0026rsquo;m using the patch in production since a year and I haven\u0026rsquo;t got any single problem yet.\nThen I really hope that the breadcrumb patch will make its way too, my colleague too care to make it backward compatible so it doesn\u0026rsquo;t break other modules. Of course, if it goes in, those modules will be able to use preprocess functions instead of overriding the breadcrumb theme function\u0026hellip; and only that, it\u0026rsquo;s a huge plus.\nOf course, as a background task, I need to work on Drupal 8 and see if Atomium would have its place there.\n","date":"10 July 2017","externalUrl":null,"permalink":"/2017/a-word-about-atomium/","section":"Posts","summary":"","title":"A word about Atomium","type":"posts"},{"content":"","date":"10 July 2017","externalUrl":null,"permalink":"/tags/atomic/","section":"Tags","summary":"","title":"Atomic","type":"tags"},{"content":"","date":"10 July 2017","externalUrl":null,"permalink":"/tags/atomium/","section":"Tags","summary":"","title":"Atomium","type":"tags"},{"content":"","date":"10 July 2017","externalUrl":null,"permalink":"/tags/theming/","section":"Tags","summary":"","title":"Theming","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/blender/","section":"Tags","summary":"","title":"Blender","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/git/","section":"Tags","summary":"","title":"Git","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/graphics/","section":"Tags","summary":"","title":"Graphics","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"Here\u0026rsquo;s a list of software that I have used across my career and which are my favorites.\nSome of them were used for work, some of them for personal use, but that\u0026rsquo;s absolutely not relevant here.\nThis list is not a ranking of the best software. This is why it is sorted in alphabetical order to not favor one or the other.\nBlender # Blender is a free and open source 3D creation suite. I started to use it 15 years ago. I remember at that time, you could even copy it on a floppy disk!.\nI discovered this software while I was discovering Linux. At that time, that was the only 3D software available.\nI spend days and night learning it. The 3D world was something pretty new for me, I really loved it.\nThen I remember I bought the \u0026ldquo;C-Key\u0026rdquo; to unlock some features, I went to London to meet the developers team, I remember I was in a cab with Ton Roosendaal, the Blender\u0026rsquo;s project founder. At that time, my english was not very good !\nThis is thanks to Blender that I discovered the Python language. I even made some scripts to show the visual result of some algorithms, the bifurcation diagram, the Koch snowflake fractal, the chainette curve, etc etc\u0026hellip;\nUnfortunately, I rarely use it now \u0026#x1f622; but I still keep the last version on my computer and can still use it, but I forgot a lot.\nDesmos # Desmos is an online tool to explore mathematical functions and graphs.\nWith Desmos you can graph functions, plot data, evaluate equations, explore transformations, and so much more.\nIt has a nice and clean interface and you can even save your graphs if you log in to your account. This is a great tool for the curious animal that I am when it comes to understand some concepts.\nHere\u0026rsquo;s a list of graphs that I made once to understand the idea behind the theory:\nDirac distribution Poisson distribution Gamma function or the factorial as an integral Value of Pi under different L(p) metrics Drupal # Drupal is, according to many, a CMS, but I consider it now, after years of practice, as a framework.\nI first registered on Drupal\u0026rsquo;s site the 24th of January in 2006. I\u0026rsquo;ve always been in love with photography and I was looking for a solution to have my online photos gallery, as you can see on my first comment on drupal.org.\nI tried it\u0026hellip; gave up and ended up using something else: Gallery \u0026#x1f602;.\nTo be honest, at first I was a bit reluctant, I could not see the power of the tool at first, but I knew that there was something that I was not understanding properly.\nI wanted to unravel the Drupal\u0026rsquo;s mystery \u0026#x1f606;\nThe more I was reading success stories about it, the more I was frustrated to not be able to do what I want with it. I gave up, then I tried again\u0026hellip; then I reproduced that pattern a couple of times until the release of Drupal 5, where I really started to handle the tool correctly.\nUnfortunately, life happened and something that goes with it: work.\nMy time to play with Drupal was considerably reduced and I lost the track for a couple of years.\nI continued to work with it after my hours\u0026hellip; until the day a better suited job found me, so to speak\u0026hellip; and since then, I work with it almost everyday.\nGeogebra # Geogebra is a 2D/3D graphing calculator for functions, geometry, algebra, calculus and statistics.\nOnline java applet tool, you can use either use the online tool or install it locally.\nThis tool is in the same category as Desmos.\nIt has a very nice and huge materials library that you can search and browse.\nYou can also create and share your material if you sign in.\nI\u0026rsquo;ve also created some examples for you to play with:\nDirac distribution Poisson distribution Gamma function or the factorial as an integral Value of Pi under different L(p) metrics Zeta function Git # Git is a version control system (VCS) for tracking changes in computer files and coordinating work on those files among multiple people.\nIt is something amazing. It\u0026rsquo;s the kind of software that makes you think that it\u0026rsquo;s powered with black magic inside.\nIt\u0026rsquo;s been years that I\u0026rsquo;m using it almost every single day and it amaze me.\nAccording to me, the best way to learn it is to read a good book and to practice it on the side. Of course there are very good websites to learn it like:\nhttps://try.github.io/, http://learngitbranching.js.org/. There are many others but your favorite search engine is your friend for that.\nAlmost all the software I used since I started playing with a computer switched to Git for their development.\nLinux # Ok, Linux is not a software, it\u0026rsquo;s an operating system, I know, but still.\nI\u0026rsquo;m using Linux since more than 15 years now. The first Linux I had was Red Hat 5.2, and I still have the original box \u0026#x1f605;.\nMy computer was an IBM i386 with 16MB of RAM. This is where it all began.\nI remember at the time where Internet was expensive and not that widespread in Belgium, there were not a lot of instant communication software. With friends, we were using IRC and then later ICQ. I remember I was having a lot of \u0026ldquo;Connection reset by peer\u0026rdquo;, it is while asking how to prevent such that I\u0026rsquo;ve been told about Linux and its security advantages. This is during those conversations about security that I saw the Linux word for the first time.\nThe curious animal that I was already at that time (and that I am still), started with Red Hat 5.2, then Suse, then Slackware and finally Gentoo.\nAnd since more than 10 years, I\u0026rsquo;m still a very happy Gentoo user.\nI also tested the BSDs but I always ended up using Linux for some practical reasons.\nI\u0026rsquo;m using Linux on my personal laptop and at work. I almost never use any other operating system.\nPHPStorm and Pycharm # PHPStorm is a proprietary IDE by Jetbrains.\nIt\u0026rsquo;s a bit against my philosophy to use it but I have to say that I haven\u0026rsquo;t found the equivalent in the open source world.\nOf course, there are Eclipse, Atom, Sublime Text, and many others\u0026hellip; but they are at lightyears from it.\nI use PHPStorm for PHP and Pycharm for Python.\nScreen # GNU Screen is a terminal multiplexer, a software application that can be used to multiplex several virtual consoles, allowing a user to access multiple separate login sessions inside a single terminal window, or detach and reattach sessions from a terminal. It is useful for dealing with multiple programs from a command line interface, and for separating programs from the session of the Unix shell that started the program, particularly so a remote process continues running even when the user is disconnected.\nI\u0026rsquo;m using Screen since 2004. It was a bit hard to remember all the shortcuts, but in the end, we always use the same ones.\nI mainly use it on remote servers when I need to run tasks and make sure I\u0026rsquo;ll see their output when I\u0026rsquo;ll reconnect to the server from another IP.\nIt\u0026rsquo;s just a tool you can\u0026rsquo;t do without it if you\u0026rsquo;re using Linux.\n","date":"1 May 2017","externalUrl":null,"permalink":"/2017/my-favorite-software/","section":"Posts","summary":"","title":"My favorite software","type":"posts"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/photography/","section":"Tags","summary":"","title":"Photography","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/software/","section":"Tags","summary":"","title":"Software","type":"tags"},{"content":"","date":"1 May 2017","externalUrl":null,"permalink":"/tags/tools/","section":"Tags","summary":"","title":"Tools","type":"tags"},{"content":"","date":"13 April 2017","externalUrl":null,"permalink":"/tags/combinations/","section":"Tags","summary":"","title":"Combinations","type":"tags"},{"content":"","date":"13 April 2017","externalUrl":null,"permalink":"/tags/combinatorics/","section":"Tags","summary":"","title":"Combinatorics","type":"tags"},{"content":"","date":"13 April 2017","externalUrl":null,"permalink":"/tags/packagist/","section":"Tags","summary":"","title":"Packagist","type":"tags"},{"content":"","date":"13 April 2017","externalUrl":null,"permalink":"/tags/permutations/","section":"Tags","summary":"","title":"Permutations","type":"tags"},{"content":" In December 2016, I started to write a PHP library called PHPermutations to handle permutations and combinations of an array of items. The array items can be any type of object: integers, arrays, strings or objects, the library will still continue to work without any trouble.\nBut before going further, let me remind you what are the differences between permutations and combinations.\nDefinition of Permutation from Wikipedia:\nThe notion of permutation relates to the act of arranging all the members of a set into some sequence or order.\nDefinition of Combination from Wikipedia:\nA combination is a way of selecting items from a collection, such that, unlike permutations, the order of selection does not matter.\nThe formula to find the number of permutations of $$ n $$ items among $$ r $$ items is:\n$$ P(n, r) = \\frac{n!}{(n-r)!}$$When the elements order does matter, it is a permutation.\nThe formula to find the number of combinations of $$ n $$ items among $$ r $$ items is:\n$$ C(n, r) = \\frac{P(n, r)}{r!} = \\frac{\\frac{n!}{(n-r)!}}{r!} = \\frac{n!}{r!(n-r)!} $$When the elements order does not matter, it is a combination.\nReal life example 1 # Let\u0026rsquo;s say you have a card game composed of 10 different cards and you would like to know how many permutations and combinations of 10 cards you can do with it.\nIn this case, this is $$ P(10, 10) = \\frac{10!}{(10-10)!} = 3628800 $$In this case, this is $$ C(10, 10) = \\frac{10!}{10!(10-10)!} = 1 $$So, with 10 cards, you\u0026rsquo;ll be able to make 3628800 permutations and only 1 combination.\nReal life example 2 # Let\u0026rsquo;s say you have a card game composed of 9 different cards and you would like to know how many permutations and combinations of 6 cards you can do with it.\nIn this case, this is $$ P(9, 6) = \\frac{9!}{(9-6)!} = 60480 $$In this case, this is $$ C(9, 6) = \\frac{9!}{6!(9-6)!} = 84 $$So, with 9 cards, you\u0026rsquo;ll be able to make 60480 permutations and 84 combinations of 6 cards.\nTo give you an idea of how the function is growing, we can use the Big O Notation.\nThe Big O notation characterizes functions according to their growth rates. Different functions with the same growth rate may be represented using the same O notation.\nIn this case, the order is $$ O(n!) $$, results are growing quickly for small input values.\nAnd if you have to store huge results arrays, you might end up with the infamous:\nFatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)\nThis is why in order to avoid those errors, I only used PHP Generators and Iterators in PHPermutations.\nFrom PHP.net:\nA generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory, which may cause you to exceed a memory limit, or require a considerable amount of processing time to generate. Instead, you can write a generator function, which is the same as a normal function, except that instead of returning once, a generator can yield as many times as it needs to in order to provide the values to be iterated over.\nMoreover, the notable difference with other combinatorics library is that you can use an extra parameter $$ r $$ (the length), that allows you to compute permutations and combinations of any particular size.\nLast but not least, PHPermutations includes tests for most of its functionalities. Tests are not my cup of tea, however, I tried to be as much complete as possible with those.\nEvery time the sources are modified, Travis, the continuous integration service, tests the library against those tests, this way you are aware if the changes you introduce are valid.\nIf you\u0026rsquo;d like to review PHPermutations or think that things should be done in another way or just found a bug, please, let me know or submit a pull request on Github, I\u0026rsquo;m quite reactive.\n","date":"13 April 2017","externalUrl":null,"permalink":"/2017/what-is-phpermutations/","section":"Posts","summary":"","title":"What is PHPermutations?","type":"posts"},{"content":"","date":"12 April 2017","externalUrl":null,"permalink":"/tags/collaboration/","section":"Tags","summary":"","title":"Collaboration","type":"tags"},{"content":"","date":"12 April 2017","externalUrl":null,"permalink":"/tags/github/","section":"Tags","summary":"","title":"Github","type":"tags"},{"content":"Lately, I’ve been working with my colleague on a project hosted on Github.\nWe were working on a specific part, which is a component composed of sub components.\nDuring the development, the parent branch “master”, where the feature branch “feature/feature-198” is originating from has evolved on its own. Some small bugs were discovered, fixed and merged.\nHowever, you guessed it, some of these commits were needed in the feature branch.\nAs always, I try to keep all my branches clean. It means that I try to avoid useless commit logs.\nNote, to keep your code and commit log clean, you might have a look at GrumPHP, thanks to @netlooker for discovering it, I love it, I use it everywhere now !\nAnd here, I didn’t want to have a pull request polluted with merge commits.\nI’ve decided to rebase the feature branch, knowing that we were two working on it.\nHere’s what I did:\n$ git fetch --all $ git checkout feature/feature-198 $ git rebase origin/master $ git push origin feature/feature-198 --force Then, my colleague has to commit/push its work.\nUnfortunately Git was unable to push the commits because history has diverged and a git pull was needed to fix the situation.\nThey did it and so far so good, everything was fine.\nExcept that we ended up with merge commits and even worse, most of the previous commits were duplicated.\nI’ve decided to let it go for this time, knowing that in the end, we would squash everything into a single commit during the merge.\nBut… we continued to work on that same feature branch the whole day and during the day, the same situation happened. The parent branch evolved and I needed some of the commits in the feature branch.\nI did the same commands as the first time, but this time, I went to my colleague’s computer and issued the following commands:\n$ git fetch $ git stash $ git pull origin/master --rebase $ git stash pop After playing these commands, I carefully checked with my colleagues if his current uncommitted work was back, and he confirmed that everything was there. The git-stashing worked perfectly.\nI was quite confident with these commands until later in the day, my colleague called me in emergency, saying that we shouldn’t work on the same branch next time, and never ever do a rebase either because some of its work was lost.\nI felt guilty at first.\nI know that doing a rebase on a branch where multiple people is working on is not a good practice, but still, we are developpers and we need to deal with such situations. Git is THE tool that we need to use and understand in order to ensure that what we do is kept somewhere safe.\nOn the other hand, even if we shouldn’t do that, we have to learn how to prevent data loss and how to handle that.\nThis is where the idea of writing a blog post explaining the situation came to my mind to, first get some feedback on what I did, secondly, to share the experience with other colleagues and lastly, to remember how to avoid these errors in the future.\nFor every good or bad situation we should draw conclusions, and here is what I concluded.\nFirst, rebase at the very end, just before merging the feature branch. If you have to include commits from the parent branch, do one or multiple merges of the parent branch back into the feature branch. It’s ugly, it’s noisy but it’s perfectly safe and sound for everyone.\nSecond, prior doing any commit and push, make sure to do a git pull first.\nThird, commit often in order to make sure that your work is saved. If you start the day at 9am, then, commit every hour or so, then, once or twice per day, push your work.\nFour, do not be afraid on being many people working on the same branch, Git is a very stable software and it has our back, we can rely on it for keeping our beloved ordered suite of random characters in a safe place.\n","date":"12 April 2017","externalUrl":null,"permalink":"/2017/prenez-un-chewing-gum-emile/","section":"Posts","summary":"","title":"Prenez un chewing-gum Emile","type":"posts"},{"content":"","date":"12 April 2017","externalUrl":null,"permalink":"/tags/rebase/","section":"Tags","summary":"","title":"Rebase","type":"tags"},{"content":"","date":"1 April 2017","externalUrl":null,"permalink":"/tags/blogging/","section":"Tags","summary":"","title":"Blogging","type":"tags"},{"content":"It\u0026rsquo;s been a while that I wanted to run a blog. I think, the last time I did one, was on Blogspot, and the last post was from late 2009.\nSo yes, it took me some time to decide myself.\nMaintaining a blog, but for which purpose ?\nAccording to me, a blog is a way to share stuff that you like on the Internet, without being forced to use any social network. Now, 8 years after my last post, I think this blog will be a kind of personal Internet log.\nThe subjects that I would like to share on these pages are all the things that I like and that I found on the Internet.\nHere\u0026rsquo;s a quick list :\nDrupal Git Sciences Work These four stuff are the things that I like the most on the Internet. Oh, and I just noticed that I forgot one important subject: the Internet \u0026ldquo;meme\u0026rdquo; :-)\nSo as I said, it took me quite a lot of time to decide myself to run a blog.\nI could have decided to use an existing social network to share my stuff, but I wanted to do it myself so I could customize it and learn something while doing it. Moreover, sharing stuff on Twitter is fine, but 160 characters are often not enough to express your feelings. Then as I\u0026rsquo;m not an active user on Facebook and on Google Plus, I wanted to find something else.\nLet\u0026rsquo;s use a software to run my own blog.\nAs a Drupal contributor, the logical path was to have a blog running with Drupal, version 8 please. I though about running it with it, but it would be overkill for just a simple blog.\nThis is why I decided to check what were the tools available to do such a thing, without too much hassle.\nI didn\u0026rsquo;t want to pay for it, I wanted something simple to use and simple to update, I wanted something secure.\nThis is when I discovered Jekyll.\nJekyll is a simple static site generator written in Ruby. It takes a template directory containing raw text files in various formats, runs it through a converter, and spits out a complete, ready-to-publish static website.\nYou\u0026rsquo;ll need a bit of time to use the Ruby commands but after some time, you\u0026rsquo;ll get used to it.\nThe procedure to create a new post is to create a file in a particular directory, commit and push to Github, and it\u0026rsquo;s done.\nMy colleague @netlooker advised me Hugo, the same kind of tool, written in Go. Even if it seems to be a great tool, I still prefer Jekyll because it\u0026rsquo;s used by Github Pages and Github regenerates the pages automatically as soon as you modify the repository.\nI think we could discuss days and nights about which software to use and which languages to use.\nThe conclusion is: Use the one you want and think it will do the job. On my side, with Jekyll, I\u0026rsquo;m 100% satisfied.\nLast but not least, as English is not my mother tongue, running a blog will help me to maintain a good level of written English.\n","date":"1 April 2017","externalUrl":null,"permalink":"/2017/why-a-blog/","section":"Posts","summary":"","title":"Why a blog?","type":"posts"},{"content":"","date":"2 July 2012","externalUrl":null,"permalink":"/tags/cms/","section":"Tags","summary":"","title":"Cms","type":"tags"},{"content":"","date":"2 July 2012","externalUrl":null,"permalink":"/tags/companies/","section":"Tags","summary":"","title":"Companies","type":"tags"},{"content":"","date":"2 July 2012","externalUrl":null,"permalink":"/tags/project-management/","section":"Tags","summary":"","title":"Project Management","type":"tags"},{"content":"I have been working for more than five years now, as a consultant in Belgium.\nI\u0026rsquo;m sailing from company to company, from building to building, and my clients are mainly large companies with 1500+ people, some others are smaller.\nUsually hired as a senior developer or project manager, I\u0026rsquo;m helping those companies to have a successful Drupal experience.\nSometimes my work consists of guiding a team and giving them the best practices around web development and Drupal, sometimes it consists of creating customs modules to fulfill their needs.\nMost of the time, I enjoy my work. I enjoy meeting people, having a talk with people in the business is always a two ways interesting exchange. I enjoy being in the loop and use the latest right technologies on my projects.\nAs long as I learn new stuff everyday and I as long as I can share it with people and make them happy, I\u0026rsquo;m happy.\nWorking in the web and especially Drupal requires a couple of skills. You have to be able to work on Linux, setup a webserver and understand how it works, understanding PHP and managing databases and how they works and if you\u0026rsquo;re lazy, you\u0026rsquo;ll use extensively a tool called Drush.\nWorking with all those technologies requires the knowledge of other sub tools like SSH, Bash, a command line editor, an IDE, etc etc\u0026hellip;\nWhen you work alone, on your own server, all those tasks are done by yourself.\nFrom changing directory rights to create backup and editing your content, all those tasks are done by you, only you.\nYou don\u0026rsquo;t have to wait to have the permission from someone nor explain to some other guys who doesn\u0026rsquo;t understand Drupal, why you\u0026rsquo;re doing that. In short, you don\u0026rsquo;t lose time.\nI\u0026rsquo;ve tried to list the pro and cons of working alone, here they are\u0026hellip;\nThe cons are:\nYou\u0026rsquo;re alone, on your own. The pros are:\nNo need to delegate the task to others.people. No need to waste time filling out useless paper. No need to count on someone else to do it. No need to ask someone to make the task a priority. There\u0026rsquo;s nobody else to blame if something fails. Almost no need to document what you do even if it\u0026rsquo;s strongly advised. When you work in team, it\u0026rsquo;s totally different, and when you work in big companies, you can be seriously disappointed by your job, you better have shoulders and strong backs.\nFirst of all, large companies are often structured. It means that every part of your development workflow is handled by someone different, who doesn\u0026rsquo;t do always the same stuff and who has a priority list to respect, which can be different from yours.\nOf course, this experience is from my personal point of view, and all it doesn’t means that all companies are working like that, fortunately for me, and for them !\nWorking with Drupal doesn\u0026rsquo;t help, it requires several types of knowledge. This knowledge is arising because of the different most commonly used softwares needed to run Drupal, like Apache, PHP and MySQL.\nWhen working alone, these softwares are often installed on a single machine and you have complete control over but when working with others, that stack is splitted on different servers and taken care by different teams of people.\nWell of course, to top it off, you have access to none of these servers and being admin (uid 1) on Drupal\u0026rsquo;s sites is disallowed, it’s another ‘middleware’ team who have those access and they don’t know how to use Drupal, and of course, no PHPMyAdmin or equivalent, which make sense on production servers, but not on development’s.\nIf you want to run a version of the website you are developing on the staging server, these are the steps, simplified:\nProvide Team A a compressed archive with all the Drupal\u0026rsquo;s related files. Provide Team A a tutorial on how to install it. Ask Team B to create a database and send credentials to team A. Ask Team C to create DNS entries, with two different address for frontend and backend. Ask Team D to create content. Ask Team E to run a full battery of tests. Be aware that if Team A is using an multisite infrastructure, you have to provide a full explanation on how to install it\u0026hellip; and don\u0026rsquo;t forget the custom SQL queries to Team B, to change the path of files and modules !\nCore and modules updates are also something to think. If you work in large companies, you won\u0026rsquo;t be granted access to staging and production server. It means that you\u0026rsquo;ll be unable to run your beloved drush up command to update core and modules.\nMore than that, every module or core update must be reviewed and approved by someone from another team.\nYou will also have to export your configuration into features, and non exportables stuff must be created manually using a module update.\nAnd if, by any chance, you have access to it, the server doesn\u0026rsquo;t have any access to the Internet, or worst, it’s behind a proxy with authentication… Bummer !\nIn summary, the cons are:\nWasting time filling out useless administrative papers. You need someone else to make your task a priority because you can\u0026rsquo;t do it yourself. No access to Apache server. No access to DB server. No access to Drupal as an admin. The pros are:\nThere\u0026rsquo;s always someone else to blame if something fails, it\u0026rsquo;s never you. You can always count on someone else to do the job, right or wrong. All those constraints can lead to a bad work experience and changing people’s mind and old habits is complicated or impossible.\nDrupal, as most other Open Source softwares, is flexible, as the software required to get it working, companies must take that in account in order to avoid complicating the developer’s life.\nThose companies needs to understand that Drupal is not bundled as something that we can call “Enterprise ready”. It doesn’t means that it’s not ready for Enterprise, it just doesn’t means that it has to be handled and managed in a different way.\nIn the interest of the company, people needs to be trained to that, and managers too !\nThe lack of knowledge can lead to many problems, the slow execution of the task, the bad atmosphere between colleagues, people shooting in other people’s legs\u0026hellip; and many more.\nBeing myself an active contributor in the Drupal’s community, I do not pretend knowing the solution, all I know is that large companies have problems managing teams and they should change their habits.\nI think that with the release of Drupal 8 and the way configuration is handled in it, that it can be exported and VCS’ized (under Version Control System), it will be much better and will hopefully help a lot of people and companies.\nA new way to solve those problems would be to reduce the number of people working on a single project.\nThis, an example of all the people working in a Drupal team:\nThemer: Take care of the design of the whole website, creating the theme from the start Site Builder: Create the views, the whole configuration of the website. They should also take care of the test content used in the site. Site Configurator: In charge to export the whole configuration of the website into files to get them under versioning. Content team: Create the main content into the website. What would be the best number of people working on a Drupal project according to you ?\nAnother idea would be to use the already famous and scary: cloud. I recently started to use for the first time a very well known Drupal cloud service and I think it might be a good solution when working in team on a Drupal project. You can create user accounts, it automatically provides you the git access and also multiple environments.\nUnfortunately, most companies are afraid of the cloud and for some institutions, it’s often unthinkable to host their source somewhere else.\nThis blog post has been written in 2012 and posted on Twitter 2 years later.\n","date":"2 July 2012","externalUrl":null,"permalink":"/2012/why-companies-are-not-ready-for-drupal/","section":"Posts","summary":"","title":"Why companies are not ready for Drupal?","type":"posts"},{"content":"","externalUrl":null,"permalink":"/.htaccess","section":"Not A Number","summary":"","title":"","type":"page"},{"content":"","externalUrl":null,"permalink":"/_redirects","section":"Not A Number","summary":"","title":"","type":"page"},{"content":"","externalUrl":null,"permalink":"/redirect/","section":"","summary":"","title":"","type":"redirect"},{"content":"","externalUrl":null,"permalink":"/cv/","section":"","summary":"","title":"","type":"redirect"},{"content":"","externalUrl":null,"permalink":"/master-thesis/","section":"","summary":"","title":"","type":"redirect"},{"content":"","externalUrl":null,"permalink":"/sponsor/","section":"","summary":"","title":"","type":"redirect"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]