My First Remote Workshop at SymfonyOnline 2026

Short reflection

On 20th January I had the chance to run a workshop during SymfonyOnline 2026, titled refactoring towards Clean Architecture.
What made this session special for me was the fact that it was my very first remote workshop ever.

Going into it, I honestly expected around 10–15 participants. Instead, almost 25 people showed up, which was both surprising and incredibly motivating. Even more important than the number was the level of engagement — lots of thoughtful questions, real-life problems, and open discussions around legacy code, boundaries, and architectural trade-offs.

Running a remote workshop is very different from speaking on stage. You don’t see the whole room, you don’t feel the same energy — or at least that’s what I was afraid of. In reality, the interaction, questions, and feedback made it feel very alive and dynamic.

Of course, it wasn’t perfect. There are a few things I already know I want to improve next time — pacing, timing of exercises, and some technical details. But overall, for a first remote workshop, it went surprisingly well, and I’m genuinely proud of how it turned out.

Thank you 🙌

I want to say a huge thank you to everyone who joined the workshop.
Your questions, openness, and willingness to discuss real-world problems made this session truly valuable and enjoyable for me as a trainer.

Big thanks as well to the SymfonyOnline team for the trust and the opportunity to run this workshop.
It was a great experience — and definitely not the last one.

Questions & Answers from the workshop

During the workshop, a lot of great questions were asked.
Below you’ll find all of them collected in one place, together with my answers, so you can come back to them anytime. Bear in mind that these are just my suggestions. As I said in the workshop 👉 in the software architecture, everything is a trade-off, so keep that in mind!

I think it’s not a realistic starting point. You’re refactoring from an already well set up project. Most of the application out there are not so well structured from the start. What if you’re dealing with a messy monolith? Do you first refactor to remove front-end code (templating, symfony-ux, …) to be in the same case and then refactor to clean architecture?

In the APP that we were working on, the UI was JSON, as it was an API. But, you can apply same principles to project that is a regular HTML. The problem will be with testing – you will need to the through the UI, to have the safety net. Your primary adapter will be the place where the HTML code will be produced.

It seems we’ve focussed on covering comment creation with ‘functional’ tests. Is this the recommendation when refactoring versus at the unit/molecular level, i suppose those kinds of tests are less resilient to the changes we’ll be making?

It is recommended to write a functional test, as this works as a safety net for refactoring. Later, with introduction of proper layering, you can keep one functional test as happy path, and test the layers via unit tests.

Do you usually add more assertions to this test, like:

self::assertSame(‘Nice article.’, $payload[‘comment’][‘body’]);

It is up to you how do you write assertions, as long as they cover the code and they are proper safety net.

Longer term do you recommend bringing fixture/entity creation closer to the tests? Currently the tests are expected to somehow know a fixture exists with the reference ‘test-article-user-first’?

Fixtures are nice for start, but in more complex project they become a problem, therefore I can recommend a builder pattern. This allow to have flexibility like ArticleBuilder::new()->withSlug(‘test’)->build()

Have you ever had problem with this new structure when upgrading projects (recipes, …) ?

Not yet, but I think that depends on the recipes.

Do you keep existing tests as is or do you restructure them also to map the new code structure ? For exemple with a new “testClean ” namespace also

In one medium size project we did testsClean, to have new tests on the side. It is optional.

Why have we introduced comments repository interface here; can’t we directly use DoctrineCommentsRepository?

This way you would break The Dependency Rule, you read more about it in the Uncle Bob article: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

Can a UseCase use another UseCase? or it’s a no-no?

Of course, you can create a composite UseCase that will use other use cases 😀

Where should we log, in which layer?

For logging I can recommend using the PSR interface – and treat it as shared component – it can be used on any layer where needed.

Going back to the conversation we were just having on use cases, comment entities etc.

Is the relationship between a controller and a use case, is it 1:1?

Could a controller leverage multiple use cases, for example, the comment controller depends on FindArticleBySlugCase and a CreateArticleCommentUseCase? Is this bad practice?

I can recommend discussing this with peers, either use multiple use cases in the controller, or create a composite use case for that purpose 😀

Can you please briefly summarize one more time what we did in the last step with CreateCommentHttpController? So, why we did it?

This is the introduction of the Primary Port and Primary Adapter. The Primary Port is an interface extracted from the Use Case. The Primary Adapter is the HTTP controller, which adapts the HTTP Request/Response to the Use Case needs. This taken from the Ports & Adapters aka Hexagonal architecture. You can read more here: https://herbertograca.com/2017/09/14/ports-adapters-architecture/#more-8817

How broad/narrow should the functionality of a use case be defined? e.g. CreateArticleComment vs ManageArticleComments (i.e. might include other comment ops, not just creation).

It should comply with the S from SOLID – Single Responsibility Principle, or Single Reason to Change. Consequently I can recommend sticking with option A.

Is there a need (or example) for multiple different implementations of a primary use case? They rely on secondary port interfaces, does that give us the flexibility we need?

There will be only one implementation in the production code, always, there could a fake/mock/stub in the tests as well. The whole point of the introduction of that interface, is to have an abstraction over the Use Case/Application layer, so we can leverage The Dependency Rule, you can read more about it here: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

So, Hexagonal architecture is clean architecture applied to each identified bounded context of an app?

No, Clean Architecture borrowed the ideas from the Hexagonal architecture (the idea of ports and adapters).

flush() is called inside the save/delete methods of the secondary adapter implementations.

Do you do that the same way in complex projects?

In my view, this breaks the Unit of Work pattern, because flush() implicitly commits all changes accumulated in the EntityManager, not just the current entity. This can lead to unintended side effects, trigger persistence-related behavior at unexpected moments, and reduce control over transaction boundaries at the use-case level. As a result, transactions have to be introduced manually where Unit of Work could otherwise handle them naturally, leading both to extra implicit commits and additional explicit transaction management.

Yes, in the project that we were working on it was not a problem, but in more complex it could. There are many possible solutions to that, via event listener, via middleware, etc.

How should events and event listeners that are highly coupled with framework (Doctrine event listeners for example) be handled? In which layer should they be? Should they be somehow decoupled from framework?

They are already coupled to Doctrine, so keep that in the Framework layer 😊 We went over it at the end of the workshop.

Do you keep only entities in the Domain layer, or do you also include domain services? In which cases do you consider it appropriate to place a service in the Domain layer?

If you need domain service, go for it. As I said, we didn’t dive deep into DDD here, we would need one more day 😅

Additional materials

For those who would like to go deeper, here are some extra materials I personally recommend:

🗂️ Slides 👉 https://speakerdeck.com/ddziaduch/refactoring-towards-clean-architecture-workshop-symfony-online-2026

💻 Repository & workshop branch

This is the repository we worked on during the workshop, including the exact branch used in the exercises:

👉 Repository: https://github.com/ddziaduch/refactoring-towards-clean-arch-workshop

👉 Workshop branch: sf-online-2026

📚 Books

My talk about Framework Agnostic – a presentation about Clean/Hexagonal architecture.

The Software Architecture Chronicles – a series of post by Herberto Graca about the evolution of the architecture.

The Deptrac tool – the static analysis tool I showed

Final thoughts

Once again, thank you for taking part in the workshop and for the great atmosphere.
I hope the ideas and tools we covered will be useful in your day-to-day work.

Best of luck applying them in your projects — and hopefully see you again at another conference or workshop 🙂

From Monolith to Modularity – My Talk at the Fyul Tech Day

This summer I had the chance to speak at our internal engineering conference, and wow, what an experience! The room was completely packed (even our CTO joined 😱), and we actually ran out of time due to the number of questions and discussions. That’s probably the best kind of problem to have.

My talk was titled From Monolith to Modularity: How Deptrac Helped Us Break the Monolith”, and it told the story of how our team took a growing, hard-to-maintain PHP codebase and started turning it into a well-structured modular monolith, by using bounded contextsclean architecture, and most importantly, Deptrac.

Continue reading From Monolith to Modularity – My Talk at the Fyul Tech Day

🚀 A big step – my workshop at SymfonyCon 2025 in Amsterdam!

I’m truly excited to announce that my workshop Refactoring Towards Clean Architecture has been selected for this year’s SymfonyCon 2025 in Amsterdam!

This is a huge milestone for me because:

  • I’ve never spoken at an international conference before,
  • I’ve never been part of an event of this scale,
  • and this will be the very first time presenting this workshop at a conference – so far, I’ve only delivered it once, at Masterlease.

Funny coincidence: I actually received the confirmation email that I got accepted to SymfonyCon while I was giving a talk at our internal company conference 😆 On the one hand, I was over the moon with happiness; on the other hand, my imposter syndrome immediately kicked in 😂

I’ve worked hard to build my credibility as a speaker – you can find all my talks here.

I can’t wait to meet the Symfony community in Amsterdam and share my knowledge 🎉

ZSA Voyager – buying & waiting

Hello there 👋🏻. Welcome to the second part of my article series about the keyboard. This time I would like to describe the buying, awaiting till to unboxing the product. So, as you know from the first article in this series, I decided to buy a split columnar keyboard, which is ZSA Voyager.

All articles in this series:

  1. Why I switched to the split columnar keyboard
  2. ZSA Voyager – buying & waiting
  3. ZSA Voygare – unboxing and the first impressions
Read more: ZSA Voyager – buying & waiting

Why ZSA? It is one of the most known companies that produce ergonomic keyboards. They are quite an established company, which sells plenty of keyboards. They started in 2015. Besides the Voyager, they also have different split keyboards like Moonlander Mark 1 and Ergodox EZ 🧑‍💻

ZSA Ergodox EZ

When you visit the ZSA website, you will find a beautiful, intuitive website that clearly shows what you can expect when you buy their product. There is a comparison tool that will help you to choose a proper keyboard. Lastly, I would like to mention the printables. Ah, they are amazing – just print the keyboard on paper and try it on your own to see whether it will fit your hands 🙌.

Although I could end up here, I would like to emphasize the rest of their webpage, which is packed with information, about the switches, keycaps, layouts (like Dvorak, Colemak), ergonomics etc. Finally, it is worth mentioning their blog where you can find a lot of interviews with people who bought their keyboards. I found such information very valuable and they made me confident before buying 🎯.

Before finishing this short article, I move on to focus on the purchase experience. In the checkout process, there is a field that allows you to add any notes/questions to your order. I wrote that I am concerned about the usage of the laptop keyboard vs the Voyager. I had doubts that I wouldn’t be able to use the regular old-fashioned keyboard. To my surprise I’ve received a response from the company CEO, here it is:

As you have to wait for the keyboard quite long (the delivery took around 20 days), the company sends multiple emails with an introduction to their software and the customization. They even encourage us to make the first changes in the keyboard layout, as it is doable without the keyboard itself via Oryx software.

Stay tuned for the next part where I will cover the unboxing and the first impressions!

Senior Software Engineer – what next?

Hello there! I am a Software Engineer with 13 years of experience. Last year I felt the need to do something with my career to not die as a Senior Software Engineer. Although staying in such a position is fine for most people. So I started doing presentations and sharing the knowledge, but without any concrete plan. This year I want to approach the problem differently.

The main image by Arek Socha from Pixabay.

So, what to do next?

Continue reading Senior Software Engineer – what next?

Sleeping – what I have learned

Time for a new episode of what I have learned! 🎬


Wanna be better? Sleep more 💤 During the last few years, I discovered that sleeping eight hours works best for me.
Focused more and much more productive I am 💪
I have tried sleeping less than six hours plus naps. It worked well till I missed the nap. Waking up was hard 😓
Monitoring your sleep is vital. Many researchers say that it is easiest to wake up in the REM, and I can confirm that ✅
That is why I switched recently from 7.5 to 8 hours. I missed the zone.
Now I can wake up and almost instantly jump into the action.


Sleep well 🙂

Improving the tests with try-finally block

This week I have learned a neat trick that you can apply to your test cases. You are testing an edge case. The system under test is expected to throw an exception. But, after the exception, you need to do a few assertions. Usually, I did it this way:

/**
 * @dataProvider markAsUndeliverableFailDataProvider
 */
public function testMarkAsUndeliverableFail(Order $order): void
{
    $exception = null;

    try {
        $order->markAsUndeliverable();
    } catch (\Throwable $exception) {
    }

    self::assertInstanceOf(OrderStatusChangeFailed::class, $exception);
    self::assertTrue($order->isAlreadySentToProduction());
}

But, there is a better way to do it! Check out the much more readable version with try-finally:

/**
 * @dataProvider markAsUndeliverableFailDataProvider
 */
public function testMarkAsUndeliverableFail(Order $order): void
{
    $this->expectException(OrderStatusChangeFailed::class);

    try {
        $order->markAsUndeliverable();
    } finally {
        self::assertTrue($order->isAlreadySentToProduction());
    }
}

Viola! Look how clean this is 🔥

Sytuacja w IT a COVID – przemyślenia

Cześć! Żyjemy już dość długo w świecie pandemicznym. Tym razem opiszę swoje przemyślenia o tym jak COVID wpłynął na branżę IT. W tym wpisie przedstawię moje obserwacje oraz przemyślenia w trzech etapach. Na końcu znajdziesz podsumowanie, gdzie subiektywnie podsumowuję całość.

Świat IT przed pandemią

Jeśli pracujesz/pracowałeś w IT to wiesz jak to było. Zdecydowana większość pracodawców nie zgadzała się na pracę zdalna. Czemu? Bo przecież pracownik w domu, zamiast pracować, będzie zajmować się wszystkim, byle nie pracą.

Continue reading Sytuacja w IT a COVID – przemyślenia

Wpływ silence operatora na error reporting w PHP

Hej, w dzisiejszym krótkim wpisie bierzemy na tapet słynny i jakże często używany operator @ tzw. STFU. Czy wiesz że jego użycie ma wpływ na error_reporting w PHP? Weźmy pod lupę ten przykład:

<?php declare(strict_types=1);

error_reporting(E_ALL);

set_error_handler(
    function () {
        // int(0) [PHP <= 7.4]
        // int(4437) [PHP >= 8.0]
        var_dump(error_reporting());
    },
    E_ALL
);

// int(32767) [E_ALL]
var_dump(error_reporting());

@trigger_error('warning', E_USER_WARNING);
Continue reading Wpływ silence operatora na error reporting w PHP

Moje dwa lata z Huel – subiektywna recenzja

Hej! Dzisiaj temat kompletnie niezwiązany z programowaniem, czy IT. W kwietniu 2021 minęło dokładnie dwa lata od kiedy pierwszy raz zamówiłem Huel. Produkt, który zmienił moje nawyki żywieniowe, i pozwolił mi prowadzić zdrowszy tryb życia. Postaram się opisać wszystkie swoje spostrzeżenia. Myślę, że przez ponad dwa poznałem produkt dobrze.

Continue reading Moje dwa lata z Huel – subiektywna recenzja