skoop.dev

  • About
  • @skoop@phpc.social
  • API Platform Con is coming

    September 16, 2024
    apiplatform, apiplatformcon, conferences, ddd, DPC, laravel, lille, php, sylius, symfony, xdebug

    Last year was my first API Platform Con, and it was an amazing experience. I heard good things about FrankenPHP and was able to get my first container migrated to FrankenPHP at the conference. It was that simple. I was blown away by the talk on the decentralized web and inspired by the possibilities that the decentralized web presents. I hope the stuff Pauline Vos presented there will become more mainstream soon. The great talks combined with the beautiful city of Lille and the very friendly community made it an amazing conference. I was quite happy to be invited back this year and am looking forward to being there again later this week.

    So let me share the stuff that I’m looking forward to.

    The subject of the opening keynote is still a surprise. The website states The subject of this conference will be announced shortly and I’m curious what it will be. Kevin is a great speaker though, so this will be good regardless.

    Sergès Goma on devs becoming villains

    I’ve seen this talk at Dutch PHP Conference and it is fantastic. It makes you think. I like it when talks make you think. It makes you laugh. I love it when speakers are able to put humour into a talk. Yes, this is one not to miss. Even if I’ve seen it before already.

    The performance dilemma

    Then it’s hard to pick. Both Allison Guilhem speaking on real-time message handling and notifications and Mathias Arlaud speaking on optimizing serialization in API Platform are really interesting subjects. I think I’ll wait until the last minute to decide which one to actually check out.

    After lunch we’ll have another mystery keynote. I guess we should be there as well!

    Admin generator!

    Admin generators have been there since the early days of before symfony (yes, with a lowercase s back then) 1.0. And Francois Zaninotto has also been around that long. I’m really looking forward to Francois speaking about the API Platform admin generator!

    Something something DDD

    Yeah, next up I’m on stage, so I can’t check out the other talk in that slot. The other one is in French anyway, so I probably would’ve skipped on it anyway. My friend is not much better than croissant, chauffeur, Disneyland Paris, baguette.

    Xdebug

    I am, still, a very happy VDD (var_dump/die)-driven developer. I know I should do more with Xdebug. And who better than to hear from than Derick himself.

    After the panel discussion it’s time for the community party. And given we’ll have a party, I’m not sure if I’ll be in time for the first session on Friday. I’ll try though because while I’ve played with FrankenPHP a bit, I’m not extremely familiar with Caddy, and in the first session Matt Holt will be talking about Caddy. So that could be very interesting!

    One Billion?!

    Florian Engelhardt will be doing some fun stuff with optimizing PHP in his experiment on processing a 1 billion row test file with PHP. That’s a lot!

    It’s alive!

    I’ve mentioned me playing with FrankenPHP already and Boas Falke will be talking about building stand-alone binaries using FrankenPHP. That is awesome!

    Consume!

    I work with a lot of API’s in all my projects, so I’m curious if Nicolas Grekas will be able to teach me what I’m doing wrong. He’s presenting his talk Consuming HTTP APIs in PHP The Right Way so I’m expecting a lot of shaking my head about how I’ve been doing this wrong the whole time.

    Sylius!

    My favorite e-commerce framework also has presence at API Platform Con, in the form of Łukasz Chruściel speaking on how they’ve handling migrating to API Platform 3. I’m working on a big migration project (although no API Platform), so it’s good to learn about how they handled this.

    Laravel?

    API Platform is a Symfony-based system, right? RIGHT? Well, apparently not. Perhaps the talk I’m looking forward to most is Steve McDougall’s talk on using API Platform within a Laravel application. I work a lot with Symfony, but I also work quite a bit with Laravel. Having a powerful tool such as API Platform available on Laravel projects is an excellent way to make Laravel projects even more fun. So yes, I’m really really looking forward to this one.

    Lille

    Having said all that, I’m also looking forward to visiting the beautiful city of Lille again. Last year on the Saturday after the conference I took a long walk through the city before driving back home. Lille is a fantastic city. Will I see you there?

  • A quick-follow up about the generated fields

    September 12, 2024
    doctrine, generated fields, json, mysql, symfony

    Since I posted about the generated fields I’ve learned some interesting new information that I wanted to share as well. There is an interesting detail that may lead to issues.

    In my previous example I used the following to map to fields inside the JSON:

    price_info->"$.salesprice"

    The -> here is the interesting part: There are two variations, being the aforementioned -> and another one ->>.

    -> simply extracts the value from the JSON. This is best used to ensure correct types from the data for basically anything but strings. If you have, for instance, an integer value or a boolean in your JSON and you map it to a correctly typed column, you’ll get an error if you use ->> because that will always cast it to a string. Why? I’ll get back to that. For now: If your value is not a string, best use ->.

    ->> does more than simply extracting the value. It also unquotes the value. This is useful for strings, because in JSON they are always between ". If you use -> on a string value, then you will get that value, plus the quotes. Such as "value". If you use ->> then you will get value. Without quotes. So ->> is the best one to use for string values. However, as mentioned before, this does mean that it will always assume a string value. So if your value is not a string, it will be made a string. If your generated column is not of a string type, this will give you errors about typing.

  • Using generated fields in MySQL

    August 23, 2024
    doctrine, generated fields, json, mysql, php, symfony

    Recently I have been working on a migration of data from an old application to a brand spanking new Symfony 7 application. This migration included getting rid of the old Couchbase document database and moving to MySQL. MySQL has for quite some time already had a special JSON field type that is actually pretty cool. And using Doctrine, you don’t even notice it’s JSON, because there are automatic transformations to a PHP array structure.

    I was looking for the right way to set indexes on specific fields inside the JSON structure for easy querying, and as I was doing so I learned about MySQL generated fields. This is pretty cool stuff, as it will automatically create virtual fields in your table with the data as it exists inside the JSON. And those fields can be part of an index!

    Step 1 is obviously creating the column. So let’s add a column to a table called articles:

    ALTER TABLE articles 
    ADD sales_price INT AS (price_info->"$.salesprice"),
    ADD cost_price INT AS (price_info->"$.costprice");

    In this example, the price_info is the JSON field. Inside the JSON structure, it has a field with key salesprice and a field with key costprice, and I here add those as seperate columns sales_price and cost_price into the table articles.

    Above query I can now add to a Doctrine migration.

    Now I also need to specify to Doctrine in the entity that the fields exist. But they are special fields, because they are read-only (you update the value by updating the JSON). So you need to configure that for your entity. For instance:

    /** * @Column(type="json") */
    protected $priceinfo;
    
    /**
     * @Column(type="int", nullable=true, insertable=false, updatable=false)
     */
    protected $sales_price;
    
    /** * @Column(type="int", nullable=true, insertable=false, updatable=false) */
    protected $cost_price;

    Notice the fact that I set insertable and updatable to false. Also important: I set nullable to true. Why? Because in a JSON field, there is no guarantee that a value is there. If a value is missing, MySQL will set it to NULL. If your field is not nullable, it will fail on writing the record to the database.

    Now, if you create a new Article and set JSON that contain the costprice and salesprice fields, as soon as you persist it in the database, the values of $cost_price and $sales_price are automatically populated based on the values in the JSON.

    Since they are now regular properties of your entity, you can also use them in the where clauses of your queries. They are, for all intents and purposes, simply regular fields in your table. The only thing you can not do is set the value on your entity and persist it, and expect it to stick. If you need to change the value, you need to update the JSON.

    I just wanted to share this because I think this is extremely cool and useful stuff. As for a practical example: One use case I know of at least is to store data structures from external systems in exactly the structure you receive it, and let MySQL sort everything out for you. Especially when you may also need that structure to communicate back to the external system, it is good to keep the structure the way you received it.

  • RabbitMQ in your Bitbucket pipeline

    August 15, 2024
    bitbucket, pipelines, rabbitmq, service

    Last week one of my tasks was getting our Behat tests to run successfully in the Bitbucket pipeline. Now, we have an interesting setup with several vhosts, exchanges and queues. Our full definition of our RabbitMQ setup is in a definitions-file. So that should be easy, right? Well, think again.

    Unfortunately, Bitbucket does not allow for volumes for services in your pipeline, so there is no way to actually get our definitions file into our RabbitMQ service. After searching for ways to solve this, with my express wish to not have to build my own RabbitMQ image, I ended up coming to the conclusion that the solution would be to… well, build my own image.

    Creating the image was very simple. As in, literally two lines of Dockerfile:

    FROM rabbitmq:3.12-management
    
    ADD rabbitmq_definitions.json /etc/rabbitmq_definitions.json

    I build the image and push it to our registry. So far so good. Now, I needed to alter our service definition in bitbucket-pipelines.yml. This was also not that hard:

    services:
        rabbitmq:
            image:
                name: <registry-url>/rabbitmq-pipeline:latest
                username: $AZURE_USERNAME
                password: $AZURE_PASSWORD
            environment:
                RABBITMQ_DEFAULT_USER: <rmq-user>
                RABBITMQ_DEFAULT_PASS: <rmq-pass>
                RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: -rabbitmq_management load_definitions "/etc/rabbitmq_definitions.json"

    The trick in this definition is in that environment variable RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS. This basically tells RabbitMQ to load the definitions file we baked into the image in the first step. That will then set up our whole RabbitMQ, so that the code executed during the Behat tests will be able to connect as usual. RabbitMQ will be available in your pipeline on 127.0.0.1.

  • Creating a Bitbucket merge train

    August 14, 2024
    bitbucket, git

    Sometimes it happens: You have to work on a new feature, but that feature is depending on another feature that isn’t merged yet. Especially when trying to keep your branches small and you’re not doing trunk-based development, this may happen.

    Luckily, Bitbucket makes our life a lot easier. Say you create a new feature-branch-2 based off of feature-branch-1, when you create the pull request, instead of targetting main which will cause your diff to contain the changes of both branches, you can set the target of your PR to be feature-branch-1. Now your diff will only contain the changes in feature-branch-2, which makes it a lot easier to review.

    Now, when the feature-branch-1 PR is reviewed and ready to be merged, you don’t really have to do anything to the feature-branch-2 PR, as long as you keep this checkbox checked that is checked by default:

    On merging, Bitbucket will now automatically re-target the feature-branch-2 PR to the main branch.

  • Goodbye Sculpin, hello WordPress

    August 9, 2024
    sculpin, wordpress

    I really liked the idea of a static site generator. I still the idea of a static site generator, to be honest. However, writing purely in Markdown and having to go through some stuff to publish a new post became a bit of a hassle. So I wanted to go for a dynamic CMS again. My initial idea was to build the site in Bolt, as I love that CMS and the flexibility it offers. I even started on that, but ended up finding I did not enjoy myself while buildings. That made me decide that perhaps I should actually go for WordPress. It works, I have a hosting provider with an easy installer, it has tons of plugins if I want something specific, and… I’ve come to enjoy the new editor on one of my other sites.

    Migration

    Now, the migration was not easy. I started looking for ways to automatically import all my Markdown files. There was a plugin, I couldn’t figure it out. It became a chore. I quit. I gave up.

    I ended up doing a manual migration. I combined the migration with a bit of a clean-up. I removed some articles, added some additional tags to some articles, etc. It was also a nice moment of reflection. Over the years I did a lot of different things. I made some mistakes, or no, I grew. I understand now why some of the opinions I used to have might not have been the best.

    And now it’s up

    So far I’m happy. I have a CMS again. I can easily write and update posts from wherever I have access to my password manager. After all the different CMS’es I’ve had, I wonder how long WordPress will last me. Should be at least a couple of years, looking at my track record of Pivot, Textpattern, Octopress and Sculpin (and possible others) that I’ve used in the past,

    Welcome to the new skoop.dev!

  • Unsupported operand types string * int

    July 30, 2024
    error, php, tip

    Today I had a weirdly failing unit test. PHPUnit complained about the data provider being invalid, with a very vague error:

    Unsupported operand types: string * int

    This was weird, because I wasn’t doing any calculations in the dataprovider.

    That made debugging annoying as well. If I’m not doing any calculations, why this error?

    It turned out a typo was the cause. The weird thing though: There was no * in there. The typo was:

    $errorString -= 'Missing required data key: "%s".';

    See the -= there? That was the issue. It’s still unclear to me why I got the error I got, but if anyone runs into this error, be aware that the error may imply more than just *.

  • Symfony and DDD (and SymfonyCon)

    July 25, 2024
    conferences, ddd, php, symfony, symfonycon, talks

    Last year at the SymfonyCon conference I did a talk about Domain-Driven Design in which I mostly focussed on the theory behind trying to understand what problem you’re actually solving. I really enjoyed doing that talk, but I got some interesting questions afterwards about practical implementation of DDD when using Symfony. And I’ve also seen at several clients that people are always looking how they can actually implement a DDD approach when building software with Symfony.

    That prompted me to consider what would be the best way to do this. There is so much to talk about and the answer to a lot of questions is “it depends”. So I decided to develop a new full-day workshop about this. In this workshop, we take a Symfony project, and we start adding some functionality.

    I am still developing the contents, but things that will come by are amongst other things:

    • How to split up domains
    • Implementing a hexagonal architecture
    • Doctrine entities vs domain entities and how to make that split
    • How to implement communication between bounded contexts and domains

    The workshop will contain a theoretical part per subject, but also exercises for people to actually get some experience with doing this, as I realize that some people learn more from listening to the theory and others learn more by doing.

    If you are interested to get this training for your team, shoot me an email. For those coming to Vienna for SymfonyCon, I do have some good news: On December 4, I’ll be doing this workshop at SymfonyCon. You can already book your tickets.

    Will I see you in Vienna?

  • Upcoming conferences

    June 21, 2024
    apiplatformcon, cakefest, conferences, php, talks

    Conferences are both fun and useful. Fun because you meet people and useful because you learn stuff. I have two conferences in the upcoming months, and I hope to see you there!

    Cakefest

    Last year was my first Cakefest. It was in Los Angeles, and a lot of fun. While I am not using CakePHP and have not used CakePHP in a while it was good to meet the community and share some information that might be useful.

    I am honored that they think I did good enough a job to be invited back again this year. And even better: I don’t have to fly out, I am actually driving to Esch-sur-Alzette in Luxembourg. The schedule is looking good! I will be doing my talk on sustainable open source contributions there.

    Tickets are available for the in-person conference, or you could even get a free ticket for the online stream of the conference. But in-person is usually more fun, so if you have the opportunity, join us!

    API Platform Conference

    Another conference that I got invited back to is API Platform Conference. Again in driving distance for me, and I had a lot of fun last time, so I’m absolutely looking forward again to being there. The conference is in Lille, in the North of France.

    In Lille, I will be doing my Domain-Driven Design basics talk, which focusses on what I think is the most important part of DDD: Understanding the problem. Lille is a beautiful city, the schedule is amazing… I’m really looking forward to it.

    This conference also has both in-person and online tickets. If you have the opportunity, I’d love to see you there!

  • Upgrade or upgrade?

    June 7, 2024
    php, symfony, upgrade

    When you have an application built on top of an existing framework, then it is very tempting to just leave it be once the initial development is done. Never change a winning team, right? So once you delivered the project and it’s running in production, the only thing you need to do is to add or change features and fix some bugs. Right?

    Well, for a long time you can indeed do that and it won’t hurt you. But in the long run, this will become a problem. Because while your application stands still, the world around you moves on. And that moving on includes new versions of your framework of choice. And as new versions come out, support of older versions will at some point be dropped. For big, popular frameworks there is usually a pretty clear release schedule of when new versions come out and how long old versions are being supported.

    In most situations there is a phased end of life. First, active support for bugs will be dropped but security issues will be fixed. Eventually though, security issues will also not be fixed anymore.

    If at that point, your application is still running on that old version, you are at risk of security issues which can lead to, amongst other things, damage to your public image or even legal action in case of security breaches. It is important to do regular maintenance and upgrades of any software you use. Whether that is the desktop software you use, frameworks and libraries and anything else.

    However, because of a lot of different reasons, you can end up with an application that is years old and a lot of versions behind the current stable version. So what then?

    Quite a few of the projects I’ve worked on in the past years have in some way or form included a situation like this (or I would see this coming in the future). There are two important approaches here, with different variations of those approaches.

    Approach 1: Upgrade step by step

    Let’s take the example of an old Symfony project. It is stuck at version 3.4 of the framework. With Symfony 7.1 out now, one approach could be to do a step-by-step upgrade. This would mean going from 3.4 to 4, then 4.4, then 5, then 5.4, then 6, then 6.4 and then finally to 7 (either directly to 7.1 or via 7.0).

    This may sound like a lot of work, and it is! So it’s important to understand how to make the decision to go for this approach. What I’ve found is the most important factor to decide on to take this choice is the size or complexity of the project. This approach is mostly interesting for projects that are really big or very complex in terms of logic.

    Requirements

    Before you even start with such a massive project that is hard to estimate in terms of time and effort is to make sure that at least you can ensure your work was done correctly. So you need to have:

    • Good documentation of what the application does, preferably including developers with a lot of experience with this application
    • A good set of tests. Preferably a combination of unit tests and integration tests
    • Support of your organization and most importantly, your management

    If you don’t have one of the above, make sure to get it. Documentation can be obtained by talking to developers that have worked on the project, but also business stakeholders and most importantly: users. Make sure that you have a clear understanding of the expected behaviour. You can use this information not just to understand what happens, but also…

    To write tests! If you don’t have a comprehensive test suite of unit tests (especially for important business logic) and integration tests (at the minimum as smoke tests to quickly see where potential trouble is, but preferably that actually tests your user experience), before you even change a minor version of your framework, start writing tests. The lessons learned from requirement 1 can help you with this requirement.

    Last but not least: Management really needs to support the effort. It’s important that they understand why it is necessary to be running on a recent and supported version of the framework. Explain to them the risk of hacks but also the extra effort needed to build new features into such old versions. The new, modern features that may be available in newer versions, etc. Without solid support from management, at some point priorities will change and you’ll be stuck with a half-upgraded project.

    Go go go!

    Once your requirements are met it’s time to do the actual work. This will most probably take a big effort. Especially with the example I used where you go from Symfony 3.4 (which does not support PHP 8) to Symfony 7.1 (which requires PHP 8). This means that along the way, you’re not just making the jump from one Symfony version to the next, but also the jump from one PHP version to the next. And you don’t just do that for your framework, but also for any other libraries you’re using. Adn the dependencies of dependencies might start clashing.

    To make this as easy as possible, you need to really take smalls steps at a time. Usually inside a major version it’s relatively easy to upgrade, so for instance from Symfony 4.0 to Symfony 4.4 is relatively easy. Once you’re on the last version before a new major, it’s important to check for all deprecations: In case of Symfony, the next major is usually the same as the .4 version, but without the deprecations. So work on getting rid of all deprecations before going to the next major version.

    Whatever you do, use static analysis tools to help you! Running PHPStan will help you catch potential issues. Also, Rector is your friend. It can help you automate fixing issues in your code and upgrading to newer versions of your framework. There are a lot of preset rules to help you in the process of upgrading, and you can extend Rector with your own rules as well for changes specifically needed for your project.

    The result

    If you have the time, the result should be an application that is running on the latest stable version of the framework, including completely adhering to modern code structures etc. However, since this is usually a very big time investment, I see it happening a lot that the upgrade of the project is done, but also refactoring to modern structures and approaches is not done. Which may make economic sense, but may still make the codebase feel a bit clunky and old-fashioned, even if it works and it on the latest and greatest.

    Approach 2: The big bang upgrade

    This second approach is, in my experience, mostly useful when your project isn’t very big or complex. With this approach, you will have to touch most of the code in your project in one way or another. In this approach, instead of doing all the individual steps of the upgrade, you basically start over, but with the code you already have. So, let’s use the same example of a project built on top of Symfony 3.4. Instead of doing the whole flow of Symfony 4, 4.4, 5, 5.4 etc, you just create a fresh new project on Symfony 7.1, then start moving the code from the old project bit by bit into the new project.

    Requirements

    Not surprisingly, the list of requirements for this approach is similar as the previous approach:

    • Good documentation of what the application does, preferably including developers with a lot of experience with this application
    • A good set of tests. Integration tests are the most important in this approach
    • Support of your organization and most importantly, your management

    The good documentation is perhaps even more important in this approach, since the developers working on this upgrade will actually touch all the code in the project. In the first approach, they will mostly touch the integration between custom code and framework. Here, all the code will have to be touched.

    For tests, the most important one may be integration tests. When using this approach you usually not just copy over code, but actually also refactor it to modern code structures and apply newly learned patterns and architecture, unit tests may or may not be very useful. There’s a good chance that the changes in code structure require you to write new unit tests or highly alter existing unit tests. The integration tests, however, are there to test if the application still does what it is supposed to do. So those are the most important in this approach.

    Support from the organization and especially management is actually the same as in approach one, but it is worth mentioning since I’ve really seen projects like this fail because this support wasn’t obtained before starting the project.

    Here we go!

    So… now to get started. You start with a fresh Symfony 7.1 project. In my example, we started with Symfony 3.4 which still had a structure of bundles inside the application code. A good approach is to migrate the bundles to non-bundle src/ code. Be critical of code placement and naming. In Symfony 3.4 times a lot of developers had the inclination to use very technical terms when naming namespaces and classes, while these days even if you don’t do full Domain-Driven Design, it is still common to use domain-based names for namespaces and classes. You don’t have to make these changes but since you’re starting from scratch, it may be worth the little extra effort while you’re copying over code anyway.

    Just like in approach one, PHPStan is your friend. Rector maybe less so although it can still help you with your tasks, but PHPStan will be there to ensure the newly written/copied code is built on modern standards and methodologies.

    Think about what you do. Don’t mindlessly copy over code and adapt it to fit into Symfony 7.1. Focus on building things the way you’d do on a fresh new project. This will make your code a lot more future-proof.

    The result

    When taking this approach, the chances are a lot bigger that at completion of the project, the code is not just “working” but also built according to the latest best practices and standards and is ready for the future.

    Upgraded, and now what?

    So you’ve done the upgrade, whichever approach you took, and now what? The most important is to not get into this situation again. Make sure to stay up-to-date by doing regular upgrades. Make this part of your regular maintenance work. Because small steps are a lot easier than a big jump. And the smaller the step, the easier it is. Since the release schedule of a lot of frameworks and libraries is openly available, you can even schedule most of the work.

    Alternatives

    If you want to stick with the same framework (in this example: Symfony), the above two approaches can work well. But there are alternatives. You can for instance start a new project, run that parallel to your existing application and then carve out specific sets of functionality. This approach can be complex when code hooks into other part of the code. But it will allow you to spread out the effort of upgrading/rewriting over a longer period, which may make it easier for a business to deal with the cost of the project. There is a risk though: I’ve worked for companies that took this approach several times and ended up with 3 or 4 different codebases that each still handled part of the logic.

    Another approach could be… but this will sound scary, to literally throw away everything you’ve done so far and start from scratch. Be really careful when you’re considering this. While this approach will probably deliver the best, most high-quality product at the end of the project, there is a lot of risk involved. Hidden functionality that no-one knows about may be forgotten, and the project may end up being so big that management is not willing to invest any more money into it, resulting in having an even older codebase in production and a half-finished new codebase that will never be used.

    You mention Symfony, but…

    … I use Laravel, CakePHP, Drupal, or another foundation for my software. Well, good news, while I used Symfony as an example here, you can apply these approaches to basically any software project. You don’t even have to use PHP to apply the above.

Previous Page
1 2 3 4 … 60
Next Page

skoop.dev

  • Bandcamp
  • Mastodon
  • Bandcamp