<?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: LkSvn</title>
    <description>The latest articles on DEV Community by LkSvn (@lksvn).</description>
    <link>https://dev.to/lksvn</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%2F205286%2Fd72b44d2-fe1e-45a9-acef-646a13cf818b.gif</url>
      <title>DEV Community: LkSvn</title>
      <link>https://dev.to/lksvn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lksvn"/>
    <language>en</language>
    <item>
      <title>Every Layer Must Earn Its Place</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Sat, 01 Aug 2026 01:26:50 +0000</pubDate>
      <link>https://dev.to/lksvn/every-layer-must-earn-its-place-56pe</link>
      <guid>https://dev.to/lksvn/every-layer-must-earn-its-place-56pe</guid>
      <description>&lt;p&gt;While starting a practical transition into C# and ASP.NET Core, I found that a&lt;br&gt;
simple endpoint was becoming harder to understand as each concept introduced a&lt;br&gt;
new structural element: endpoint, service, repository, interface, DTO, and&lt;br&gt;
result type.&lt;/p&gt;

&lt;p&gt;Each tool can solve a real problem. The problem is adopting the complete stack&lt;br&gt;
before those problems exist.&lt;/p&gt;

&lt;p&gt;My working rule is now incremental:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with the smallest endpoint that expresses the behavior.&lt;/li&gt;
&lt;li&gt;Extract application behavior when HTTP and business rules begin changing
for different reasons.&lt;/li&gt;
&lt;li&gt;Add a persistence boundary when it protects the application from meaningful
storage concerns or supports valuable test isolation.&lt;/li&gt;
&lt;li&gt;Add interfaces when multiple implementations or a genuine boundary exists.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not anti-architecture. It is architecture proportional to the system.&lt;br&gt;
A modular monolith with clear responsibilities can be safer than a deeply&lt;br&gt;
layered or distributed design whose abstractions mostly forward calls.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Done Is Finally Better Than Perfect</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Tue, 28 Jul 2026 20:51:39 +0000</pubDate>
      <link>https://dev.to/lksvn/done-is-finally-better-than-perfect-2ok6</link>
      <guid>https://dev.to/lksvn/done-is-finally-better-than-perfect-2ok6</guid>
      <description>&lt;p&gt;I finally shipped the first version of my freelance landing page.&lt;/p&gt;

&lt;p&gt;The funny part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I spent weeks thinking I had a design problem.&lt;/li&gt;
&lt;li&gt;I didn't.&lt;/li&gt;
&lt;li&gt;I had a content problem.&lt;/li&gt;
&lt;li&gt;The layout is good enough.&lt;/li&gt;
&lt;li&gt;The copy is good enough.&lt;/li&gt;
&lt;li&gt;The CSS is good enough.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What the page really needs now is more real projects.&lt;/p&gt;

&lt;p&gt;Instead of redesigning it again, I'm going to spend my time replacing concept work with actual client work as it comes in.&lt;/p&gt;

&lt;p&gt;Sometimes the next version isn't another refactor.&lt;/p&gt;

&lt;p&gt;It's simply experience.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://lksvn.com.br/freelance/" rel="noopener noreferrer"&gt;https://lksvn.com.br/freelance/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
      <category>freelance</category>
      <category>portfolio</category>
    </item>
    <item>
      <title>Omitted Is Not Empty: Modeling Nullable Partial Updates</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Mon, 27 Jul 2026 19:19:44 +0000</pubDate>
      <link>https://dev.to/lksvn/omitted-is-not-empty-modeling-nullable-partial-updates-9po</link>
      <guid>https://dev.to/lksvn/omitted-is-not-empty-modeling-nullable-partial-updates-9po</guid>
      <description>&lt;p&gt;While adding Job Opportunity editing to my Candidate Tracker, one optional description produced three different behaviors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;omit the property to preserve the stored value;&lt;/li&gt;
&lt;li&gt;provide a string to replace it;&lt;/li&gt;
&lt;li&gt;provide &lt;code&gt;null&lt;/code&gt; to clear it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first version mixed &lt;code&gt;undefined&lt;/code&gt; and &lt;code&gt;null&lt;/code&gt; across the domain, Prisma adapter, application service, and form action. That made clearing a value ambiguous.&lt;/p&gt;

&lt;p&gt;The final convention uses &lt;code&gt;string | null&lt;/code&gt; for persisted domain entities and optional properties for partial update commands. PostgreSQL &lt;code&gt;NULL&lt;/code&gt;, Prisma &lt;code&gt;null&lt;/code&gt;, and the domain now use the same absence representation. At the update boundary, omission still means “do not change.”&lt;/p&gt;

&lt;p&gt;The broader lesson is that update types describe commands and state transitions. They should distinguish every behavior the application needs instead of merely reusing an entity shape without considering omission.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Tests Should Buy Confidence, Not Become the Feature</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Fri, 24 Jul 2026 20:28:35 +0000</pubDate>
      <link>https://dev.to/lksvn/tests-should-buy-confidence-not-become-the-feature-46ma</link>
      <guid>https://dev.to/lksvn/tests-should-buy-confidence-not-become-the-feature-46ma</guid>
      <description>&lt;p&gt;While implementing the Job Opportunity creation workflow in my Candidate Tracker, I reached an uncomfortable point: the application-service tests felt harder to understand than the feature itself.&lt;/p&gt;

&lt;p&gt;The production workflow was small:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validate and normalize the submitted input.&lt;/li&gt;
&lt;li&gt;Confirm that the selected Company exists.&lt;/li&gt;
&lt;li&gt;Create the Job Opportunity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tests introduced much more vocabulary and setup: fixtures, fakes, spies, mocks, controlled failures, and assertions that certain repository methods were never called.&lt;/p&gt;

&lt;p&gt;That complexity is not automatically a problem. A test must construct the world in which a behavior runs. However, it made me reconsider what each test was actually buying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests I kept
&lt;/h2&gt;

&lt;p&gt;I kept three application-service cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;valid input is normalized and created;&lt;/li&gt;
&lt;li&gt;invalid input stops before persistence;&lt;/li&gt;
&lt;li&gt;a missing Company does not create an orphan opportunity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These cases protect business decisions. If any of them breaks, the application can accept invalid data or violate an important relationship.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tests I did not add
&lt;/h2&gt;

&lt;p&gt;The service also forwards failures returned by repositories. I could mock every repository method and test every forwarding branch, but those tests would mostly prove that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
 {data-source-line="157"}&lt;/p&gt;

&lt;p&gt;returns the same result it received.&lt;/p&gt;

&lt;p&gt;That behavior is already constrained by TypeScript, while real PostgreSQL integration tests verify persistence behavior. The complete browser workflow was also checked manually.&lt;/p&gt;

&lt;p&gt;Adding more mocks would increase the test count, but not necessarily my confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right testing level
&lt;/h2&gt;

&lt;p&gt;My current rule is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unit-test business rules and meaningful decisions;&lt;/li&gt;
&lt;li&gt;integration-test actual persistence behavior;&lt;/li&gt;
&lt;li&gt;verify the complete user workflow;&lt;/li&gt;
&lt;li&gt;add regression tests when real bugs reveal a missing case;&lt;/li&gt;
&lt;li&gt;do not optimize for test count or branch coverage alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not an argument against testing. It is an argument for making every test justify its maintenance cost.&lt;/p&gt;

&lt;p&gt;Tests should reduce the fear of changing code. When the setup becomes harder to understand than the protected behavior, the testing level or scope may need simplification—not necessarily the feature.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>learning</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A Prisma Schema Change Has Three Lifecycles</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Wed, 22 Jul 2026 21:47:40 +0000</pubDate>
      <link>https://dev.to/lksvn/a-prisma-schema-change-has-three-lifecycles-3pcn</link>
      <guid>https://dev.to/lksvn/a-prisma-schema-change-has-three-lifecycles-3pcn</guid>
      <description>&lt;p&gt;One valid PostgreSQL row refused to appear on my Next.js page.&lt;/p&gt;

&lt;p&gt;The relationship was correct, the SQL join returned the row, and the repository compiled. At runtime, however, Prisma returned an undefined &lt;code&gt;jobOpportunity&lt;/code&gt; relation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stale layer was not the database
&lt;/h2&gt;

&lt;p&gt;I had changed the Prisma schema while the development server was running. That change involved three independent lifecycles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;prisma migrate&lt;/code&gt; updates the database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prisma generate&lt;/code&gt; updates the TypeScript client.&lt;/li&gt;
&lt;li&gt;Restarting Next.js replaces the stale generated client held by the running process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first two steps were complete. The third was not.&lt;/p&gt;

&lt;p&gt;Coming from PHP and CodeIgniter, this is an important mental-model shift. A request-scoped PHP application normally loads changed code on the next request. A long-running Node.js process can keep generated code and development caches alive.&lt;/p&gt;

&lt;p&gt;Prisma provides valuable type safety, but it does not remove complexity—it relocates it.&lt;/p&gt;

&lt;p&gt;My new debugging rule is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application edit → trust hot reload.&lt;/li&gt;
&lt;li&gt;Prisma model change → migrate, generate, restart.&lt;/li&gt;
&lt;li&gt;Suspicious stale behavior → clear the framework cache and restart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before rewriting a correct query, identify which layer is stale.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>prisma</category>
      <category>nextjs</category>
      <category>learning</category>
    </item>
    <item>
      <title>Not Every Productive Day Looks Like Writing Code</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Wed, 22 Jul 2026 01:11:55 +0000</pubDate>
      <link>https://dev.to/lksvn/not-every-productive-day-looks-like-writing-code-91h</link>
      <guid>https://dev.to/lksvn/not-every-productive-day-looks-like-writing-code-91h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Sometimes the most valuable work doesn't produce a single commit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today was one of those days.&lt;/p&gt;

&lt;p&gt;I didn't implement a new feature in my TypeScript project.&lt;/p&gt;

&lt;p&gt;I didn't learn a new framework.&lt;/p&gt;

&lt;p&gt;I didn't even spend much time writing code.&lt;/p&gt;

&lt;p&gt;At first, that felt unproductive.&lt;/p&gt;

&lt;p&gt;But looking back, I realized I spent the day investing in something that will make future work easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Infrastructure Around Development
&lt;/h2&gt;

&lt;p&gt;The first thing I worked on was updating my &lt;code&gt;fresh-install&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;Every time I format my machine or switch computers, I find myself repeating the same setup steps. Automating those tasks doesn't make my GitHub contribution graph greener, but it saves hours every time I need a fresh environment.&lt;/p&gt;

&lt;p&gt;Then I spent several hours reorganizing my personal knowledge base.&lt;/p&gt;

&lt;p&gt;I reviewed old notes, connected documentation from personal projects, organized topics by area, improved tagging, and turned scattered information into something I can actually navigate.&lt;/p&gt;

&lt;p&gt;It wasn't exciting.&lt;/p&gt;

&lt;p&gt;It wasn't glamorous.&lt;/p&gt;

&lt;p&gt;But it felt necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Optimize Applications...
&lt;/h2&gt;

&lt;p&gt;As developers, we spend a lot of time reducing friction for users.&lt;/p&gt;

&lt;p&gt;We optimize APIs.&lt;/p&gt;

&lt;p&gt;We improve application performance.&lt;/p&gt;

&lt;p&gt;We refactor code to make future changes easier.&lt;/p&gt;

&lt;p&gt;But we rarely apply the same mindset to ourselves.&lt;/p&gt;

&lt;p&gt;Why should finding a note from six months ago take longer than searching production logs?&lt;/p&gt;

&lt;p&gt;Why should I rediscover the same solution every few months?&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge Compounds
&lt;/h2&gt;

&lt;p&gt;One thing I've been realizing while working on my &lt;strong&gt;Candidate Tracker&lt;/strong&gt; project is that the code is only part of the learning process.&lt;/p&gt;

&lt;p&gt;The architecture decisions.&lt;/p&gt;

&lt;p&gt;The trade-offs.&lt;/p&gt;

&lt;p&gt;The mistakes.&lt;/p&gt;

&lt;p&gt;The reasons why I chose one approach instead of another.&lt;/p&gt;

&lt;p&gt;Those are often more valuable than the final implementation.&lt;/p&gt;

&lt;p&gt;If I don't capture them somewhere, I'll eventually lose them.&lt;/p&gt;

&lt;p&gt;A personal knowledge base isn't just documentation.&lt;/p&gt;

&lt;p&gt;It's an extension of memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invisible Progress
&lt;/h2&gt;

&lt;p&gt;It's easy to measure productivity by commits.&lt;/p&gt;

&lt;p&gt;It's much harder to measure things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better documentation&lt;/li&gt;
&lt;li&gt;Faster onboarding to your own projects&lt;/li&gt;
&lt;li&gt;Easier environment setup&lt;/li&gt;
&lt;li&gt;Less context switching&lt;/li&gt;
&lt;li&gt;Less time searching for information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These improvements don't show up on GitHub.&lt;/p&gt;

&lt;p&gt;But they compound over time.&lt;/p&gt;

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

&lt;p&gt;Today reminded me that software engineering isn't only about writing code.&lt;/p&gt;

&lt;p&gt;Sometimes the best investment you can make is reducing the friction of tomorrow's work.&lt;/p&gt;

&lt;p&gt;The results may not be visible immediately.&lt;/p&gt;

&lt;p&gt;But future you will definitely notice.&lt;/p&gt;




&lt;p&gt;I'd love to know:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's one "behind the scenes" improvement that has made the biggest difference in your daily workflow?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
      <category>productivity</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Architecture starts paying rent when a user workflow reaches it</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Mon, 20 Jul 2026 20:47:42 +0000</pubDate>
      <link>https://dev.to/lksvn/architecture-starts-paying-rent-when-a-user-workflow-reaches-it-5e81</link>
      <guid>https://dev.to/lksvn/architecture-starts-paying-rent-when-a-user-workflow-reaches-it-5e81</guid>
      <description>&lt;p&gt;My TypeScript Candidate Tracker passed 100 tests before it had a page I could actually use.&lt;/p&gt;

&lt;p&gt;The repository contracts, Result types, validation services, Prisma adapter, and PostgreSQL integration all had value—but the project still felt like it was walking in place.&lt;/p&gt;

&lt;p&gt;Today I changed direction and connected one complete Company workflow to Next.js:&lt;/p&gt;

&lt;p&gt;FormData from the browser&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runtime shape validation&lt;/li&gt;
&lt;li&gt;business validation&lt;/li&gt;
&lt;li&gt;application service&lt;/li&gt;
&lt;li&gt;repository&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;refreshed Server Component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same application now lists, creates, displays, and edits real persisted Companies.&lt;/p&gt;

&lt;p&gt;Several earlier decisions finally became concrete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browser validation improves UX but cannot protect the server&lt;/li&gt;
&lt;li&gt;successful database absence becomes an explicit not-found outcome&lt;/li&gt;
&lt;li&gt;Server Actions are real public input boundaries&lt;/li&gt;
&lt;li&gt;a shared Prisma client matters under development hot reload&lt;/li&gt;
&lt;li&gt;database-generated UUIDs work beyond Prisma Client, including Studio and raw SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lesson was not that architecture is useless. It was that architecture needs a consumer.&lt;/p&gt;

&lt;p&gt;Once a real user workflow crossed every layer, the abstractions stopped feeling theoretical and started explaining their cost.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>learning</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Stronger application-layer types remove impossible states</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Sat, 18 Jul 2026 17:00:00 +0000</pubDate>
      <link>https://dev.to/lksvn/stronger-application-layer-types-remove-impossible-states-53m4</link>
      <guid>https://dev.to/lksvn/stronger-application-layer-types-remove-impossible-states-53m4</guid>
      <description>&lt;p&gt;Today I completed a small Company write vertical slice in TypeScript, from business validation to PostgreSQL persistence.&lt;/p&gt;

&lt;p&gt;One detail clarified why application services are more than repository wrappers.&lt;/p&gt;

&lt;p&gt;The repository update returns &lt;code&gt;Company | undefined&lt;/code&gt;. That makes sense at the data layer: the query can succeed while the requested row does not exist.&lt;/p&gt;

&lt;p&gt;But the application service translates &lt;code&gt;undefined&lt;/code&gt; into an explicit &lt;code&gt;not-found&lt;/code&gt; result.&lt;/p&gt;

&lt;p&gt;After that translation, keeping &lt;code&gt;Company | undefined&lt;/code&gt; in the successful return type would force every caller to handle a state the service has made impossible.&lt;/p&gt;

&lt;p&gt;So the application contract returns either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;success with a Company&lt;/li&gt;
&lt;li&gt;validation failure&lt;/li&gt;
&lt;li&gt;not-found failure&lt;/li&gt;
&lt;li&gt;repository failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The type now describes the use-case guarantee instead of leaking the repository's lower-level uncertainty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The practical lesson:&lt;/strong&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;good TypeScript types do more than prevent syntax mistakes. They help make invalid or impossible application states unrepresentable.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A passing test can still prove nothing</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Fri, 17 Jul 2026 01:42:52 +0000</pubDate>
      <link>https://dev.to/lksvn/a-passing-test-can-still-prove-nothing-2p16</link>
      <guid>https://dev.to/lksvn/a-passing-test-can-still-prove-nothing-2p16</guid>
      <description>&lt;p&gt;Today I had a &lt;strong&gt;PostgreSQL&lt;/strong&gt; integration test passing for the wrong reason.&lt;/p&gt;

&lt;p&gt;The test was supposed to prove that updating a missing Company returned a successful "not found" result.&lt;/p&gt;

&lt;p&gt;I passed an id like: &lt;code&gt;company-missing&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But the database column was a &lt;strong&gt;UUID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt; rejected the malformed value before &lt;strong&gt;Prisma&lt;/strong&gt; could determine whether the Company existed. The repository returned a failure instead of the expected missing-record outcome.&lt;/p&gt;

&lt;p&gt;The test still passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Its assertion was inside a conditional success branch. Because the result was a failure, the branch never ran. The test completed with no failing assertion.&lt;/p&gt;

&lt;p&gt;The correction was small but important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate a valid UUID that was never inserted&lt;/li&gt;
&lt;li&gt;assert the complete Result object directly&lt;/li&gt;
&lt;li&gt;expect success with undefined data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That made the test exercise Prisma's real missing-record behavior instead of an invalid-input error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A green test is not automatically evidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Check that the intended branch was reached and that the assertion could actually fail.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Strong TypeScript contracts turn refactors into checklists</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Wed, 15 Jul 2026 15:10:00 +0000</pubDate>
      <link>https://dev.to/lksvn/strong-typescript-contracts-turn-refactors-into-checklists-40h4</link>
      <guid>https://dev.to/lksvn/strong-typescript-contracts-turn-refactors-into-checklists-40h4</guid>
      <description>&lt;p&gt;Today a TypeScript refactor produced &lt;strong&gt;15 compiler errors&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;It looked worse than it was.  &lt;/p&gt;

&lt;p&gt;My Candidate Tracker used a type called &lt;code&gt;AsyncResult&amp;lt;T&amp;gt;&lt;/code&gt; with errors represented only as strings.  &lt;/p&gt;

&lt;p&gt;While adding a real PostgreSQL repository, two design problems became clear:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the result itself was not asynchronous; the surrounding Promise was &lt;/li&gt;
&lt;li&gt;an error string discarded its category and original cause  I changed the contract to &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; and introduced a typed &lt;code&gt;RepositoryError&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The compiler immediately identified every repository, dashboard function, test, and callback that still depended on the old contract.  &lt;/p&gt;

&lt;p&gt;Most of the 15 errors were not separate problems. They were downstream symptoms of a few outdated type definitions.  &lt;/p&gt;

&lt;p&gt;Once those source contracts were corrected, the remaining errors disappeared and all tests passed again.  &lt;/p&gt;

&lt;p&gt;The lesson was practical:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Strong types do more than prevent mistakes while writing code. They make architectural changes searchable, explicit, and finite.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>typescript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>Automated Tests in Typescript</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Tue, 14 Jul 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/lksvn/automated-tests-in-typescript-1716</link>
      <guid>https://dev.to/lksvn/automated-tests-in-typescript-1716</guid>
      <description>&lt;p&gt;Today I wrote my first automated tests for my TypeScript learning project.&lt;/p&gt;

&lt;p&gt;Until now, most of my testing was manual: run the code, check the output, adjust, repeat.&lt;/p&gt;

&lt;p&gt;That works for small experiments, but today I started seeing why automated tests matter once business rules begin to grow.&lt;/p&gt;

&lt;p&gt;The most useful lesson was not just the syntax of describe, it, and expect.&lt;/p&gt;

&lt;p&gt;The useful lesson was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tests expose unclear thinking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some examples from today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a function called &lt;code&gt;getOpenJobs&lt;/code&gt; was too vague, so it became &lt;code&gt;getSavedJobs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a project function sounded like "ready to start", but the actual rule meant "overdue to start"&lt;/li&gt;
&lt;li&gt;id lookups were returning arrays, but a unique id lookup should return one item or undefined&lt;/li&gt;
&lt;li&gt;TypeScript caught union type mistakes that the runtime tests would not catch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the tests were not only checking behavior.&lt;br&gt;
They were pushing the model to become clearer.&lt;/p&gt;

&lt;p&gt;I also learned a practical distinction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual testing asks:&lt;/strong&gt;&lt;br&gt;
"Does this work right now?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated testing asks:&lt;/strong&gt;&lt;br&gt;
"Will I know when this breaks later?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next step:&lt;/strong&gt; testing async repository behavior before moving toward a real database.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>Backend/Domain foundation</title>
      <dc:creator>LkSvn</dc:creator>
      <pubDate>Mon, 13 Jul 2026 20:58:13 +0000</pubDate>
      <link>https://dev.to/lksvn/backenddomain-foundation-24hl</link>
      <guid>https://dev.to/lksvn/backenddomain-foundation-24hl</guid>
      <description>&lt;p&gt;Today I continued my TypeScript learning project after a short break.&lt;/p&gt;

&lt;p&gt;Instead of jumping into React right away, I decided to keep working on the backend/domain side of the Candidate Tracker project.&lt;/p&gt;

&lt;p&gt;The main lesson today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript is not just useful for components and props.&lt;/li&gt;
&lt;li&gt;It also helps clarify ownership, data flow, and service boundaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some examples from today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using &lt;code&gt;Omit&lt;/code&gt; and &lt;code&gt;Partial&lt;/code&gt; to define create/update inputs&lt;/li&gt;
&lt;li&gt;deciding which fields the caller can change and which fields the service owns&lt;/li&gt;
&lt;li&gt;using generics for reusable helpers like findById and filterByProperty&lt;/li&gt;
&lt;li&gt;typing async repository functions with &lt;code&gt;Promise&amp;lt;AsyncResult&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;using &lt;code&gt;Promise.all&lt;/code&gt; for independent data loading&lt;/li&gt;
&lt;li&gt;splitting async loading into stages when later data depends on earlier results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One useful distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Services express behavior.&lt;/li&gt;
&lt;li&gt;Repositories decide where data comes from.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That separation should make the next steps cleaner: adding tests first, then replacing seed data with a real database later.&lt;/p&gt;

&lt;p&gt;I’m intentionally delaying the frontend a bit.&lt;/p&gt;

&lt;p&gt;Not because React is less important, but because I want the domain and data flow to be understandable before putting UI on top.&lt;/p&gt;

&lt;p&gt;Next step: tests.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
