<?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: Michael Placzek</title>
    <description>The latest articles on DEV Community by Michael Placzek (@heymaikol).</description>
    <link>https://dev.to/heymaikol</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%2F4099690%2F3213ac26-f0bf-41d0-89b2-b85c85bca0ee.jpg</url>
      <title>DEV Community: Michael Placzek</title>
      <link>https://dev.to/heymaikol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/heymaikol"/>
    <language>en</language>
    <item>
      <title>I Stopped Trying to Prove My Code Works. I Started Trying to Prove It Wrong.</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Tue, 29 Sep 2026 13:15:00 +0000</pubDate>
      <link>https://dev.to/heymaikol/i-stopped-trying-to-prove-my-code-works-i-started-trying-to-prove-it-wrong-3c4k</link>
      <guid>https://dev.to/heymaikol/i-stopped-trying-to-prove-my-code-works-i-started-trying-to-prove-it-wrong-3c4k</guid>
      <description>&lt;p&gt;For a long time, my tests asked a pretty normal question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this code work?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Valid input goes in.&lt;/p&gt;

&lt;p&gt;Expected output comes out.&lt;/p&gt;

&lt;p&gt;Green checkmark.&lt;/p&gt;

&lt;p&gt;Ship it.&lt;/p&gt;

&lt;p&gt;Then I started building Network Doctor, an open-source network troubleshooting tool.&lt;/p&gt;

&lt;p&gt;And that mindset stopped being good enough.&lt;/p&gt;

&lt;p&gt;Because network software lives in the horrible little gaps between "valid" and "invalid."&lt;/p&gt;

&lt;p&gt;An IPv6 address can be valid and still break your assumptions.&lt;/p&gt;

&lt;p&gt;A simulated failure can look realistic while actually describing an impossible network.&lt;/p&gt;

&lt;p&gt;A privacy filter can correctly redact 99% of addresses and still leak the one format you forgot existed.&lt;/p&gt;

&lt;p&gt;A test suite can be completely green while the program is still wrong.&lt;/p&gt;

&lt;p&gt;So I changed the question.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can I prove this works?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can I prove this is wrong?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That change has probably improved the project more than any individual feature I've added.&lt;/p&gt;

&lt;h2&gt;
  
  
  The happy path is the easy part
&lt;/h2&gt;

&lt;p&gt;Network Doctor checks multiple layers of a connection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network interfaces&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;TCP&lt;/li&gt;
&lt;li&gt;TLS&lt;/li&gt;
&lt;li&gt;HTTP&lt;/li&gt;
&lt;li&gt;proxies&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;path MTU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The normal cases are surprisingly boring.&lt;/p&gt;

&lt;p&gt;DNS resolves.&lt;/p&gt;

&lt;p&gt;TCP connects.&lt;/p&gt;

&lt;p&gt;TLS negotiates.&lt;/p&gt;

&lt;p&gt;HTTP returns a response.&lt;/p&gt;

&lt;p&gt;The interesting bugs are hiding around the edges.&lt;/p&gt;

&lt;p&gt;So I started deliberately feeding the project things I hoped would break it.&lt;/p&gt;

&lt;p&gt;And they did.&lt;/p&gt;

&lt;h2&gt;
  
  
  IPv6 has been particularly good at humbling me
&lt;/h2&gt;

&lt;p&gt;Take an address like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fe80::1%eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;%eth0&lt;/code&gt; matters.&lt;/p&gt;

&lt;p&gt;It identifies the interface scope for a link-local IPv6 address.&lt;/p&gt;

&lt;p&gt;If you're writing code that parses, displays, compares, exports, or redacts network addresses, suddenly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fe80::1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fe80::1%eth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are not necessarily interchangeable strings.&lt;/p&gt;

&lt;p&gt;Then there are bracketed addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2001:db8::1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And addresses embedded inside other text.&lt;/p&gt;

&lt;p&gt;And equivalent IPv6 spellings.&lt;/p&gt;

&lt;p&gt;And IPv6 addresses whose final group contains hexadecimal letters instead of looking suspiciously like an IPv4 address.&lt;/p&gt;

&lt;p&gt;Each one is perfectly reasonable.&lt;/p&gt;

&lt;p&gt;Each one is also an opportunity for a program to quietly make a bad assumption.&lt;/p&gt;

&lt;p&gt;I have fixed multiple bugs in Network Doctor simply by asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the weirdest valid version of this input I can think of?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question is becoming one of my favorite testing tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I started attacking the simulator
&lt;/h2&gt;

&lt;p&gt;Network Doctor has a simulator because reproducing real network failures on demand is difficult.&lt;/p&gt;

&lt;p&gt;I can describe situations like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS is slow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;there is no default route
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and exercise the diagnostic logic against them.&lt;/p&gt;

&lt;p&gt;At first, I mostly tested whether valid scenarios worked.&lt;/p&gt;

&lt;p&gt;Then I realized the simulator itself could lie.&lt;/p&gt;

&lt;p&gt;What if a scenario claims there is no default route, but its other configuration requires one?&lt;/p&gt;

&lt;p&gt;What if two simulated services try to listen on the same address?&lt;/p&gt;

&lt;p&gt;What if a scheduled DNS delay is smaller than the simulator's timing precision?&lt;/p&gt;

&lt;p&gt;What if a timeline contains latency values that cannot actually be represented correctly?&lt;/p&gt;

&lt;p&gt;Those are not necessarily bugs in the diagnostic engine.&lt;/p&gt;

&lt;p&gt;They are bugs in the laboratory used to test the diagnostic engine.&lt;/p&gt;

&lt;p&gt;That is worse.&lt;/p&gt;

&lt;p&gt;If your test environment can represent impossible states, a passing test can give you confidence in something that was never true in the first place.&lt;/p&gt;

&lt;p&gt;So now the simulator gets attacked too.&lt;/p&gt;

&lt;h2&gt;
  
  
  My new rule: prove the bug before fixing the bug
&lt;/h2&gt;

&lt;p&gt;This became especially important once I started using AI coding tools heavily.&lt;/p&gt;

&lt;p&gt;AI is very good at looking at code and saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I found a bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes it really did.&lt;/p&gt;

&lt;p&gt;Sometimes it found something that looked suspicious but was intentional.&lt;/p&gt;

&lt;p&gt;Sometimes it misunderstood the surrounding code.&lt;/p&gt;

&lt;p&gt;And sometimes it confidently proposed a fix for a problem that did not exist.&lt;/p&gt;

&lt;p&gt;So I adopted a rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No proof, no fix.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The workflow looks roughly like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find a suspicious behavior.&lt;/li&gt;
&lt;li&gt;Reproduce it.&lt;/li&gt;
&lt;li&gt;Write a test that fails because of it.&lt;/li&gt;
&lt;li&gt;Confirm the failure is actually wrong.&lt;/li&gt;
&lt;li&gt;Make the smallest reasonable change.&lt;/li&gt;
&lt;li&gt;Run the regression test.&lt;/li&gt;
&lt;li&gt;Run the rest of the test suite.&lt;/li&gt;
&lt;li&gt;Try to break the new behavior again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Network Doctor that can include things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-race&lt;/span&gt; ./...
./scripts/check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;along with fuzzing, cross-platform checks, simulator validation, and other project-specific tests.&lt;/p&gt;

&lt;p&gt;The important part is not the commands.&lt;/p&gt;

&lt;p&gt;The important part is the order.&lt;/p&gt;

&lt;p&gt;The fix comes &lt;strong&gt;after the evidence&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A green checkmark does not mean "correct"
&lt;/h2&gt;

&lt;p&gt;This sounds obvious.&lt;/p&gt;

&lt;p&gt;But I think it is an incredibly easy trap to fall into.&lt;/p&gt;

&lt;p&gt;A test suite only proves the things you asked it to prove.&lt;/p&gt;

&lt;p&gt;If all your tests say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Given normal input X,
does function Y return Z?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then congratulations.&lt;/p&gt;

&lt;p&gt;You have learned a lot about normal input X.&lt;/p&gt;

&lt;p&gt;Production is currently preparing input Q-17 from a Windows machine connected through a VPN with a scoped IPv6 address and a proxy configuration you have never seen before.&lt;/p&gt;

&lt;p&gt;Good luck.&lt;/p&gt;

&lt;p&gt;So I have been trying to make tests more adversarial.&lt;/p&gt;

&lt;p&gt;Instead of only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does it accept valid input?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which valid input looks invalid?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does redaction work?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What representation of this address escapes redaction?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does the simulator run this scenario?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Can I construct a scenario that should never be allowed to exist?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those questions find much more interesting bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strangely, this has made AI more useful
&lt;/h2&gt;

&lt;p&gt;I use Claude Code, Codex, and local models during development.&lt;/p&gt;

&lt;p&gt;The more I use them, the less interested I am in whether they can generate lots of code.&lt;/p&gt;

&lt;p&gt;Generating code is easy now.&lt;/p&gt;

&lt;p&gt;Verification is the expensive part.&lt;/p&gt;

&lt;p&gt;So one of the most useful things I can ask an AI coding agent is no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Implement this feature.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try to prove this implementation is wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look for counterexamples.&lt;/p&gt;

&lt;p&gt;Find inputs that violate assumptions.&lt;/p&gt;

&lt;p&gt;Trace the behavior through another platform.&lt;/p&gt;

&lt;p&gt;Construct a regression test.&lt;/p&gt;

&lt;p&gt;Compare what the documentation promises with what the code actually guarantees.&lt;/p&gt;

&lt;p&gt;That turns AI from a code generator into something closer to an extremely persistent adversarial reviewer.&lt;/p&gt;

&lt;p&gt;It still gets things wrong.&lt;/p&gt;

&lt;p&gt;But that's fine.&lt;/p&gt;

&lt;p&gt;Because it has to prove its case too.&lt;/p&gt;

&lt;h2&gt;
  
  
  This feels slower
&lt;/h2&gt;

&lt;p&gt;Sometimes it is.&lt;/p&gt;

&lt;p&gt;A tiny bug can become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;investigation
→ reproduction
→ regression test
→ fix
→ full validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;change three lines
→ looks good
→ merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the second workflow only looks faster because it stops measuring time before the bug comes back.&lt;/p&gt;

&lt;p&gt;I would rather spend an extra hour proving a fix today than spend a day figuring out why an "obvious" fix caused something bizarre three releases later.&lt;/p&gt;

&lt;h2&gt;
  
  
  I don't want tests that agree with me
&lt;/h2&gt;

&lt;p&gt;I want tests that are annoying.&lt;/p&gt;

&lt;p&gt;I want fuzzers discovering inputs I didn't consider.&lt;/p&gt;

&lt;p&gt;I want the simulator refusing contradictory scenarios.&lt;/p&gt;

&lt;p&gt;I want privacy tests assuming I forgot another representation of an IP address.&lt;/p&gt;

&lt;p&gt;I want CI rejecting something that looked completely harmless.&lt;/p&gt;

&lt;p&gt;I want another developer to look at my implementation and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But what happens if...?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is incredibly valuable.&lt;/p&gt;

&lt;p&gt;Software gets interesting exactly where our assumptions stop working.&lt;/p&gt;

&lt;p&gt;So these days, when I finish a feature, I try not to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did I make this work?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I wanted to embarrass the person who wrote this, how would I break it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, that person is usually me.&lt;/p&gt;

&lt;p&gt;And so far, it has been a pretty effective development strategy.&lt;/p&gt;




&lt;p&gt;Network Doctor is open source, and I am continuing to build it in public.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the weirdest edge case your tests have ever caught before a user did?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I genuinely want to hear them.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>testing</category>
      <category>go</category>
    </item>
    <item>
      <title>Combating AI Slop in Network Doctor</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Fri, 25 Sep 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/heymaikol/combating-ai-slop-in-network-doctor-26gb</link>
      <guid>https://dev.to/heymaikol/combating-ai-slop-in-network-doctor-26gb</guid>
      <description>&lt;p&gt;I use AI heavily while developing &lt;a href="https://github.com/heymaikol/network-doctor" rel="noopener noreferrer"&gt;Network Doctor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Claude Code, Codex, and local models have all helped me find bugs, write tests, investigate weird edge cases, review code, and improve documentation.&lt;/p&gt;

&lt;p&gt;I am not interested in pretending otherwise.&lt;/p&gt;

&lt;p&gt;But there is a problem.&lt;/p&gt;

&lt;p&gt;AI can produce code that looks &lt;em&gt;extremely&lt;/em&gt; convincing while being completely unnecessary, subtly wrong, overengineered, or based on a bug that never existed in the first place.&lt;/p&gt;

&lt;p&gt;That is what is known as &lt;strong&gt;AI slop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And as I have used AI more while building Network Doctor, I have become much more interested in a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do you get the speed of AI-assisted development without slowly filling your project with garbage?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I do not think the answer is "stop using AI."&lt;/p&gt;

&lt;p&gt;I think the answer is to make the repository hostile to unverified work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 1: prove the bug exists
&lt;/h2&gt;

&lt;p&gt;This is probably the most important rule in Network Doctor's repository guidelines:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before changing behavior, verify the reported issue against the current HEAD.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That rule exists for humans, but it is especially useful for AI.&lt;/p&gt;

&lt;p&gt;Give a coding agent a convincing bug report and it will often happily start fixing it.&lt;/p&gt;

&lt;p&gt;That does not mean the bug is real.&lt;/p&gt;

&lt;p&gt;Maybe the report is outdated.&lt;/p&gt;

&lt;p&gt;Maybe another change already fixed it.&lt;/p&gt;

&lt;p&gt;Maybe the reproduction depends on an assumption that is false.&lt;/p&gt;

&lt;p&gt;Maybe the proposed fix is solving the wrong layer entirely.&lt;/p&gt;

&lt;p&gt;So before I want a fix, I want evidence.&lt;/p&gt;

&lt;p&gt;Reproduce it.&lt;/p&gt;

&lt;p&gt;Write a focused test.&lt;/p&gt;

&lt;p&gt;Show me the failure.&lt;/p&gt;

&lt;p&gt;Then fix it.&lt;/p&gt;

&lt;p&gt;A surprising number of "bugs" become much less convincing once you require that first step.&lt;/p&gt;

&lt;p&gt;This also changes the way I prompt coding agents. Instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fix this bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I increasingly want something closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Investigate this report against current HEAD. Do not change anything until you can reproduce it. If it is valid, create the smallest regression test that demonstrates the problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That one distinction removes a lot of garbage before it ever reaches the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 2: AI does not get to declare itself correct
&lt;/h2&gt;

&lt;p&gt;One of the easiest traps with coding agents is this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI writes the code.&lt;/li&gt;
&lt;li&gt;AI reads the code.&lt;/li&gt;
&lt;li&gt;AI says the code looks correct.&lt;/li&gt;
&lt;li&gt;Done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is not verification.&lt;/p&gt;

&lt;p&gt;Network Doctor has a local validation command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs formatting checks, &lt;code&gt;go vet&lt;/code&gt;, builds the project with the same &lt;code&gt;CGO_ENABLED=0&lt;/code&gt; constraint used by releases, cross-compiles for multiple operating systems, and runs the ordinary Go test suite.&lt;/p&gt;

&lt;p&gt;For changes where concurrency matters, there is also:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/check &lt;span class="nt"&gt;--race&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CI goes considerably further.&lt;/p&gt;

&lt;p&gt;There are integration tests, fuzz tests, security analysis, platform checks, packaging checks, documentation checks, and other repository invariants.&lt;/p&gt;

&lt;p&gt;The important part is that these checks do not care how confident an AI model sounds.&lt;/p&gt;

&lt;p&gt;The code either satisfies the contract or it does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 3: turn important assumptions into executable rules
&lt;/h2&gt;

&lt;p&gt;Documentation saying "please don't do this" is useful.&lt;/p&gt;

&lt;p&gt;A test that fails when somebody does it is better.&lt;/p&gt;

&lt;p&gt;Network Doctor has accumulated tests for things that would otherwise be very easy to accidentally break.&lt;/p&gt;

&lt;p&gt;Some protect architecture.&lt;/p&gt;

&lt;p&gt;Some protect packaging.&lt;/p&gt;

&lt;p&gt;Some protect documentation.&lt;/p&gt;

&lt;p&gt;Some protect stable behavior.&lt;/p&gt;

&lt;p&gt;And one of my favorites is extremely small:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Doctor rejects em dashes in tracked text files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is an actual test for it.&lt;/p&gt;

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

&lt;p&gt;Because I kept seeing them creep back into generated text, especially from AI-assisted writing. I did not want that style in the project, so instead of repeatedly asking models not to use them, I made the repository enforce the rule.&lt;/p&gt;

&lt;p&gt;Now it does not matter whether the text came from me, Claude, Codex, a contributor, or something else.&lt;/p&gt;

&lt;p&gt;If an em dash comes back, the test fails.&lt;/p&gt;

&lt;p&gt;That is a tiny example, but the principle scales:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you keep correcting the same AI mistake manually, consider turning the correction into an invariant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The repository starts remembering the lesson for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 4: protect the boring contracts
&lt;/h2&gt;

&lt;p&gt;AI loves improving things.&lt;/p&gt;

&lt;p&gt;Sometimes that is exactly the problem.&lt;/p&gt;

&lt;p&gt;A mature CLI has behavior that should remain boring.&lt;/p&gt;

&lt;p&gt;Argument shapes.&lt;/p&gt;

&lt;p&gt;Exit codes.&lt;/p&gt;

&lt;p&gt;JSON fields.&lt;/p&gt;

&lt;p&gt;Labels.&lt;/p&gt;

&lt;p&gt;Timeout behavior.&lt;/p&gt;

&lt;p&gt;Platform boundaries.&lt;/p&gt;

&lt;p&gt;Output semantics.&lt;/p&gt;

&lt;p&gt;Once users or scripts depend on those things, an "improvement" can easily become a regression.&lt;/p&gt;

&lt;p&gt;Network Doctor has tests around many of these contracts precisely because a locally reasonable change can have consequences somewhere completely different.&lt;/p&gt;

&lt;p&gt;This matters even more with agents because they are very good at making a modification look internally consistent.&lt;/p&gt;

&lt;p&gt;They can update the implementation, update the nearby test, update the comment, and produce a beautifully self-consistent change that still breaks the public contract.&lt;/p&gt;

&lt;p&gt;The defense is having tests outside the immediate implementation that say:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No. This behavior belongs to the user now.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 5: fuzz the places where cleverness gets dangerous
&lt;/h2&gt;

&lt;p&gt;Some areas of Network Doctor deal with messy input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;targets and addresses&lt;/li&gt;
&lt;li&gt;sanitization and redaction&lt;/li&gt;
&lt;li&gt;DNS responses&lt;/li&gt;
&lt;li&gt;generated network simulations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are exactly the kinds of places where an AI-generated implementation can look elegant while missing one horrible input nobody thought about.&lt;/p&gt;

&lt;p&gt;So Network Doctor fuzzes them.&lt;/p&gt;

&lt;p&gt;For example, changes to target parsing have a dedicated fuzz target. Sanitization has one too.&lt;/p&gt;

&lt;p&gt;I like fuzzing in an AI-heavy workflow because it changes the argument.&lt;/p&gt;

&lt;p&gt;The model can tell me why its parser is correct.&lt;/p&gt;

&lt;p&gt;I would rather throw thousands of ugly inputs at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 6: replay reality
&lt;/h2&gt;

&lt;p&gt;Unit tests are necessary, but networking has an annoying property:&lt;/p&gt;

&lt;p&gt;Reality is much stranger than the test cases you invent.&lt;/p&gt;

&lt;p&gt;Network Doctor has a field-case corpus containing recorded diagnostic situations. Its diagnosis engine can replay those snapshots without performing the original network probes.&lt;/p&gt;

&lt;p&gt;That gives me another defense against plausible-looking changes.&lt;/p&gt;

&lt;p&gt;A modification to diagnostic reasoning might pass the test the agent just wrote while changing how an old real-world incident is interpreted.&lt;/p&gt;

&lt;p&gt;Replay catches that class of mistake.&lt;/p&gt;

&lt;p&gt;This is something I want to expand over time.&lt;/p&gt;

&lt;p&gt;Every strange real-world failure can become another permanent adversary for future code.&lt;/p&gt;

&lt;p&gt;The project gets harder to fool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 7: use AI against AI
&lt;/h2&gt;

&lt;p&gt;I also do not always use the same model for implementation and review.&lt;/p&gt;

&lt;p&gt;Sometimes one agent investigates.&lt;/p&gt;

&lt;p&gt;Another reviews the resulting diff.&lt;/p&gt;

&lt;p&gt;Another looks specifically for edge cases.&lt;/p&gt;

&lt;p&gt;Sometimes I use a local model.&lt;/p&gt;

&lt;p&gt;Sometimes Claude Code or Codex catches something another model missed.&lt;/p&gt;

&lt;p&gt;This is not because one model is magically trustworthy.&lt;/p&gt;

&lt;p&gt;It is because disagreement is useful.&lt;/p&gt;

&lt;p&gt;If one agent writes 200 lines and another immediately says, "This can be 30," that is worth investigating.&lt;/p&gt;

&lt;p&gt;If one agent claims an edge case is impossible and another produces a reproduction, even better.&lt;/p&gt;

&lt;p&gt;AI is very good at generating hypotheses.&lt;/p&gt;

&lt;p&gt;So I try to use multiple passes to attack those hypotheses instead of treating the first answer as truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 8: test the actual platforms
&lt;/h2&gt;

&lt;p&gt;Network Doctor supports Linux, macOS, and Windows.&lt;/p&gt;

&lt;p&gt;Cross-compilation catches a lot.&lt;/p&gt;

&lt;p&gt;It does not catch everything.&lt;/p&gt;

&lt;p&gt;So I also test releases on real machines.&lt;/p&gt;

&lt;p&gt;That has included Fedora, Windows 11, and macOS systems.&lt;/p&gt;

&lt;p&gt;This matters because AI knows what platform APIs &lt;em&gt;usually&lt;/em&gt; do.&lt;/p&gt;

&lt;p&gt;The machine gets the final vote.&lt;/p&gt;

&lt;p&gt;Networking is especially good at exposing the difference between "this should work" and "this actually works."&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 9: keep changes small enough to understand
&lt;/h2&gt;

&lt;p&gt;Another defense against slop is simple:&lt;/p&gt;

&lt;p&gt;Do less at once.&lt;/p&gt;

&lt;p&gt;When an AI agent produces a giant refactor, every additional changed behavior increases the amount of trust required to review it.&lt;/p&gt;

&lt;p&gt;A focused change is much easier to challenge.&lt;/p&gt;

&lt;p&gt;What was broken?&lt;/p&gt;

&lt;p&gt;How was it reproduced?&lt;/p&gt;

&lt;p&gt;What changed?&lt;/p&gt;

&lt;p&gt;Which test proves it?&lt;/p&gt;

&lt;p&gt;What unrelated behavior moved?&lt;/p&gt;

&lt;p&gt;Ideally, the answer to the last question is "none."&lt;/p&gt;

&lt;p&gt;I would much rather merge five boring changes that I understand than one spectacular AI-generated rewrite that requires faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  The goal is not "AI-free" code
&lt;/h2&gt;

&lt;p&gt;I sometimes see the AI coding discussion reduced to two positions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI writes everything now.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real programmers do not use AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Neither is particularly useful to me.&lt;/p&gt;

&lt;p&gt;I am building an open-source project largely by myself. AI lets me investigate more ideas, test more edge cases, review more code, and move faster than I otherwise could.&lt;/p&gt;

&lt;p&gt;I absolutely want that leverage.&lt;/p&gt;

&lt;p&gt;What I do not want is the corresponding temptation to lower the standard for what gets merged.&lt;/p&gt;

&lt;p&gt;So I have slowly arrived at a different model:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI can propose almost anything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The repository decides what survives.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reproduce first.&lt;/p&gt;

&lt;p&gt;Test behavior instead of confidence.&lt;/p&gt;

&lt;p&gt;Turn repeated mistakes into invariants.&lt;/p&gt;

&lt;p&gt;Fuzz dangerous boundaries.&lt;/p&gt;

&lt;p&gt;Replay real failures.&lt;/p&gt;

&lt;p&gt;Cross-check with other models.&lt;/p&gt;

&lt;p&gt;Run on real operating systems.&lt;/p&gt;

&lt;p&gt;Keep the changes small.&lt;/p&gt;

&lt;p&gt;And never confuse a very convincing explanation with evidence.&lt;/p&gt;

&lt;p&gt;AI slop is not inevitable.&lt;/p&gt;

&lt;p&gt;But preventing it takes more than writing "please produce high-quality code" in a prompt.&lt;/p&gt;

&lt;p&gt;You have to build a development process that assumes plausible-looking garbage will occasionally appear, then make that garbage difficult to merge.&lt;/p&gt;

&lt;p&gt;That is what I am trying to do with Network Doctor.&lt;/p&gt;

&lt;p&gt;And somewhat ironically, AI has helped me build many of the defenses against AI itself.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Network Doctor&lt;/strong&gt; is an open-source cross-platform network troubleshooting TUI written in Go. It diagnoses interface, DNS, TCP, TLS, HTTP, proxy, path-MTU, and other connectivity problems and tries to tell you where the failure actually is instead of dumping raw probe output.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/heymaikol/network-doctor" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://networkdoctor.dev/" rel="noopener noreferrer"&gt;https://networkdoctor.dev/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>I spent months building an open-source network diagnostic tool. Now I’m trying to make my first dollar.</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Sat, 19 Sep 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/heymaikol/i-spent-months-building-an-open-source-network-diagnostic-tool-now-im-trying-to-make-my-first-b1k</link>
      <guid>https://dev.to/heymaikol/i-spent-months-building-an-open-source-network-diagnostic-tool-now-im-trying-to-make-my-first-b1k</guid>
      <description>&lt;p&gt;For the last few months, I've been building &lt;strong&gt;Network Doctor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's a cross-platform terminal application for answering a deceptively simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where is this connection actually breaking?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When something on the network fails, the normal troubleshooting process tends to look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;ping&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;dig&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Try &lt;code&gt;curl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check the proxy&lt;/li&gt;
&lt;li&gt;Try another DNS server&lt;/li&gt;
&lt;li&gt;Run a traceroute&lt;/li&gt;
&lt;li&gt;Check TLS&lt;/li&gt;
&lt;li&gt;Try another network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, if you're experienced enough and collect enough evidence, you figure out whether the problem is your machine, your local network, DNS, the path, a proxy, or the service itself.&lt;/p&gt;

&lt;p&gt;I wanted one tool that could reason across those layers instead of making the user interpret each command independently.&lt;/p&gt;

&lt;p&gt;That became &lt;strong&gt;Network Doctor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Today it runs on &lt;strong&gt;Linux, macOS, and Windows&lt;/strong&gt; and checks things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interfaces and local connectivity&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;public and encrypted DNS&lt;/li&gt;
&lt;li&gt;TCP&lt;/li&gt;
&lt;li&gt;TLS&lt;/li&gt;
&lt;li&gt;HTTP and HTTPS&lt;/li&gt;
&lt;li&gt;proxies&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;path MTU&lt;/li&gt;
&lt;li&gt;service-specific connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also has Watch Mode for intermittent failures, diagnostic snapshots, remote diagnosis, two-sided diagnosis, service profiles, and a network simulator with deliberately broken networks.&lt;/p&gt;

&lt;p&gt;I just released &lt;strong&gt;v1.17.3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But this release also marks a different milestone for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The project has made $0
&lt;/h2&gt;

&lt;p&gt;I've spent a lot of time building Network Doctor.&lt;/p&gt;

&lt;p&gt;People use it. People star it. People contribute to it. It's available through package managers.&lt;/p&gt;

&lt;p&gt;Other projects have even started pointing their own users toward it for network troubleshooting.&lt;/p&gt;

&lt;p&gt;But financially, it has made me &lt;strong&gt;$0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I don't want to turn the useful parts of Network Doctor into paid features just because I want the project to become sustainable.&lt;/p&gt;

&lt;p&gt;So I'm trying something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paid help, not a paid binary
&lt;/h2&gt;

&lt;p&gt;Network Doctor can generate a sanitized support snapshot locally:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
netdoc --support support.ndoc example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>opensource</category>
      <category>devtools</category>
      <category>networking</category>
      <category>go</category>
    </item>
    <item>
      <title>Looking for Contributors: Good First Issues in Network Doctor</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Thu, 17 Sep 2026 05:02:39 +0000</pubDate>
      <link>https://dev.to/heymaikol/looking-for-contributors-good-first-issues-in-network-doctor-3fcb</link>
      <guid>https://dev.to/heymaikol/looking-for-contributors-good-first-issues-in-network-doctor-3fcb</guid>
      <description>&lt;p&gt;I’ve been working on Network Doctor, an open-source Go TUI for diagnosing network problems, and I’d like to get more people involved in the project.&lt;/p&gt;

&lt;p&gt;I currently have a few issues ready for contributors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good first issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #110 - Make the causal-evidence golden mutation test non-vacuous
&lt;/h3&gt;

&lt;p&gt;A small, test-focused issue. No production behavior changes are needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/heymaikol/network-doctor/issues/110" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor/issues/110&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  #111 - Add hermetic tests for macOS and Windows SSID command wrappers
&lt;/h3&gt;

&lt;p&gt;A slightly larger testing task involving the existing platform-specific SSID code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/heymaikol/network-doctor/issues/111" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor/issues/111&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking for something more involved?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #97 - Bound hunt shard inputs before &lt;code&gt;netdoc-sim merge&lt;/code&gt; decodes them
&lt;/h3&gt;

&lt;p&gt;This one involves input-size enforcement and is better suited to someone already comfortable with Go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/heymaikol/network-doctor/issues/97" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor/issues/97&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also several field-validation issues for contributors who have access to environments I can’t easily reproduce, including macOS, IPv6-only networks, VPN split DNS, captive portals, and managed proxy networks.&lt;/p&gt;

&lt;p&gt;Network Doctor is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/heymaikol/network-doctor" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The contributor setup is intentionally simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/heymaikol/network-doctor.git
&lt;span class="nb"&gt;cd &lt;/span&gt;network-doctor
go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
go run &lt;span class="nb"&gt;.&lt;/span&gt; github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re new to open source, that’s completely fine. The good first issues are scoped so you shouldn’t need to understand the entire project before getting started.&lt;/p&gt;

&lt;p&gt;Questions are welcome too.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>go</category>
      <category>beginners</category>
      <category>networking</category>
    </item>
    <item>
      <title>Ping Works, but HTTPS Doesn't: How to Find What Actually Broke</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Sun, 13 Sep 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/heymaikol/ping-works-but-https-doesnt-how-to-find-what-actually-broke-5c6n</link>
      <guid>https://dev.to/heymaikol/ping-works-but-https-doesnt-how-to-find-what-actually-broke-5c6n</guid>
      <description>&lt;p&gt;You've probably seen this before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ping example.com
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=18 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=54 time=17 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the network works, right?&lt;/p&gt;

&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl https://example.com
curl: (28) Connection timed out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or your browser spins forever.&lt;/p&gt;

&lt;p&gt;This is one of the most common traps in network troubleshooting: treating a successful ping as proof that "the network is fine."&lt;/p&gt;

&lt;p&gt;It isn't.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ping&lt;/code&gt; answers one fairly narrow question. Your application depends on several other things succeeding after that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ping actually proves
&lt;/h2&gt;

&lt;p&gt;Ping normally uses ICMP echo requests and replies.&lt;/p&gt;

&lt;p&gt;If a host responds, you've learned something useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your machine has some working route toward the destination&lt;/li&gt;
&lt;li&gt;packets can travel across at least part of that path&lt;/li&gt;
&lt;li&gt;the destination, or something representing it, is responding to ICMP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But an HTTPS connection needs much more.&lt;/p&gt;

&lt;p&gt;A simplified path looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Network interface
      |
Routing
      |
DNS
      |
TCP connection
      |
TLS handshake
      |
HTTP
      |
Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And real networks can add more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Proxy
VPN
Firewall
NAT
MTU problems
IPv4 / IPv6 differences
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful ICMP echo doesn't prove all of those layers work.&lt;/p&gt;

&lt;p&gt;That's why "but I can ping it" often doesn't get you very far.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS can still be the problem
&lt;/h2&gt;

&lt;p&gt;There are a few variations here.&lt;/p&gt;

&lt;p&gt;Suppose you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 1.1.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and it works.&lt;/p&gt;

&lt;p&gt;That says nothing about DNS.&lt;/p&gt;

&lt;p&gt;Try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;getent ahosts example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If name resolution fails, applications using hostnames will still be broken even though you have basic IP connectivity.&lt;/p&gt;

&lt;p&gt;There's another wrinkle: your application and your diagnostic tool may not necessarily use DNS in exactly the same way.&lt;/p&gt;

&lt;p&gt;Your system resolver, a browser using encrypted DNS, a VPN-provided resolver, and a corporate DNS setup can produce different behavior.&lt;/p&gt;

&lt;p&gt;So "DNS works" can sometimes need a more specific question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which DNS, resolving what name, from which environment?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TCP can fail even when ping succeeds
&lt;/h2&gt;

&lt;p&gt;HTTPS normally needs a TCP connection to port 443.&lt;/p&gt;

&lt;p&gt;That is a completely different exchange from ICMP.&lt;/p&gt;

&lt;p&gt;You can test it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nc &lt;span class="nt"&gt;-vz&lt;/span&gt; example.com 443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A firewall might allow ICMP while blocking TCP 443.&lt;/p&gt;

&lt;p&gt;The server might be reachable but not listening on the expected port.&lt;/p&gt;

&lt;p&gt;A VPN route might send the application traffic somewhere different.&lt;/p&gt;

&lt;p&gt;A proxy might be involved.&lt;/p&gt;

&lt;p&gt;The path could simply behave differently for the traffic your application actually uses.&lt;/p&gt;

&lt;p&gt;So this situation is perfectly possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ICMP       PASS
TCP :443   FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no contradiction there.&lt;/p&gt;

&lt;p&gt;You're testing two different things.&lt;/p&gt;

&lt;h2&gt;
  
  
  TCP working still doesn't prove HTTPS works
&lt;/h2&gt;

&lt;p&gt;Let's say port 443 accepts a connection.&lt;/p&gt;

&lt;p&gt;Great.&lt;/p&gt;

&lt;p&gt;You're still not done.&lt;/p&gt;

&lt;p&gt;Before HTTP can happen over HTTPS, the client and server need to complete a TLS handshake.&lt;/p&gt;

&lt;p&gt;TLS can fail because of things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;certificate validation&lt;/li&gt;
&lt;li&gt;hostname mismatches&lt;/li&gt;
&lt;li&gt;TLS interception&lt;/li&gt;
&lt;li&gt;protocol incompatibility&lt;/li&gt;
&lt;li&gt;a middlebox interfering with the connection&lt;/li&gt;
&lt;li&gt;the wrong service running on the port&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect that layer with tools such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you can have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DNS    PASS
TCP    PASS
TLS    FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much more useful than saying "the internet is broken."&lt;/p&gt;

&lt;p&gt;You now know roughly where to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  And TLS working doesn't prove HTTP works
&lt;/h2&gt;

&lt;p&gt;Suppose DNS resolves, TCP connects, and TLS completes.&lt;/p&gt;

&lt;p&gt;The server can still return an HTTP error.&lt;/p&gt;

&lt;p&gt;You might get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;403 Forbidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;502 Bad Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;503 Service Unavailable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a very different problem from a dead network path.&lt;/p&gt;

&lt;p&gt;The connection reached the service.&lt;/p&gt;

&lt;p&gt;The service responded.&lt;/p&gt;

&lt;p&gt;The failure has moved farther up the stack.&lt;/p&gt;

&lt;p&gt;That's why I like troubleshooting networking as a sequence of questions rather than one giant "does it work?" test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't forget proxies
&lt;/h2&gt;

&lt;p&gt;Proxies make this even more interesting.&lt;/p&gt;

&lt;p&gt;Your shell might have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;HTTPS_PROXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://proxy.example:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while also having something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NO_PROXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;internal.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now two requests to different hosts may follow completely different paths.&lt;/p&gt;

&lt;p&gt;One can go directly to the destination.&lt;/p&gt;

&lt;p&gt;The other can go through a proxy.&lt;/p&gt;

&lt;p&gt;If the proxy is down, misconfigured, or excluded incorrectly, the symptoms can look like an ordinary network failure even though the direct network path is perfectly healthy.&lt;/p&gt;

&lt;p&gt;Testing both paths can matter.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and, when appropriate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--noproxy&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; https://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one succeeds and the other doesn't, you've learned a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Path MTU problems are another nasty case
&lt;/h2&gt;

&lt;p&gt;Some failures are even stranger.&lt;/p&gt;

&lt;p&gt;Small packets work.&lt;/p&gt;

&lt;p&gt;Connections establish.&lt;/p&gt;

&lt;p&gt;Then larger transfers hang or behave unpredictably.&lt;/p&gt;

&lt;p&gt;This can happen when the effective MTU somewhere along the path is smaller than expected and Path MTU Discovery isn't working correctly.&lt;/p&gt;

&lt;p&gt;That's one reason a simple ping can be especially misleading.&lt;/p&gt;

&lt;p&gt;A tiny ICMP echo succeeding isn't proof that larger application traffic can make it through the same path successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful question isn't "does the network work?"
&lt;/h2&gt;

&lt;p&gt;A better question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the first layer that doesn't work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you want to reach something more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Interface     PASS
DNS           PASS
TCP           PASS
TLS           FAIL
HTTP          SKIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Interface     PASS
DNS           FAIL
TCP           SKIPPED
TLS           SKIPPED
HTTP          SKIPPED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are very different problems.&lt;/p&gt;

&lt;p&gt;And once you know which layer failed, the number of possible causes becomes much smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing this manually
&lt;/h2&gt;

&lt;p&gt;You absolutely can troubleshoot this with the standard tools.&lt;/p&gt;

&lt;p&gt;Depending on the problem, I regularly reach for things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip route
ping
dig
nc
curl
openssl
traceroute
mtr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those tools are excellent.&lt;/p&gt;

&lt;p&gt;The difficult part isn't usually running them.&lt;/p&gt;

&lt;p&gt;It's deciding:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;which test to run next&lt;/li&gt;
&lt;li&gt;what its result actually proves&lt;/li&gt;
&lt;li&gt;which later tests are meaningful after an earlier failure&lt;/li&gt;
&lt;li&gt;whether two failures are related or independent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is why I built &lt;strong&gt;Network Doctor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project is open source: &lt;a href="https://github.com/heymaikol/network-doctor" rel="noopener noreferrer"&gt;Network Doctor on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of treating connectivity as one yes/no test, it probes the relevant layers independently and tries to identify where the evidence stops.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can check things including the local interface, DNS, TCP, TLS, HTTP, proxy connectivity, and path MTU, then give you a diagnosis based on those results.&lt;/p&gt;

&lt;p&gt;I still use the underlying tools when I need to dig deeper. Network Doctor isn't intended to replace &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;dig&lt;/code&gt;, &lt;code&gt;mtr&lt;/code&gt;, or the rest.&lt;/p&gt;

&lt;p&gt;The goal is to get to the right one faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reverse is also true: ping can fail while everything works
&lt;/h2&gt;

&lt;p&gt;There's another reason not to treat ping as the final authority.&lt;/p&gt;

&lt;p&gt;Some networks and servers simply block or deprioritize ICMP.&lt;/p&gt;

&lt;p&gt;You can see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ping: no reply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while this works perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://example.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the application's perspective, that's not an outage.&lt;/p&gt;

&lt;p&gt;The traffic you actually care about succeeded.&lt;/p&gt;

&lt;p&gt;This is why good diagnostics need to test the protocol that matters instead of assuming ICMP represents every other kind of traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better troubleshooting habit
&lt;/h2&gt;

&lt;p&gt;The next time you hear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It can't be the network. Ping works."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ask what layer has actually been tested.&lt;/p&gt;

&lt;p&gt;Work upward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do I have an interface and route?
        ↓
Can I resolve the name?
        ↓
Can I reach the service's port?
        ↓
Can I complete TLS?
        ↓
Can I make the application request?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there is a VPN or proxy involved, test that path too.&lt;/p&gt;

&lt;p&gt;The goal isn't to collect as much command output as possible.&lt;/p&gt;

&lt;p&gt;The goal is to find the boundary between &lt;strong&gt;working&lt;/strong&gt; and &lt;strong&gt;broken&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once you know that boundary, network troubleshooting gets a lot less mysterious.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>networking</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Debugging a Network Problem From Another Machine</title>
      <dc:creator>Michael Placzek</dc:creator>
      <pubDate>Sat, 29 Aug 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/heymaikol/debugging-a-network-problem-from-another-machine-1fam</link>
      <guid>https://dev.to/heymaikol/debugging-a-network-problem-from-another-machine-1fam</guid>
      <description>&lt;p&gt;One of the most useful questions in network troubleshooting is also one of the simplest:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it fail from another machine too?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a website will not load on my laptop, trying it from another computer can immediately change the investigation.&lt;/p&gt;

&lt;p&gt;If it works there, the service probably is not down. Something about my machine, DNS configuration, VPN, firewall, route, or network path is different.&lt;/p&gt;

&lt;p&gt;If it fails there too, the problem may be farther upstream.&lt;/p&gt;

&lt;p&gt;I wanted Network Doctor to be able to ask that question directly.&lt;/p&gt;

&lt;p&gt;So I added remote diagnosis over SSH.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; ideapad github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of running the diagnosis locally, Network Doctor connects to &lt;code&gt;ideapad&lt;/code&gt;, runs the checks there, and reports the result back on my machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why another vantage point matters
&lt;/h2&gt;

&lt;p&gt;A network failure is always observed from somewhere.&lt;/p&gt;

&lt;p&gt;Suppose &lt;code&gt;github.com&lt;/code&gt; is unreachable from my workstation.&lt;/p&gt;

&lt;p&gt;I can test DNS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then TCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nc &lt;span class="nt"&gt;-vz&lt;/span&gt; github.com 443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then TLS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; github.com:443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe I inspect my routes, VPN, proxy settings, or firewall.&lt;/p&gt;

&lt;p&gt;Those tests are useful, but they all share one property: they are observing the network from the same machine.&lt;/p&gt;

&lt;p&gt;Trying the same destination from another machine gives me a new piece of evidence.&lt;/p&gt;

&lt;p&gt;Imagine this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thelio:
DNS       PASS
TCP 443   FAIL

Ideapad:
DNS       PASS
TCP 443   PASS
TLS       PASS
HTTPS     PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference is interesting.&lt;/p&gt;

&lt;p&gt;GitHub clearly is not universally unreachable. The second machine just reached it.&lt;/p&gt;

&lt;p&gt;Now I have a much smaller problem to investigate: what is different about the path from Thelio?&lt;/p&gt;

&lt;p&gt;That is often more useful than running another five commands on Thelio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning that into a command
&lt;/h2&gt;

&lt;p&gt;Network Doctor already runs network checks as a dependency graph.&lt;/p&gt;

&lt;p&gt;For an HTTPS target, for example, it can test things such as the local interface, DNS resolution, TCP connectivity, TLS, HTTP, routing, and path MTU.&lt;/p&gt;

&lt;p&gt;Normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagnose github.com from this machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With &lt;code&gt;--via&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; ideapad github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagnose github.com from ideapad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The SSH machine is the vantage point. My local machine is just controlling the run and displaying the result.&lt;/p&gt;

&lt;p&gt;That distinction becomes especially useful with service profiles.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; ideapad &lt;span class="nt"&gt;--profile&lt;/span&gt; github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The GitHub profile independently checks GitHub's website, API, normal SSH endpoint, and alternate SSH endpoint.&lt;/p&gt;

&lt;p&gt;So I can ask a more useful question than simply "can the other computer ping GitHub?"&lt;/p&gt;

&lt;p&gt;I can ask whether the actual service paths I care about work from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  It also works across operating systems
&lt;/h2&gt;

&lt;p&gt;One of my tests involved a Linux workstation controlling a Windows machine over SSH.&lt;/p&gt;

&lt;p&gt;The command was still just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; ideapad &lt;span class="nt"&gt;--profile&lt;/span&gt; github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remote worker ran on Windows, while I launched and viewed the diagnosis from Linux.&lt;/p&gt;

&lt;p&gt;I like this because the two machines do not need to be identical.&lt;/p&gt;

&lt;p&gt;In fact, sometimes it is more interesting when they are not.&lt;/p&gt;

&lt;p&gt;A Windows laptop and a Linux workstation might have different DNS configuration, routes, VPN software, firewall rules, interfaces, or network locations.&lt;/p&gt;

&lt;p&gt;Those differences are exactly what can make a second vantage point useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not just "run the command over SSH"
&lt;/h2&gt;

&lt;p&gt;I could obviously do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh ideapad netdoc github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And sometimes that is perfectly sufficient.&lt;/p&gt;

&lt;p&gt;The reason I wanted remote execution inside Network Doctor is that the location of the probe becomes part of the diagnostic model.&lt;/p&gt;

&lt;p&gt;That means the same mechanism can be used with profiles and structured output instead of treating the remote command as an unrelated terminal session.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; ideapad &lt;span class="nt"&gt;--profile&lt;/span&gt; github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;still means "run the GitHub diagnostic profile," while &lt;code&gt;ideapad&lt;/code&gt; answers the separate question of where those probes should originate.&lt;/p&gt;

&lt;p&gt;I think that separation is useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What should I test?     --profile github
Where should I test it? --via ideapad
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What this can tell you
&lt;/h2&gt;

&lt;p&gt;A second vantage point does not magically identify every network problem.&lt;/p&gt;

&lt;p&gt;But it can eliminate a lot of possibilities quickly.&lt;/p&gt;

&lt;p&gt;If the same destination fails from both machines in the same way, that is evidence that the issue may not be specific to one host.&lt;/p&gt;

&lt;p&gt;If it fails from one machine but works from another, host-specific or path-specific explanations become much more interesting.&lt;/p&gt;

&lt;p&gt;If DNS answers differ, investigate DNS.&lt;/p&gt;

&lt;p&gt;If DNS agrees but TCP connectivity differs, look farther down the path.&lt;/p&gt;

&lt;p&gt;If TCP succeeds from both but TLS fails from only one, that is another useful distinction.&lt;/p&gt;

&lt;p&gt;The important part is not simply having more probes.&lt;/p&gt;

&lt;p&gt;It is having &lt;strong&gt;different observations that can disagree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Disagreement is often where the useful information is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The larger idea
&lt;/h2&gt;

&lt;p&gt;Network troubleshooting tools usually become collections of tests:&lt;/p&gt;

&lt;p&gt;ping something.&lt;/p&gt;

&lt;p&gt;Resolve something.&lt;/p&gt;

&lt;p&gt;Open a socket.&lt;/p&gt;

&lt;p&gt;Inspect a route.&lt;/p&gt;

&lt;p&gt;Check a certificate.&lt;/p&gt;

&lt;p&gt;Those are necessary, but I am increasingly interested in the reasoning that connects the observations.&lt;/p&gt;

&lt;p&gt;A diagnostic tool should help answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does this result rule out?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remote diagnosis adds another way to obtain that evidence.&lt;/p&gt;

&lt;p&gt;Instead of endlessly probing the same broken machine, sometimes the best next probe is the same test from somewhere else.&lt;/p&gt;

&lt;p&gt;That is now one command in Network Doctor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netdoc &lt;span class="nt"&gt;--via&lt;/span&gt; another-machine target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Network Doctor is open source, and I would especially like to hear about cases where comparing two machines gives a misleading result or where the remote diagnosis reaches the wrong conclusion.&lt;/p&gt;

&lt;p&gt;Those are the interesting bugs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/heymaikol/network-doctor" rel="noopener noreferrer"&gt;https://github.com/heymaikol/network-doctor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>go</category>
      <category>networking</category>
    </item>
  </channel>
</rss>
