<?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: Nikolay Chirkov</title>
    <description>The latest articles on DEV Community by Nikolay Chirkov (@nikolay_chirkov).</description>
    <link>https://dev.to/nikolay_chirkov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3117648%2Ff7acb5fe-ded7-4e25-8d47-07883a02393e.png</url>
      <title>DEV Community: Nikolay Chirkov</title>
      <link>https://dev.to/nikolay_chirkov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikolay_chirkov"/>
    <language>en</language>
    <item>
      <title>$100K/day cloud bill isn't a Bug – it's by Design</title>
      <dc:creator>Nikolay Chirkov</dc:creator>
      <pubDate>Thu, 08 May 2025 19:57:33 +0000</pubDate>
      <link>https://dev.to/nikolay_chirkov/100kday-cloud-bill-isnt-a-bug-its-by-design-5fk4</link>
      <guid>https://dev.to/nikolay_chirkov/100kday-cloud-bill-isnt-a-bug-its-by-design-5fk4</guid>
      <description>&lt;p&gt;Cloud platforms are built to scale. That’s their core feature — and their hidden risk. Every request to a cloud function, database, or storage API has a cost. If enough requests arrive, even legitimate-looking ones, the backend will scale automatically and incur that cost — and the account owner will receive the bill.&lt;/p&gt;

&lt;p&gt;This is not an exception. It is the intended behavior.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Real Incidents of Cost-Based Abuse
&lt;/h1&gt;

&lt;p&gt;Several public cases illustrate how cloud billing can be exploited or spiral out of control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.reddit.com/r/selfhosted/comments/1kdxqwj/burned_by_cloud_100k_looking_at_self_hosting/" rel="noopener noreferrer"&gt;$100K in 24 hours via Firebase&lt;/a&gt;&amp;nbsp;– A WebGL hosting app saw a sudden traffic spike and was billed over $100,000. The cloud service scaled perfectly. No failure occurred — other than financial.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.reddit.com/r/googlecloud/comments/1kg9icb/one_public_firebase_file_one_day_98000_how_it/" rel="noopener noreferrer"&gt;One public file in Firebase = $98K&lt;/a&gt;&amp;nbsp;– A single shared file led to massive egress usage and a near six-figure bill.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.reddit.com/r/googlecloud/comments/1jzoi8v/ddos_attack_facing_100000_bill/" rel="noopener noreferrer"&gt;GCP DDoS → $100K+ projected bill&lt;/a&gt;&amp;nbsp;– Valid-looking requests during a DDoS ran up charges with no way to stop them quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples — and many others — follow the same pattern: no security breach, just usage that scaled and billed exactly as designed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Protections Often Fail
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Rate limits are global and imprecise&lt;/strong&gt;&amp;nbsp;Most limits apply per service, not per client. For example: a database may be capped at 100 queries per second. If there are 100 legitimate clients and 1,000,000 automated attackers,&amp;nbsp;&lt;em&gt;legitimate users may not be served at all&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limits are hard to balance across services&lt;/strong&gt;&amp;nbsp;Every backend (DB, API, cache) needs separate tuning. Too tight = outages. Too loose = runaway costs. In distributed systems, this balance is nearly impossible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Budget alerts are too late&lt;/strong&gt;&amp;nbsp;Billing data can lag by 15 minutes to several hours. By the time alerts arrive, thousands of dollars may already be spent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attackers look like users&lt;/strong&gt;&amp;nbsp;Tokens can be pulled from apps or frontends. Even time-limited tokens — like&amp;nbsp;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html" rel="noopener noreferrer"&gt;AWS pre-signed S3 URLs&lt;/a&gt;&amp;nbsp;— can be refreshed by any client the attacker controls.&lt;/p&gt;

&lt;p&gt;Becoming a “legitimate client” is often as simple as making an HTTPS request.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Could Help?
&lt;/h1&gt;

&lt;p&gt;To protect against cost-based abuse, three mechanisms can be combined:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Per-client real-time quota enforcement&lt;/strong&gt;&amp;nbsp;Each client gets a monetary quota. Every request (log, DB op, message) deducts from it. Clients near their limit are automatically slowed or paused — without affecting others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Proof-of-work before provisioning&lt;/strong&gt;&amp;nbsp;New clients must solve a computational puzzle before access. This cost is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Negligible (milliseconds) under normal use — for both real users and attackers
&lt;/li&gt;
&lt;li&gt;Increased during abuse — e.g., if mass registrations occur
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mechanism uses a&amp;nbsp;&lt;strong&gt;pool of bcrypt hashes&lt;/strong&gt;&amp;nbsp;with a dynamic seed, difficulty, and verification target.&amp;nbsp;&lt;a href="https://aethernet.io/technology#register-a-client-with-proof-of-work1" rel="noopener noreferrer"&gt;More details here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Optional cleanup and usage-aware control&lt;/strong&gt;&amp;nbsp;Inactive clients can be dropped. Clients near quota can trigger backend checks (how fast was quota used, is usage organic, etc.).&amp;nbsp;&lt;em&gt;Note: this is app-specific and may require custom business logic.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Outcome: Cost-Limited Scalability
&lt;/h1&gt;

&lt;p&gt;When every client has a cap and must do work to onboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abuse becomes expensive
&lt;/li&gt;
&lt;li&gt;Real users aren't throttled globally
&lt;/li&gt;
&lt;li&gt;Backend resources scale safely&lt;/li&gt;
&lt;li&gt;Alerts aren’t needed to stop financial loss — enforcement is automatic
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The attack surface shifts: instead of “can I make this API fail?”, it becomes “can I afford to keep sending requests?”&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Thought
&lt;/h1&gt;

&lt;p&gt;Clouds scale. And they bill. What they don’t do — by default — is distinguish between a valuable client and a costly one.&lt;/p&gt;

&lt;p&gt;Security doesn’t end at authentication. When requests generate cost,&amp;nbsp;&lt;strong&gt;economic boundaries matter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Systems need a way to say “no”&amp;nbsp;&lt;em&gt;before&lt;/em&gt;&amp;nbsp;the invoice says “too late.”&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Interviewing Software Developers: From Junior to Architect in a Single Programming Task</title>
      <dc:creator>Nikolay Chirkov</dc:creator>
      <pubDate>Tue, 06 May 2025 05:55:53 +0000</pubDate>
      <link>https://dev.to/nikolay_chirkov/interviewing-software-developers-from-junior-to-architect-in-a-single-programming-task-1gdd</link>
      <guid>https://dev.to/nikolay_chirkov/interviewing-software-developers-from-junior-to-architect-in-a-single-programming-task-1gdd</guid>
      <description>&lt;p&gt;Over the years, I’ve interviewed around 100 software developers at Google and roughly the same number across my own companies. One thing has become very clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Resumes don’t work.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They’re too noisy. You get flooded with titles, buzzwords, and irrelevant project summaries. So I distilled everything down to one single task. One prompt I can give to anyone — junior or architect — and instantly get a signal.&lt;/p&gt;

&lt;p&gt;The task?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write a library that calculates the sum of a vector of values.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s it. No extra requirements. The beauty is that it looks trivial — but the depth reveals itself as the candidate explores edge cases, generalization, scalability, performance, and design.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪜 Level 1: The Junior Developer
&lt;/h2&gt;

&lt;p&gt;Most junior candidates start like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It compiles. It runs. But you immediately see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;const&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No null check&lt;/li&gt;
&lt;li&gt;Indexing instead of pointer-based iteration&lt;/li&gt;
&lt;li&gt;No header splitting or inline consideration&lt;/li&gt;
&lt;li&gt;No thoughts about reusability or API quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Already, you’re learning a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪜 Level 2: The Mid-Level Developer
&lt;/h2&gt;

&lt;p&gt;The next tier generalizes the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then comes overflow protection — separate input/output types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;I&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;O&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They start thinking in terms of the STL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;InputIt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputIt&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InputIt&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And even bring in &lt;code&gt;constexpr&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;InputIt&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputIt&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InputIt&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually someone realizes this is already in the standard library (&lt;code&gt;std::accumulate&lt;/code&gt;) — and more advanced candidates point out &lt;code&gt;std::reduce&lt;/code&gt;, which is reorderable and SIMD/multithread-friendly (and &lt;code&gt;constexpr&lt;/code&gt; in C++20).&lt;/p&gt;

&lt;p&gt;At this point, we’re talking fluency in STL, value categories, compile-time evaluation, and API design.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Level 3: The Senior Engineer
&lt;/h2&gt;

&lt;p&gt;Now the conversation shifts.&lt;/p&gt;

&lt;p&gt;They start asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s the maximum number of elements?&lt;/li&gt;
&lt;li&gt;Will the data fit in memory?&lt;/li&gt;
&lt;li&gt;Is it a single-machine process or distributed?&lt;/li&gt;
&lt;li&gt;Is the data streamed from disk?&lt;/li&gt;
&lt;li&gt;Is disk the bottleneck?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They consider &lt;strong&gt;chunked reads&lt;/strong&gt;, &lt;strong&gt;asynchronous prefetching&lt;/strong&gt;, &lt;strong&gt;thread pool handoff&lt;/strong&gt;, and &lt;strong&gt;single-threaded summing&lt;/strong&gt; when disk I/O dominates.&lt;/p&gt;

&lt;p&gt;Then comes UX: can the operation be &lt;em&gt;paused&lt;/em&gt; or &lt;em&gt;aborted&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Now we need a serializable processing state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Summarizer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Summarizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputIt&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InputIt&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Summarizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ifstream&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Summarizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;distributed_nodes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;max_memory_to_use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;GetProgress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Resume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now they’re designing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Persistent resumability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State encoding&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Granular progress tracking&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous error callbacks&lt;/strong&gt; (e.g., if input files are missing)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging and performance tracing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory usage accounting&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Numeric &lt;strong&gt;precision improvements&lt;/strong&gt; (e.g., sorting values or using Kahan summation)&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;partial sort/save&lt;/strong&gt; for huge datasets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They’ve moved beyond code — this is system architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ Level 4: The Architect
&lt;/h2&gt;

&lt;p&gt;They start asking questions few others do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this running on &lt;strong&gt;CPU or GPU&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Is the data already in GPU memory?&lt;/li&gt;
&lt;li&gt;Should the GPU be used for batch summing?&lt;/li&gt;
&lt;li&gt;Should the CPU be used first while shaders compile?&lt;/li&gt;
&lt;li&gt;Can shaders be &lt;strong&gt;precompiled&lt;/strong&gt;, versioned, and cached?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They propose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Abstract device interface&lt;/strong&gt; (CPU/GPU/DSP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://reddit.com/r/aethernet/comments/1kd79g7/crossplatform_software_development_part_1_yes/" rel="noopener noreferrer"&gt;Cross-platform development&lt;/a&gt;&lt;/strong&gt; trade-offs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution policy selection&lt;/strong&gt; at runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary shader storage&lt;/strong&gt;, deployed per version&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On-device code caching and validation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And memory gets serious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the library &lt;strong&gt;allocate memory&lt;/strong&gt;, or use &lt;strong&gt;externally-managed buffers&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;map/unmap&lt;/strong&gt;, &lt;strong&gt;pinned memory&lt;/strong&gt;, &lt;strong&gt;DMA&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detailed profiling: cold vs. warm latencies&lt;/li&gt;
&lt;li&gt;Per-device throughput models&lt;/li&gt;
&lt;li&gt;Smart batching&lt;/li&gt;
&lt;li&gt;First-run performance vs. steady-state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then come platform constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compile-time configuration to &lt;strong&gt;shrink binary size&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;heapless environments&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;platform-specific allocators&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encryption of in-flight and at-rest data&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory zeroing&lt;/strong&gt; post-use&lt;/li&gt;
&lt;li&gt;Compliance with &lt;strong&gt;SOC 2&lt;/strong&gt; and similar standards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💥 Bonus Level: The “Startuper”
&lt;/h2&gt;

&lt;p&gt;There should probably be one more level of seniority: the &lt;strong&gt;“startuper”&lt;/strong&gt; — someone who recently failed because they tried to build the &lt;em&gt;perfect&lt;/em&gt;, highly-extensible system right away…&lt;/p&gt;

&lt;p&gt;Instead of just sticking to the “junior-level” sum function — until they had at least one actual customer. 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  ☁️ Real-World Parallel: Æthernet
&lt;/h2&gt;

&lt;p&gt;This progression is exactly what we saw while building the &lt;a href="https://github.com/aethernetio/aether-client-cpp" rel="noopener noreferrer"&gt;Æthernet client library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We started with a minimal concept: adapters that wrap transport methods like Ethernet, Wi-Fi, GSM, satellite.&lt;/p&gt;

&lt;p&gt;But the design questions came fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if a client has &lt;strong&gt;multiple adapters&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;What if one fails? Add a &lt;strong&gt;backup policy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What if latency is critical? Add a &lt;strong&gt;redundant policy&lt;/strong&gt;: duplicate each message across all adapters&lt;/li&gt;
&lt;li&gt;What if we want &lt;strong&gt;backup within groups&lt;/strong&gt;, and &lt;strong&gt;parallel send across groups&lt;/strong&gt;? Introduce &lt;strong&gt;adapter groups&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then came the “infinite design moment”:&lt;/p&gt;

&lt;p&gt;What if a client wants to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send &lt;strong&gt;small messages&lt;/strong&gt; through LTE (cheap)&lt;/li&gt;
&lt;li&gt;Send &lt;strong&gt;large messages&lt;/strong&gt; through fiber (fast)&lt;/li&gt;
&lt;li&gt;Route messages differently based on &lt;strong&gt;user-defined metadata&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Swap policies based on &lt;strong&gt;live network metrics&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point, you realize: &lt;strong&gt;this never ends&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So we stopped.&lt;/p&gt;

&lt;p&gt;We &lt;strong&gt;open-sourced&lt;/strong&gt; the client libraries.&lt;br&gt;
We let users define their own policies.&lt;br&gt;
Because the most scalable design is knowing &lt;strong&gt;where to stop&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Final Thought
&lt;/h2&gt;

&lt;p&gt;This one task — &lt;code&gt;sum()&lt;/code&gt; — exposes almost everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical depth&lt;/li&gt;
&lt;li&gt;Communication style&lt;/li&gt;
&lt;li&gt;Architectural insight&lt;/li&gt;
&lt;li&gt;Prioritization&lt;/li&gt;
&lt;li&gt;Practical vs. ideal tradeoffs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It reveals if someone knows how to build things that &lt;em&gt;work&lt;/em&gt;, how to make them &lt;em&gt;better&lt;/em&gt;, and — most importantly — how to recognize when to &lt;strong&gt;stop&lt;/strong&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cross-Platform Software Development – Part 1: Yes, Bytes Can Be 9 Bits</title>
      <dc:creator>Nikolay Chirkov</dc:creator>
      <pubDate>Fri, 02 May 2025 21:28:26 +0000</pubDate>
      <link>https://dev.to/nikolay_chirkov/cross-platform-software-development-part-1-yes-bytes-can-be-9-bits-2c71</link>
      <guid>https://dev.to/nikolay_chirkov/cross-platform-software-development-part-1-yes-bytes-can-be-9-bits-2c71</guid>
      <description>&lt;p&gt;When we say &lt;em&gt;cross-platform&lt;/em&gt;, we often underestimate just how diverse platforms really are. Did you know the last commercial computer using 9-bit bytes was shut down only 30 years ago? That was the PDP-10—still running when C was dominant, C++ was just emerging (but not yet standardized), Java hadn’t launched (just one year before its release), and Python was still in development (two years before version 1.0).&lt;/p&gt;

&lt;p&gt;That kind of diversity hasn’t gone away—it’s just shifted. Today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are 35+ active CPU architecture families: x86/64, Arm, MIPS, RISC-V, Xtensa, TriCore, SPARC, PIC, AVR, and many more
&lt;/li&gt;
&lt;li&gt;Some use unusual instruction widths (e.g., &lt;a href="https://www.padauk.com.tw" rel="noopener noreferrer"&gt;13-bit for Padauk’s $0.03 MCU&lt;/a&gt;)
&lt;/li&gt;
&lt;li&gt;Not all CPUs support floating-point—or even 8-bit operations
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And beyond the hardware:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;15+ actively used IDEs
&lt;/li&gt;
&lt;li&gt;10+ build systems (CMake, Bazel, Make, etc.)
&lt;/li&gt;
&lt;li&gt;10+ CI/CD tools
&lt;/li&gt;
&lt;li&gt;Multiple documentation systems (e.g., Doxygen)
&lt;/li&gt;
&lt;li&gt;Dozens of compliance and certification standards (MISRA C++, aerospace, safety, security, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if your library is just &lt;code&gt;int sum(int a, int b)&lt;/code&gt;, complexity sneaks in. You have to think about integration, testing, versioning, documentation—and possibly even certification or safety compliance.&lt;/p&gt;

&lt;p&gt;Over time, we’ve solved many problems that turned out to be avoidable. Why? Because cross-platform development forces you to explore the strange corners of computing. This article series is our way of sharing those lessons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why C++?
&lt;/h2&gt;

&lt;p&gt;We’re focusing on C++ because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It compiles to native code and runs without a virtual machine (unlike Java)
&lt;/li&gt;
&lt;li&gt;It’s a descendant of C, with a wealth of low-level, highly optimized libraries
&lt;/li&gt;
&lt;li&gt;It builds for almost any architecture—except the most constrained devices, where pure C, mini-C (Padauk), or assembly is preferred
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes it the language of choice for serious cross-platform development—at least on CPUs. We’re skipping GPUs, FPGAs, and low-level peripherals (e.g., GPIO, DMA) for now, as they come with their own portability challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not C?
&lt;/h2&gt;

&lt;p&gt;C is still a valid choice for embedded and systems development—but modern C++ offers major advantages. C++17 is supported by all major toolchains and improves development by providing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Templates that dramatically reduce boilerplate and code size
&lt;/li&gt;
&lt;li&gt;Compile-time programming (metaprogramming), simplifying toolchains and shifting logic from runtime to compile time
&lt;/li&gt;
&lt;li&gt;Stronger type systems
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, binary size can increase—but with proper design, it’s manageable. Features like exceptions, RTTI, and STL containers can be selectively disabled or replaced. The productivity and maintainability gains often outweigh the cost, especially when building reusable cross-platform libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Think About Requirements
&lt;/h2&gt;

&lt;p&gt;You can’t build a library that runs &lt;em&gt;everywhere&lt;/em&gt;—but you can plan wisely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List all platforms you want to support
&lt;/li&gt;
&lt;li&gt;Choose the smallest subset of toolchains (IDE, build system, CI) that covers most of them
&lt;/li&gt;
&lt;li&gt;Stick with standard ecosystems (e.g., Git + GitHub) for sharing and integration
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example: Big-endian support
&lt;/h3&gt;

&lt;p&gt;If your library needs to support communication between systems with different endianness (e.g., a little-endian C++ app and a big-endian Java app), it’s better to handle byte order explicitly from the start.&lt;/p&gt;

&lt;p&gt;Adding byte-swapping now might increase complexity by, say, 3%. But retrofitting it later—especially after deployment—could cost, say, 30% more in refactoring, debugging, and testing.&lt;/p&gt;

&lt;p&gt;Still, ask: &lt;em&gt;Does this broaden our potential market?&lt;/em&gt; Supporting cross-endian interaction makes your library usable in more environments—especially where Java (which uses big-endian formats) is involved. It’s often safer and easier to normalize data on the C++ side than to change byte handling in Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements Are Multidimensional
&lt;/h2&gt;

&lt;p&gt;Even a single feature—like big-endian support—adds complexity to your CI/CD matrix. Cross-platform code must be tested across combinations of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU architectures
&lt;/li&gt;
&lt;li&gt;Compilers
&lt;/li&gt;
&lt;li&gt;Toolchains
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that’s just the beginning. A typical project spans many other dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build configurations (debug, release, minimal binary size)
&lt;/li&gt;
&lt;li&gt;Optional modules (e.g., pluggable hash algorithms)
&lt;/li&gt;
&lt;li&gt;Hardware features (e.g., FPU availability)
&lt;/li&gt;
&lt;li&gt;Compile-time flags (e.g., log verbosity, filtering, platform constraints)
&lt;/li&gt;
&lt;li&gt;Business logic flags—often hundreds of &lt;code&gt;#define&lt;/code&gt;s
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each dimension multiplies the test matrix. The challenge isn’t just making code portable—it’s keeping it maintainable.&lt;/p&gt;

&lt;p&gt;Supporting a new CPU architecture means expanding your CI/CD infrastructure—especially if using GitHub Actions. Many architectures require local runners, which are harder to manage. Pre-submit tests for such configurations can take tens of minutes per run (&lt;a href="https://github.com/aethernetio/aether-client-cpp/blob/main/.github/workflows/ci-cd-multi-platforms.yml" rel="noopener noreferrer"&gt;see our multi-platform CI config&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Compile-time customization increases complexity further. Our &lt;a href="https://github.com/aethernetio/aether-client-cpp/blob/main/aether/config.h" rel="noopener noreferrer"&gt;&lt;code&gt;config.h&lt;/code&gt;&lt;/a&gt; in the Aethernet C++ client toggles options like floating-point support, logging verbosity, and platform-specific constraints. Multiply that by every build configuration and platform, and you get an idea of how quickly things grow.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>aethernet</category>
    </item>
  </channel>
</rss>
