Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Neos Con 2025

Neos Con 2025

Avatar for Fiach Dillon

Fiach Dillon

June 20, 2025
Tweet

Other Decks in Technology

Transcript

  1. Hello eos Con Fiach Louis Dillon Senior Software Engineer 1&1

    Telecommunication SE "A good story, like good code, always finds its structure."
  2. Signs of a Mess – It Was Always There Mr.

    Messy lived in a particularly messy-looking house. The paint was peeling—just like his PHP code, full of syntax errors and no linting to catch them. The windows were broken—like his Fusion templates, unpredictable and nearly impossible to debug. There were tiles missing from the roof—much like the nodetype inconsistencies in his project, where some pages loaded fine, and others failed completely at random. The flower beds were overrun with weeds, and the garden gate hung off its hinges—a perfect metaphor for his lack of testing, where every fix introduced more bugs than it solved. And had Mr. Messy cut the grass lately? He had not!
  3. The Breaking Point – When Everything Falls Apart Mr. Messy

    rolled out of his messy bed, yawned, scratched, and shuffled into the chaos of his usual routine. He brushed his teeth—leaving the cap off the toothpaste, just like he'd been leaving syntax errors all over his messy PHP code. At breakfast, he poured himself a bowl of cereal—cornflakes flew everywhere, much like his Fusion templates, scattering unpredictable errors with every render. Heading out the door, he tripped over a broom he’d left lying in the yard two weeks ago. That broom? Technical debt—ignored and waiting to strike at the worst possible moment. But Mr. Messy wasn’t just stumbling through his morning— It was Launch Day.
  4. Discovery – A Glimpse of What’s Possible Mr. Messy went

    for a stroll and found the neatest, prettiest-looking little cottage he had ever seen. It had a lovely yard with a stream running right through the middle—a smooth CI/CD pipeline, perhaps? There was a man in the yard, clipping the hedge with precision. As Mr. Messy approached, he said, “Good morning! I’m Mr. Messy!” The man looked him up and down and replied, “I can see that. I’m Mr. Tidy.” Then another man appeared from the house, holding a clipboard and a lint report, “And I’m Mr. Neat.” “Tidy and Neat,” said Mr. Tidy. “Neat and Tidy,” said Mr. Neat. Together, they were everything Mr. Messy wasn’t—order, clarity, and care.
  5. The Offer – Resistance to Change “We’re in business together,”

    explained Mr. Tidy. “And the people who own this house asked us to do some work.” “What sort of work?” asked Mr. Messy. “Oh, we make things nice and neat,” said Mr. Neat, flicking a speck of dust off his PHPStan manual. “Tidy things up,” added Mr. Tidy, holding a folder labeled CI/CD Pipelines – Jenkins. “Perhaps we could come along and do some work for you?” Mr. Neat offered, eyeing Mr. Messy, who looked even more unstructured and untested than usual that morning. “But I don’t want things neat and tidy,” muttered Mr. Messy, looking downright miserable at the thought of it. The very idea of linting Fusion files, YAML schema validation, unit tests, and automated pipelines made him twitch.
  6. Intervention – Time to Clean Up “Nonsense!” said Mr. Tidy,

    pulling on his Jenkins gloves. “Fiddlesticks!” said Mr. Neat, tucking a PHPUnit test report into his toolbelt. “But…” Mr. Messy tried to argue. “Come along,” said Mr. Neat, pulling out a USB stick labeled Playwright E2E tests. “Off we go,” said Mr. Tidy, opening the doors to their code-cleaning van, humming with Fusion.Tracing dashboards. “But… but…” Mr. Messy stammered. “But nothing,” said Mr. Neat. Before Mr. Messy could even write another untested function, they’d bundled him into the van and were off— Heading straight to his project at the other side of the wood.
  7. First Impressions – Code Review Panic “Good heavens!” said Mr.

    Neat when they arrived. “Good gracious me,” added Mr. Tidy. “This is the messiest house—er, codebase—I’ve ever seen in all my born days,” they both said at the same time. There were inline scripts tangled like weeds, Fusion templates with zero linting, and YAML files yelling in syntax agony. “Better do something about it,” said Mr. Neat, already unpacking the Neos Code Styles formatter. Before Mr. Messy could even open his mouth, they were rushing here and there— running PHPStan, validating schemas, snapshotting layouts, and setting up the first Jenkins job he’d ever seen.
  8. Refactoring Begins – Mr. Neat Gets to Work Mr. Neat

    hoed through outdated YAML configs, mowed down wild, overgrown Fusion structures, and pruned unnecessary HTML wrappers. He clipped duplicated PHP functions and old, forgotten classnames. He cleared performance bottlenecks using Fusion.Tracing and Neos.Debug, and dug deep into layout rendering with Snapshot testing. He set up functional and unit tests with PHPUnit and Fixtures, then handed the clean code pipeline over to Jenkins with a satisfied smile. By the time he was done, the yard—er, frontend—looked better than ever: Fast, clean, and stable.
  9. Backend Overhaul – Mr. Tidy Gets to Work Mr. Tidy

    cleaned up the controllers, scrubbing away years of tangled logic. He rubbed through every config file, aligning them with YAML schema validation. He primed and mended broken endpoints, added type safety checks with PHPStan, and enforced Neos Code Styles for clarity. Then he painted the codebase with clean comments, refactored classes, and beautifully structured modules. By the time he was done, the outside of Mr. Messy’s codebase—the foundation, the APIs, the data flow—looked more solid, consistent, and maintainable than it ever had before. Mr. Messy peeked out and blinked. He barely recognized his own backend.
  10. Full Stack Clean-Up – Inside the Codebase Then they both

    stepped into the house. “Good heavens!” said Mr. Neat—for the second time that morning. “Good gracious!” echoed Mr. Tidy—also for the second time. And without another word, they set about cleaning the house from top to bottom. They brushed through templates using Fusion Linting. They swept away duplicate and unreachable code. They polished the UI with Snapshot validation and Playwright E2E tests. They scrubbed business logic and added PHPUnit functional tests. They even optimized performance with Fusion.Tracing. And wired it all together in a neat, reliable CI/CD pipeline with Jenkins. By the time they were done, the inside of Mr. Messy’s house—his codebase—looked neater, faster, and more maintainable than it had ever looked before.
  11. The Transformation – It’s Done “There we are,” said Mr.

    Tidy, wiping Jenkins dust from his gloves. “All finished,” said Mr. Neat, closing his laptop with the last successful test run glowing green. “Tidy and neat,” smiled Mr. Tidy, gesturing at the polished codebase.' “Neat and tidy,” nodded Mr. Neat, admiring the structured, fast-loading site. • The garden was green, the house was pristine, and the codebase? Clean, fast, and predictable. • The code was linted and formatted. • Tests were all passing—unit, functional, and E2E. • The CI/CD pipeline was running smoothly. • Performance metrics were clean and optimized. • Pages loaded in milliseconds. Mr. Messy looked around—at the stable site, the readable code, the clean structure— and for once in his messy life… he just didn’t know what to say.
  12. 🧹 PHP Linting & Static Code Analysis What it does:

    Analyzes PHP code for type issues, undefined methods, unreachable code. Prevents: • Silent runtime failures • Sloppy, untyped legacy code Why it’s good: • Catches bugs early • Makes your PHP codebase safe, testable, and easier to refactor 🔖 https://phpstan.org/user-guide/getting-sta
  13. 🧹 PHP Linting & Static Code Analysis 🔖 https://phpstan.org/user-guide/getting-sta //

    ❌ Undefined property echo $user->fullname; // ✅ Correct property echo $user->displayName; // ❌ No return type function getName() { return $this->name; } // ✅ Typed return function getName(): string { return $this->name; }
  14. 🎨 Fusion Linting What it does: Enforces formatting and Fusion

    best practices Prevents: • Inconsistent Fusion files • Presentation components being misused or non-reusable Why it’s good: • Cleaner templates, fewer rendering surprises • Better collaboration on frontends 🔖 https://github.com/cvette/neos-code-style
  15. 🎨 Fusion Linting 🔖 https://github.com/cvette/neos-code-style ------------------------------------------------------------------------------ File ...ckages/BaseComponents/Resources/Private/Fusion/Content/Button/Presentation/ Button.fusion ==============================================================================

    1 | ERROR | Presentation prototype is "Neos.Neos:ContentCollection" but has to inherit from one of: Neos.Fusion:Component prototype(Site.BaseComponents:Button) < prototype(Neos.Neos:ContentCollection) { renderer = afx`<button class="primary">{props.label}</button>` }
  16. 📑 YAML Linting (Schema/Core) What it does: Validates your NodeTypes

    and settings configs Prevents: • Invalid childNodes, broken help messages, rendering bugs Why it’s good: • Ensures structure is predictable • Makes editor UI work as intended 🔖 https://github.com/Sebobo/Shel.Neos.Schema
  17. 📸 HTML/Fusion Snapshot Testing What it does: Captures output of

    templates to detect unexpected changes Prevents: • UI drift • Layouts silently breaking Why it’s good: • Makes Fusion rendering predictable • Confidence in visual stability 🔖 https://github.com/suffle/Suffle.Snapshot
  18. 📸 HTML/Fusion Snapshot Testing @snapshot { props { href =

    'neos.io' classes = 'link-class' } propSets { 'targetBlank' { target = '_blank' } } <a href="neos.io" class="link-class">Link</a> <a href="neos.io" target="_blank" class="link-class">Link</a> 🔖 https://github.com/suffle/Suffle.Snapshot
  19. 🧪Unit Testing (PHP) What it does: Tests logic in isolation

    Prevents: • Logic bugs • Breaking core functionality without knowing Why it’s good: • Fast feedback • Easier to refactor safely 🔖 https://phpunit.de/index.html
  20. 🧪Unit Testing (PHP) public function testJobOfferEncodesAllValues(string $fieldName, mixed $inputValue, mixed

    $expec tedValue): void { $arguments = [ 'title' => 'Backend Developer (m/f/d)', 'jobId' => '1234-en_US', 'jobLink' => 'https://example.org/job-invite/1234/?locale=en_US', 'addressCitys' => ['Sampletown'], 'contractType' => 'Permanent', 'workingTime' => 'Full-time', 'companyName' => 'Example Corp', 'imageId' => '01' ]; $arguments[$fieldName] = $inputValue; $offer = JobOffer::create(...$arguments); self::assertEquals($expectedValue, $offer->{$fieldName}); } 🔖 https://phpunit.de/index.html
  21. 🧩 Functional Tests (PHP & Fusion) What it does: Tests

    how backend logic affects page rendering Prevents: • Pages failing silently • Bad rendering after content creation Why it’s good: • Confidence that content flows correctly • Catches schema vs. output mismatches
  22. 🧩 Functional Tests (PHP & Fusion) protected string $rootFusionPattern =

    __DIR__ . '/Fixtures/Root.fusion'; protected ?string $fixtureFileName = 'Fixtures/NodeStructure.xml'; protected ?string $nodeContextPath = '/sites/vendor-site'; public function testCreatedSectionHeadlineMinimal(): void {  $sectionHeadlineMinimalNode = $this->createNodeWithProperties(   'NodeTypes : Content.SectionHeadlineMinimal',    nodeName : 'section-headline-minimal',    properties: [     'sectionHeadlineMinimal_headline' => 'My headline',     'sectionHeadlineMinimal_subline' => 'My subline',     'sectionHeadlineMinimal_preline' => 'My preline', ], parentNodePath: $this->node->getNode('site/home/main')->getPath(), ); $renderedNode = $this->simulateRendering(  fusionPath : 'renderCurrentNode',  nodePath : $sectionHeadlineMinimalNode->getPath(), ); self::assertTrue(str_contains($renderedNode, 'My headline'), 'Headline not found in rendered markup'); self::assertTrue(str_contains($renderedNode, 'My subline' ), 'Subline not found in rendered markup'); self::assertTrue(str_contains($renderedNode, 'My preline' ), 'Preline not found in rendered markup'); }
  23. 🌐 End-to-End Testing What it does: Simulates real user flows

    — like logging into the CMS, creating content, and verifying it's live Prevents: • Critical workflows breaking after deployment • UI inconsistencies across browsers or environments Why it’s good: • Catches regressions before your users do • Tests full flow: login → content → publish → frontend • Validates things unit & functional tests can’t reach 🔖 https://gauge.org/index.html
  24. 🌐 End-to-End Testing ## Scenario: Login to CMS and create

    a new blog article * Call the URL "https://cms.cloud.io/neos/" async function createAndPublishBlogArticle(url) { let page = await openBrowser(); // Login to the CMS // Go to the blog section // Create a new blog article // Fill in the article details // Publish the article    // Call Website with new blog article } 🔖 https://gauge.org/index.html
  25. 🚦Performance (Fusion Tracing/Debug) What it does: Visualizes rendering paths and

    bottlenecks Prevents: • Slow pages due to hidden Fusion complexity • Render loops or expensive queries Why it’s good: • Optimize what actually matters • Improves user and editor experience 🔖 https://github.com/Flowpack/Flowpack.Fusion.Tracing 🔖 https://github.com/Flowpack/neos-debug
  26. ⚙ CI/CD Automation What it does: Automates testing and deployment

    pipelines Prevents: • Manual errors • Unreviewed code going live Why it’s good: • Reliable builds, quality delivery • Test, lint, and deploy with confidence
  27. ⚙ CI/CD Automation pipeline { agent any stages { stage('PHP

    Linting') { steps { sh '.bin/phpstan' } } stage('Fusion Linting') { steps { sh './neoscs.phar -c neoscs.yaml' } } stage('YAML Linting') { steps { sh './validate.js -v validate path-to-neos-project' } } stage('Static Checks') { steps { echo '✔ All good!' } } stage('Snapshot Tests') { steps { sh './flow snapshot:takeall' } } stage('Unit Tests') { steps { sh 'composer run unit-tests' } } stage('Functional Tests') { steps { sh 'composer run functional-tests' } } stage('E2E Tests') { steps { sh 'gauge run specs' } } stage('Performance Check') { steps { echo 'Trace & optimize' } } stage('Deploy or Fail Fast') { steps { echo '🚀 Deploying…' } } } }
  28. 🔮 Future Tools & Ideas – Continuing the Journey 🧩

    Fusion Static Code Analysis (Catch issues early) 🧱 Prototype Analyzer for Fusion (Visualize. Inspect. Optimize) 📊 Profiler & Performance Insights (Focus where it matters) 💡 Query Sandbox for the CR (Powerful queries, deep insights.) 🛡 Sheriff for Neos (Governance meets automation)
  29. The Final Bug – Mr. Messy Himself Mr. Messy just

    didn’t know what to say. The project was clean. The site was fast. The logs were quiet. Then Mr. Neat and Mr. Tidy turned to look at him. “Are you thinking what I’m thinking?” Mr. Neat asked, adjusting his Fusion code linter. “Precisely,” replied Mr. Tidy, glancing at his PHPStan rule set. Then they both turned to Mr. Messy. “What we’re both thinking,” they said together, “is that you look much too messy to live in a neat and tidy codebase like this!” Mr. Messy’s eyes widened. “But…,” he said, clutching his old habits, “…what about my quick fixes? My random commits? My late-night hotpatches?!”
  30. The Developer Refactor – Mr. Messy Gets Cleaned But whatever

    Mr. Messy said was no use. Mr. Neat and Mr. Tidy whisked him off to the bathroom upstairs once the messiest room in the house, now spotless thanks to clean configs and automated tests. Then Mr. Neat grabbed one arm (still holding a manual deploy script), and Mr. Tidy grabbed the other (clutching a stack of unchecked TODOs), and they dropped him straight into the bath. In went the linters, out came the unit tests, followed by a good scrub of CI/CD best practices. Mr. Messy wasn’t used to baths… …or to writing clean, testable code.
  31. Transformation Complete – A New Mr. Messy? Mr. Neat and

    Mr. Tidy washed and brushed, cleaned and scrubbed, combed and linted until Mr. Messy didn’t look messy at all. In fact—he looked the opposite of messy. His code was clear. His commits were clean. His tests were green. He stared at himself in the mirror, eyes wide. “You know what I’m going to have to do now?” he said in a rather fierce voice. Mr. Neat and Mr. Tidy froze. Had they pushed him too far? Was he about to revert to main without review?
  32. A New Name – And a New Way of Working

    "What are you going to have to do?" they asked Mr. Messy. "I'm going to have to change my name!" said Mr. Messy. And then he chuckled. And Mr. Neat and Mr. Tidy chuckled. And then Mr. Messy laughed. And Mr. Neat and Mr. Tidy laughed. And then they all laughed together and became the best of friends. And that really is the end of the story, except to say that if you're a messy sort of person, you might just get a visit from two people— Mr. Neat and Mr. Tidy, who’ll help you clean up your code and your workflow.
  33. Running on eos 🛒 Customer Portals 🏪 Main Website (https://www.1und1.de/)

    🛒 DSL Portal (https://dsl.1und1.de/) 📱 Mobile Portal (https://mobile.1und1.de/) 🔐 Customer Login (https://kunden.1und1.de/) 🏢 Company & Careers 🏢 Company Info (https://unternehmen.1und1.de/) 💼 Careers (https://karriere.1und1.de/) 🌐 Partner Program 🌐 Profiseller (https://www.profiseller.de/)