<?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: Daniele Bourgis</title>
    <description>The latest articles on DEV Community by Daniele Bourgis (@thebetterway).</description>
    <link>https://dev.to/thebetterway</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2265987%2F04a16102-f5c0-4f38-ba18-c6ebcaceacc1.png</url>
      <title>DEV Community: Daniele Bourgis</title>
      <link>https://dev.to/thebetterway</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thebetterway"/>
    <language>en</language>
    <item>
      <title>Developing Software with AI: Why Understanding Code Still Matters</title>
      <dc:creator>Daniele Bourgis</dc:creator>
      <pubDate>Sun, 25 Oct 2026 10:14:35 +0000</pubDate>
      <link>https://dev.to/thebetterway/developing-software-with-ai-why-understanding-code-still-matters-3iea</link>
      <guid>https://dev.to/thebetterway/developing-software-with-ai-why-understanding-code-still-matters-3iea</guid>
      <description>&lt;p&gt;Artificial intelligence can help us develop software faster. It can produce an initial implementation, suggest tests, explain unfamiliar code, and assist with debugging. These are practical opportunities whose value depends on the work we need to do.&lt;/p&gt;

&lt;p&gt;But generating code in seconds and delivering a reliable product are two different outcomes.&lt;/p&gt;

&lt;p&gt;The key is learning to use these tools while retaining the ability to understand what they produce. Generated code is a proposal to evaluate. Speed becomes an advantage when you know how to verify the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits of AI Start with a Good Question
&lt;/h2&gt;

&lt;p&gt;Consider a common feature: deleting a document from an application. The request “add a button to delete documents” seems clear. Yet it leaves several questions unanswered.&lt;/p&gt;

&lt;p&gt;Who can delete them? The owner, an administrator, or any authenticated user? Should deletion be permanent? What happens if another user is editing the same document?&lt;/p&gt;

&lt;p&gt;AI can help us identify these questions. The answers, however, must reflect the product’s actual requirements. If we implicitly accept the assumptions embedded in the code, we risk implementing the wrong feature well.&lt;/p&gt;

&lt;p&gt;Software development expertise also means knowing how to turn a request into verifiable rules before choosing classes, components, and libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Project Is More Than the Sum of Its Files
&lt;/h2&gt;

&lt;p&gt;A solution can be correct in isolation yet poorly suited to the application it belongs to. It might duplicate existing functionality, introduce an unnecessary dependency, or mix user interface logic, data access, and business rules.&lt;/p&gt;

&lt;p&gt;Guiding AI therefore requires context: the repository’s structure, conventions, software versions, and the responsibilities of its components. Asking it to “follow best practices” is not enough. We need to understand which choices actually serve the project.&lt;/p&gt;

&lt;p&gt;This does not mean designing elaborate architectures for every problem. Recognizing when a simple solution is sufficient is also a design skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  “It Works on My Screen” Is Only the First Check
&lt;/h2&gt;

&lt;p&gt;A successful demo is useful, but it only tells us about the path we tested. It does not prove that the application handles missing data, network errors, concurrent requests, or unauthorized access.&lt;/p&gt;

&lt;p&gt;GitHub’s documentation warns that generated code can appear valid while containing errors or security vulnerabilities, and recommends reviewing and testing it. This is a practical precaution—even when the AI’s explanation sounds convincing. &lt;a href="https://docs.github.com/en/copilot/responsible-use/inline-suggestions" rel="noopener noreferrer"&gt;GitHub documentation on the responsible use of code suggestions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Compilation remains essential: it catches one category of problems. Correctness against requirements and security need additional checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  A .NET Example: Hiding a Button Does Not Protect a Document
&lt;/h2&gt;

&lt;p&gt;Imagine a Blazor application where only a document’s owner can delete it. The interface correctly hides the button from other users. Everything looks fine during the demo.&lt;/p&gt;

&lt;p&gt;But what check runs when a deletion request arrives?&lt;/p&gt;

&lt;p&gt;Microsoft explains that &lt;code&gt;AuthorizeView&lt;/code&gt; controls the visibility of interface elements; it does not automatically secure the method associated with a button. Authorization must also be enforced in the relevant operation or API. In particular, checks performed in the browser are not a reliable security boundary for protecting server-side data. &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-10.0" rel="noopener noreferrer"&gt;Blazor security documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The requirement to verify is: “An authenticated user can delete only documents they own.” In an ASP.NET Core authorization handler, the core rule might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClaimTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameIdentifier&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identity&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Succeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requirement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an excerpt from a small supporting example, rather than a complete authentication system. The user identifier must come from the authenticated server-side identity. The owner must be read from a trusted resource, rather than accepted from the browser. The authorization result must then be enforced before deletion.&lt;/p&gt;

&lt;p&gt;In the local example, we verified six cases: the authenticated owner was allowed access; another user, an anonymous user, an unauthenticated identity with the same claim, an identity without an identifier, and a different identifier were denied. These checks exercise the rule using ASP.NET Core’s actual authorization service. They do not test an HTTP endpoint, a database, or a complete Blazor application.&lt;/p&gt;

&lt;p&gt;This is where expertise matters: recognizing a missing requirement even when the screen looks correct. In a real application, resource-specific authorization must be integrated into the server-side workflow. &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resource-based?view=aspnetcore-10.0" rel="noopener noreferrer"&gt;Resource-based authorization&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests Deserve a Review Too
&lt;/h2&gt;

&lt;p&gt;AI can help us write tests. But if both the implementation and the tests come from the same mistaken interpretation, they may agree with each other without checking the actual requirement.&lt;/p&gt;

&lt;p&gt;In the previous example, testing only that the owner can delete the document would be insufficient. We also need to verify that another user cannot.&lt;/p&gt;

&lt;p&gt;Expected results must come from the requirements. We can ask AI to identify edge cases, then compare them with documentation, product rules, and observed behavior. A second AI response can assist the review, but it is not proof of correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization Requires Measurement
&lt;/h2&gt;

&lt;p&gt;Shorter code or a more sophisticated solution is not automatically more efficient. To determine whether performance has improved, we need relevant measurements: response times, memory usage, database queries, and behavior under representative workloads.&lt;/p&gt;

&lt;p&gt;Productivity gains should also be assessed across the entire task. How many minutes did we save on writing? How many did we spend fixing, integrating, and reviewing? Will the code be understandable when we next need to change it?&lt;/p&gt;

&lt;p&gt;We should avoid promises of faster development that supposedly apply to every project. In its February 2026 update, METR considers greater benefits than those observed in its 2025 study likely, but highlights experimental limitations that prevent reliable estimates of their size. Context matters. &lt;a href="https://metr.org/blog/2026-02-24-uplift-update/" rel="noopener noreferrer"&gt;METR update&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beginners Can Use AI—with a Method
&lt;/h2&gt;

&lt;p&gt;You do not need to know everything before getting started. AI can support learning by explaining an error, suggesting an exercise, or comparing two solutions. It is useful to ask why a particular choice is appropriate, modify it, and check what changes.&lt;/p&gt;

&lt;p&gt;The warning sign comes when we accept code we cannot explain and keep adding fixes without understanding their effects.&lt;/p&gt;

&lt;p&gt;We do not need to memorize every API. We need sufficiently strong foundations to find our way, consult reliable sources, and recognize when a more experienced reviewer is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Checklist Before Accepting AI-Generated Code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Have I clarified the expected behavior, including errors and permissions?&lt;/li&gt;
&lt;li&gt;Do I understand the main design choices and how they fit into the project?&lt;/li&gt;
&lt;li&gt;Have I checked APIs, dependencies, and compatibility with the versions in use?&lt;/li&gt;
&lt;li&gt;Have I compiled the code and run relevant checks, including negative test cases?&lt;/li&gt;
&lt;li&gt;Are performance claims supported by measurements?&lt;/li&gt;
&lt;li&gt;Could I diagnose a problem or modify this solution later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Responsibility for the product remains with the people who build and deliver it. Using AI well means delegating tasks while retaining the judgment needed to evaluate the outcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What check do you never skip before accepting AI-generated code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TheBetterWay — Blazor, C#, and .NET, one lesson at a time.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is the English translation of &lt;a href="https://thebetterway.it/2026/10/23/sviluppare-intelligenza-artificiale-conoscere-codice/" rel="noopener noreferrer"&gt;the original Italian article published on TheBetterWay&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
