<?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: Mike Cornwell</title>
    <description>The latest articles on DEV Community by Mike Cornwell (@mtleadership).</description>
    <link>https://dev.to/mtleadership</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%2F3989415%2F1eefd098-3c1c-407b-ab2f-eebed574923e.png</url>
      <title>DEV Community: Mike Cornwell</title>
      <link>https://dev.to/mtleadership</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mtleadership"/>
    <language>en</language>
    <item>
      <title>tgo Devlog #3: Taming Context Windows, Compiling Lodash, and the Repetitive Reality of True Ownership</title>
      <dc:creator>Mike Cornwell</dc:creator>
      <pubDate>Fri, 26 Jun 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/mtleadership/tgo-devlog-3-taming-context-windows-compiling-lodash-and-the-repetitive-reality-of-true-4d7l</link>
      <guid>https://dev.to/mtleadership/tgo-devlog-3-taming-context-windows-compiling-lodash-and-the-repetitive-reality-of-true-4d7l</guid>
      <description>&lt;p&gt;I’ve been making massive headway on tgo, my TypeScript to Go compiler library, but it is forcing me to confront some hard realities about how I manage systems, AI, and even people.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cost of Scaling Complexity
&lt;/h3&gt;

&lt;p&gt;Since the last devlog, I’ve added full support for Node libraries—&lt;code&gt;fs&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;process&lt;/code&gt;, and a few others. Right now, I’m in the trenches trying to compile Lodash, &lt;code&gt;argparse&lt;/code&gt;, and &lt;code&gt;date-fns&lt;/code&gt;. I pushed &lt;code&gt;date-fns&lt;/code&gt; to the side for a minute because Lodash is proving to be the perfect stress test. It is, frankly, obnoxious. In some cases, the code is just very poorly written. &lt;/p&gt;

&lt;p&gt;Lodash has 316 different entry points. Right now, 122 are failing. But dealing with this massive, complex library has forced me to completely overhaul my test runner. I’ve built it so that you can choose specific entry points and compile only what you need—similar to how ES bundle works. I’ve also implemented heavy caching. If you are continually rebuilding, it won't re-compile the source to Go every single time; it just handles the binary compilation unless something actually changed. It’s significantly faster.&lt;/p&gt;

&lt;p&gt;But as this project scales, the sheer complexity is threatening to break the system—and by the system, I mean the AI I am using to build it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Process is Survival
&lt;/h3&gt;

&lt;p&gt;I do most of this development through AI, and getting an LLM to consistently output good software engineering without breaking existing features is incredibly difficult. I was constantly blowing out the context window. Even at 200,000 tokens, it wasn't enough. By the time the AI figured out what to do, it would start summarizing the context and immediately start doing a terrible job. &lt;/p&gt;

&lt;p&gt;This forced me to narrow down all possibilities. I realized there are really only four things I am ever asking the AI to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the test runner.&lt;/li&gt;
&lt;li&gt;Fix a bug.&lt;/li&gt;
&lt;li&gt;Implement a new feature.&lt;/li&gt;
&lt;li&gt;Work on a library.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it. I defined strict workflows for those four pathways. If I ask it to fix a bug, it has to run the specific test, read the JavaScript, read the outputted Go code, and reproduce it with a unit test. I spent a ton of time programming the AI "out of the box" so it doesn't try to read the entire codebase and break things. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Context Trap and Feature Creep
&lt;/h3&gt;

&lt;p&gt;I also had to learn the hard way to stop mixing code changes. I was implementing two features at once, one became hostage to the other, and it took hours to untangle the unit tests. Do one thing at a time. If you want to do two, use two different repos.&lt;/p&gt;

&lt;p&gt;Now, I am using the 1-million token context window, but I have to watch it like a hawk. When you are halfway through, every single request is sending 500,000 tokens back and forth. You can't just close your eyes and keep rocking. You have to be deliberate. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Hard Truth About Leadership
&lt;/h3&gt;

&lt;p&gt;Here is the biggest life lesson that tgo is hammering into my skull: Managing AI is exactly like managing people. &lt;/p&gt;

&lt;p&gt;For years, I've worked with people across different functions, and one of the most frustrating things is feeling like you constantly have to look over someone's shoulder. You think to yourself, &lt;em&gt;"How do I build a better system so I don't have to constantly remind them to do the basics?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Working with AI has shown me that this might be a fool's errand. You are fighting the wind. &lt;/p&gt;

&lt;p&gt;I built all these rules, workflows, and documentations for the AI, and I found myself getting incredibly annoyed when it wouldn't go read them. I would have to tell it, &lt;em&gt;"Go read the docs,"&lt;/em&gt; every single time. &lt;/p&gt;

&lt;p&gt;Then it hit me: Why am I getting mad at reality? &lt;/p&gt;

&lt;p&gt;I have just accepted that I have to encourage it to do the &lt;em&gt;one right thing&lt;/em&gt; right out of the gate, every single time. I now preemptively say "go read the docs" on the initial request. &lt;/p&gt;

&lt;h3&gt;
  
  
  Stop Complaining and Own the Process
&lt;/h3&gt;

&lt;p&gt;This translates perfectly to human leadership. Let's say you need your team to update the documentation after they learn something new. If your mindset is wrong, you will come to hate having to tell them to update the system. You will blame them. You will think, &lt;em&gt;"Why should I have to say this three times?"&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Because that's the job. You have to get okay with saying it every single time. And if it doesn't get done, you need to start blaming yourself for failing to remind them. Giving a tip or a reminder dramatically improves the odds of success. It might take 20 times for them to consistently do it on their own. But as a leader, your frustration doesn't write code, and it doesn't build businesses. &lt;/p&gt;

&lt;p&gt;Stop complaining about the repetition. Accept the reality of the machine you are operating, take extreme ownership of the process, and get back to work.&lt;/p&gt;

</description>
      <category>go</category>
      <category>typescript</category>
      <category>leadership</category>
      <category>programming</category>
    </item>
    <item>
      <title>tgo Dev Log #2: Compiling UUIDs, Async Goroutines, and the Lodash Nightmare</title>
      <dc:creator>Mike Cornwell</dc:creator>
      <pubDate>Thu, 25 Jun 2026 13:57:41 +0000</pubDate>
      <link>https://dev.to/mtleadership/tgo-dev-log-2-compiling-uuids-async-goroutines-and-the-lodash-nightmare-38l5</link>
      <guid>https://dev.to/mtleadership/tgo-dev-log-2-compiling-uuids-async-goroutines-and-the-lodash-nightmare-38l5</guid>
      <description>&lt;p&gt;I am about two and a half weeks into building tgo (my TypeScript to Go compiler). Over the weekend, I hit a massive milestone: I officially have the UUID library (both v12 and v13) compiling, running, and passing all of its included unit tests natively in Go. &lt;/p&gt;

&lt;p&gt;That is a big fucking deal. &lt;/p&gt;

&lt;p&gt;On top of that, I built out the package importing system. You can now do an NPM install, configure the tgo compiler to point to the source, and bada bing, bada boom—it pulls it in. I also added precompilation optimizations. If you aren't changing the library, it precompiles those dependencies into Go and only updates your specific code changes when you run the compiler. It speeds the whole dev loop up significantly. &lt;/p&gt;

&lt;p&gt;Getting the UUID unit tests to run completely was awesome. But it's also a testament to the emotional swings of building something this complex. You get an idea, you implement it, you get positive feedback, and you're like, &lt;em&gt;Hell yeah.&lt;/em&gt; But then the reality seeps in of how ridiculously hard the next level is. &lt;/p&gt;

&lt;h4&gt;
  
  
  The AI Wall and the Need for Rigid TDD
&lt;/h4&gt;

&lt;p&gt;Right now, this repository is officially one of the largest I have worked with in a long time. There are so many things to handle—from bridging the Node standard library to Go, to creating TypeScript-level linkers. &lt;/p&gt;

&lt;p&gt;Because the project is so massive, it is starting to challenge the AI tools I'm using. I had to turn Cursor onto the 1-million-token context window. By the time the AI got enough context to understand what was happening, it had to summarize and obliterate its own thinking just to tackle the problem. Worse, AI wants to just hop in and change code to make a specific scenario work. When it does that in a codebase this deeply interconnected, it wrecks all the previous scenarios. &lt;/p&gt;

&lt;p&gt;This forced me to get religious about TDD (Test-Driven Development). My scenario runner inputs an AST (Abstract Syntax Tree) and spits out string code. I have to force the AI to respect these scenarios, otherwise, the regressions will kill the project.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Lodash Nightmare
&lt;/h4&gt;

&lt;p&gt;I needed an entry point library, so I got &lt;code&gt;argparse&lt;/code&gt; working. But then I looked at &lt;code&gt;lodash&lt;/code&gt;. My god, compiling Lodash has been a fucking nightmare. &lt;/p&gt;

&lt;p&gt;I have used Lodash on the backend forever. But when you are writing a compiler, you have to look at the internals to figure out why things aren't running. Inside Lodash, there are so many obscure, low-level, weird JavaScript tricks going on. It is heavily using state, constructors, and globals. It physically hurts the head to look at. &lt;/p&gt;

&lt;p&gt;This is exactly why I want tgo to exist. I want developers to write expressive, high-level functional TypeScript—like maps and reduces—and have the compiler optimize that into ridiculously speedy Go &lt;code&gt;for&lt;/code&gt; loops behind the scenes. You shouldn't have to write annoyingly obscure, low-level JavaScript just to get performance. &lt;/p&gt;

&lt;h4&gt;
  
  
  Async/Await to Native Goroutines
&lt;/h4&gt;

&lt;p&gt;Amidst the frustration with Lodash, we had a massive win: Promises. &lt;/p&gt;

&lt;p&gt;We implemented Promises so that they map directly to Goroutines. When you write &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; in TypeScript now, tgo runs those as independent Go routines. Depending on what your application is doing, you can get massive, huge increases in parallel performance directly out of the box. &lt;/p&gt;

&lt;h4&gt;
  
  
  The Hard Numbers: Performance Testing
&lt;/h4&gt;

&lt;p&gt;I've been building out performance tests, and I want to be totally transparent: Go is not always faster out of the gate. &lt;/p&gt;

&lt;p&gt;I wrote a test to compute a million primes. When you run this using standard JavaScript numbers (which are floats), Node absolutely kicks the crap out of Go. Node's engine is incredibly optimized for float modulation. &lt;/p&gt;

&lt;p&gt;However, if you explicitly type your TypeScript numbers as &lt;code&gt;BigInt&lt;/code&gt; (which forces direct integer math) and you run it in parallel? Go absolutely smokes Node. &lt;/p&gt;

&lt;p&gt;Here are the raw results from the latest scenario runner:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Total Time&lt;/th&gt;
&lt;th&gt;tsx&lt;/th&gt;
&lt;th&gt;node&lt;/th&gt;
&lt;th&gt;go&lt;/th&gt;
&lt;th&gt;node → go&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;perf-compute-primes-million&lt;/strong&gt; (Float, Serial)&lt;/td&gt;
&lt;td&gt;10.87s&lt;/td&gt;
&lt;td&gt;1.83s&lt;/td&gt;
&lt;td&gt;1.74s&lt;/td&gt;
&lt;td&gt;6.74s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.3x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;perf-compute-primes-million-bigint&lt;/strong&gt; (Int, Serial)&lt;/td&gt;
&lt;td&gt;14.02s&lt;/td&gt;
&lt;td&gt;5.18s&lt;/td&gt;
&lt;td&gt;5.71s&lt;/td&gt;
&lt;td&gt;2.70s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.1x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;perf-compute-primes-million-bigint-parallel&lt;/strong&gt; (Int)&lt;/td&gt;
&lt;td&gt;12.01s&lt;/td&gt;
&lt;td&gt;5.26s&lt;/td&gt;
&lt;td&gt;5.56s&lt;/td&gt;
&lt;td&gt;703ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.9x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;perf-compute-primes-million-parallel&lt;/strong&gt; (Float)&lt;/td&gt;
&lt;td&gt;5.81s&lt;/td&gt;
&lt;td&gt;1.87s&lt;/td&gt;
&lt;td&gt;1.71s&lt;/td&gt;
&lt;td&gt;1.83s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.9x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;perf-compute-primes-thousand&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;622ms&lt;/td&gt;
&lt;td&gt;150ms&lt;/td&gt;
&lt;td&gt;30ms&lt;/td&gt;
&lt;td&gt;26ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.2x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Note: 5 passing in 43.34s total. Average across all tests: 1.2x. node 14.74s vs go 12.00s)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It is going to be difficult for the compiler to automatically infer an integer over a float without explicitly being told via &lt;code&gt;BigInt&lt;/code&gt;, so we will leave these tests in as a benchmark for where we can improve. &lt;/p&gt;

&lt;p&gt;Next up: diving deeper into complex type systems like my Functional Models library. I'm going to keep plugging away. &lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>go</category>
      <category>typescript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>tgo Dev Log #1: Writing Strict TypeScript, Compiling to Native Go</title>
      <dc:creator>Mike Cornwell</dc:creator>
      <pubDate>Mon, 22 Jun 2026 14:25:57 +0000</pubDate>
      <link>https://dev.to/mtleadership/tgo-dev-log-1-writing-strict-typescript-compiling-to-native-go-365b</link>
      <guid>https://dev.to/mtleadership/tgo-dev-log-1-writing-strict-typescript-compiling-to-native-go-365b</guid>
      <description>&lt;p&gt;I’m a little further ahead in this project than I’d like to be to just start a dev log, but I'm going to do it anyway. Moving forward, I want to treat this as a daily log—a place to dump my thoughts, the hard realities, and the technical pivots of what I'm building.&lt;/p&gt;

&lt;p&gt;The project is called tgo (t-G-O). The reason for the name is simple: "tsgo" was already taken by Microsoft when they wanted to create a compiler chain and checker for TypeScript written in Go. When I first heard about their project, I actually thought they were doing what I’m doing—writing TypeScript and producing compiled Go. They aren't. But I am.&lt;/p&gt;

&lt;p&gt;And so far, the results are wildly compelling.&lt;/p&gt;

&lt;p&gt;If you've built complex systems, you know the cycle. You get real hot on an idea, you go down the rabbit hole, and then you hit a wall. The classic feelings of inadequacy creep in. You start wondering, Is this actually going to work? Will it be good enough? But then there are the moments where you get over the hurdle, look at the output, and go, This shit motherfucking works.&lt;/p&gt;

&lt;p&gt;From V1 Chaos to V2 Precision&lt;/p&gt;

&lt;p&gt;Right now, we are on version two of the compiler. V1 was basically me just throwing stuff at the wall. It was a rough attempt to create an intermediate representation and write it out as strings. The result? Massive, 5,000-line files. Crazy nested logic. Switch statements and if/else blocks spanning a thousand lines.&lt;/p&gt;

&lt;p&gt;To manage this scale of abstract code, I am using AI heavily—but I am strictly controlling the process.&lt;/p&gt;

&lt;p&gt;I took all my past experiences in development and decided to anchor this entire project to a rigid Test-Driven Development (TDD) process. I’ve known about TDD my whole career. I’m a massive advocate for unit tests, 100% code coverage, and edge-case testing because I build platforms and libraries that people depend on. But this compiler is different. It is astronomically complex and pretty fucking hard.&lt;/p&gt;

&lt;p&gt;Every single inch we move forward is driven by a scenario. We want to implement a new feature, a refactor, or support a new library? We write the scenario first. We run it. We make sure it fails. We look at the converted TypeScript-to-Go output, and then we write the changes. It is the only way to prevent regressions.&lt;/p&gt;

&lt;p&gt;The Wins: Speedy as Hell&lt;/p&gt;

&lt;p&gt;I am trying to make this compiler output code that is speedy as hell, and the results are already in.&lt;/p&gt;

&lt;p&gt;We ran a performance test against standard Node generating UUIDs (calling Node's &lt;code&gt;randomUUID()&lt;/code&gt; function a million times). tgo is slower by about 0.1% on pure generation. However, when we take that same test and add a deduplication confirmation to ensure all one million hashes are unique, tgo is an 8x speedup. It is monumentally faster.&lt;/p&gt;

&lt;p&gt;To make this work, we’ve actually had to build a Go standard library that effectively replaces the Node/JavaScript standard libraries. I can currently compile the "uuid" library and run it as a package to a Go library, or drop the full source code inside an application as a folder, and the whole thing just works. Validations, UUID v5s, binary operations, arrays, buffers—it works, and it matches external expectations perfectly.&lt;/p&gt;

&lt;p&gt;The Hard Engineering Realities&lt;/p&gt;

&lt;p&gt;We chose Go primarily because of memory management. I looked at C++, but the lack of a garbage collector meant memory management would become astronomically complicated—effectively requiring me to invent a garbage collector just to handle things like instantiating new objects.&lt;/p&gt;

&lt;p&gt;But Go comes with its own limitations. Go doesn't support "OR-ing" on types. It doesn't have JavaScript's version of truthiness (where undefined and null are separate things but work similarly in truthiness evaluations). Go just has a nil concept.&lt;/p&gt;

&lt;p&gt;The core philosophy of tgo is this: You are a TypeScript developer. You shouldn't have to care about Go. You write TypeScript, think in TypeScript, and you get the exact same expected results, just running natively in Go.&lt;/p&gt;

&lt;p&gt;To pull that off, we're doing deep work on polymorphism. I want to build structs that are generated at compile time with minimal name-mangling so the code remains intelligible. We are aggressively avoiding dynamic types, interfaces, and anys so the compiled Go code stays fast. If the TypeScript inference gets into any territory, it gets boxed into an interface, and it just won't run as fast.&lt;/p&gt;

&lt;p&gt;We are constantly hitting limitations—like handling casting (as unknown as)—and we will publish a full list of these limitations. The compiler will eventually warn you as early as possible when you do something that Go fundamentally cannot do.&lt;/p&gt;

&lt;p&gt;The Ultimate Vision&lt;/p&gt;

&lt;p&gt;Once we clear these major hurdles—like compiling my highly-generic Functional Models library, which has layers of complex type inference—the endgame is clear.&lt;/p&gt;

&lt;p&gt;This is for developers who want to write in one language. You write your front end in React. You use the exact same TypeScript libraries, typing, and interfaces for your back end. Then, tgo compiles your back end into ridiculously fast, memory-efficient Go.&lt;/p&gt;

&lt;p&gt;But there is a catch. This compiler is going to force you to be a better developer. You have to have good typing. You can't have jacked-up typing where you bypass the TypeScript system. If you try to cheat the compiler, you're going to run into trouble.&lt;/p&gt;

&lt;p&gt;We have about 170 tests passing right now. The next major milestone is getting deep polymorphism fully dialed in.&lt;/p&gt;

&lt;p&gt;I’ll keep updating this log as we push forward.&lt;/p&gt;

</description>
      <category>tgo</category>
      <category>typescript</category>
      <category>go</category>
      <category>compiler</category>
    </item>
  </channel>
</rss>
