<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CodeBlueprint</title>
	<atom:link href="https://sysdev.me/feed/" rel="self" type="application/rss+xml" />
	<link>https://sysdev.me</link>
	<description>Architecture, Leadership, Innovation, Mastery</description>
	<lastBuildDate>Tue, 03 Jun 2025 11:27:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>
<site xmlns="com-wordpress:feed-additions:1">63298517</site>	<item>
		<title>Go Optimization Guide, Networking</title>
		<link>https://sysdev.me/go-optimization-guide-net/</link>
					<comments>https://sysdev.me/go-optimization-guide-net/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Tue, 03 Jun 2025 11:27:03 +0000</pubDate>
				<category><![CDATA[Books, articles, lectures...]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[pitfalls]]></category>
		<category><![CDATA[Software Architecture]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3223</guid>

					<description><![CDATA[Writing about Go performance is one thing. Writing about networking performance in Go is something else entirely. Turns out it’s incomparably more involved. Exploring practical networking patterns meant going beyond code: testing across different AWS instance types, experimenting with system-level tunings, validating behavior on multiple operating systems, and chasing edge cases that only show up under real... <a class="more-link" href="https://sysdev.me/go-optimization-guide-net/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/go-optimization-guide/" rel="bookmark" title="Go Optimization Guide">Go Optimization Guide</a></li>
<li><a href="https://sysdev.me/secure-coding-guide/" rel="bookmark" title="Secure Coding Guide от Apple">Secure Coding Guide от Apple</a></li>
<li><a href="https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/" rel="bookmark" title="GFSM: A Simple and Fast Finite State Machine for Go">GFSM: A Simple and Fast Finite State Machine for Go</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> Writing about Go performance is one thing. Writing about networking performance in Go is something else entirely. </p> 
 <p> Turns out it’s incomparably more involved. Exploring practical networking patterns meant going beyond code: testing across different AWS instance types, experimenting with system-level tunings, validating behavior on multiple operating systems, and chasing edge cases that only show up under real traffic. </p> 
 <p> It’s been a deep dive—equal parts technical and exploratory. The work isn’t finished, but I’ve decided it’s worth sharing its current state. Honestly, I&#8217;m a bit tired and want to pause the guide writing for a while. </p> 
 <p> If you’re building high-throughput services, tuning TCP, or just trying to push Go’s networking stack further, you might find something useful here: <a href="https://goperf.dev/02-networking/" target="_blank" rel="noopener">goperf.dev/02-networking</a> </p> 
 <p> Feedback, benchmarks, and counterexamples are always welcome. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/go-optimization-guide/" rel="bookmark" title="Go Optimization Guide">Go Optimization Guide</a></li>
<li><a href="https://sysdev.me/secure-coding-guide/" rel="bookmark" title="Secure Coding Guide от Apple">Secure Coding Guide от Apple</a></li>
<li><a href="https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/" rel="bookmark" title="GFSM: A Simple and Fast Finite State Machine for Go">GFSM: A Simple and Fast Finite State Machine for Go</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/go-optimization-guide-net/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3223</post-id>	</item>
		<item>
		<title>Go Optimization Guide</title>
		<link>https://sysdev.me/go-optimization-guide/</link>
					<comments>https://sysdev.me/go-optimization-guide/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Fri, 04 Apr 2025 10:02:22 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Have a look]]></category>
		<category><![CDATA[Optimization]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3217</guid>

					<description><![CDATA[So, I have a new shiny toy – Go Optimization Guide! And the toy consumes quite a lot of my free time, considering I do not have much. This is a work in progress, and I am actively adding new info there. Why do I believe this is needed? Because even Go doesn’t expose as many... <a class="more-link" href="https://sysdev.me/go-optimization-guide/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/secure-coding-guide/" rel="bookmark" title="Secure Coding Guide от Apple">Secure Coding Guide от Apple</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <span data-preserver-spaces="true">So, I have a new shiny toy – </span><a class="editor-rtfLink" href="http://goperf.dev/" target="_blank" rel="noopener"><span data-preserver-spaces="true">Go Optimization Guide</span></a><span data-preserver-spaces="true">! And the toy consumes quite a lot of my free time, considering I do not have much. </span><span data-preserver-spaces="true">This</span><span data-preserver-spaces="true"> is a work in progress, and I am actively adding new info there. Why do I believe this is needed? Because even Go doesn’t expose as many opportunities for performance tuning as languages like C++ or Rust, it still provides plenty of opportunities to make your applications significantly faster. At the same time, I do not see anything practical that covers this area. Sure, there’s the go-per-book, but maybe it&#8217;s because of my broad C++ background, but I do not think it&#8217;s practical enough or easy to read or adopt in real projects. I needed something clear, straightforward, and, I say, enjoyable! </span> </p> 
 <p> The initial part of my guide is complete and relatively polished based on the feedback I have received. The next step is to develop the networking section because I believe Go is fundamentally about networking apps. Therefore, I&#8217;m not planning to post anything here for a while, at least until my new project reaches a reasonable state. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/secure-coding-guide/" rel="bookmark" title="Secure Coding Guide от Apple">Secure Coding Guide от Apple</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/go-optimization-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3217</post-id>	</item>
		<item>
		<title>C++ still lacks switch on strings</title>
		<link>https://sysdev.me/c-still-lacks-switch-on-strings/</link>
					<comments>https://sysdev.me/c-still-lacks-switch-on-strings/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Mon, 17 Feb 2025 12:13:27 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Optimization]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3197</guid>

					<description><![CDATA[C++ is a powerful language, and I genuinely love it, but sometimes, even in modern versions, it lacks some surprisingly simple features. One such missing feature is switch on std::string. You’d think that by now, we could use a switch statement on strings just like we do with integers or enums—after all, Go has it!... <a class="more-link" href="https://sysdev.me/c-still-lacks-switch-on-strings/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/get-current-for-loop-count/" rel="bookmark" title="Как получить индекс в цикле for">Как получить индекс в цикле for</a></li>
<li><a href="https://sysdev.me/cpp-monitor-pattern/" rel="bookmark" title="Монитор от Герба Саттера">Монитор от Герба Саттера</a></li>
<li><a href="https://sysdev.me/branch-prediction/" rel="bookmark" title="Ускорение ветвления в C++">Ускорение ветвления в C++</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<div id="attachment_3202" style="width: 210px" class="wp-caption alignleft"><a href="https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove.jpeg"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-3202" class="wp-image-3202 size-medium" src="https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-200x300.jpeg" alt="" width="200" height="300" srcset="https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-200x300.jpeg 200w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-683x1024.jpeg 683w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-768x1152.jpeg 768w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-1024x1536.jpeg 1024w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-500x750.jpeg 500w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-150x225.jpeg 150w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-1200x1800.jpeg 1200w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-400x600.jpeg 400w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove-800x1200.jpeg 800w, https://sysdev.me/wp-content/uploads/2025/02/Birch-Grove.jpeg 1365w" sizes="(max-width: 200px) 100vw, 200px" /></a><p id="caption-attachment-3202" class="wp-caption-text">Birch Grove is just 40 minutes from Bishkek. Although I was concerned about the strong, foggy weather, it was an amazing opportunity for photography! </p> </div>
 <p> C++ is a powerful language, and I genuinely love it, but sometimes, even in modern versions, it lacks some surprisingly simple features. One such missing feature is switch on <inl_code>std::string</inl_code>. You’d think that by now, we could use a switch statement on strings just like we do with integers or enums—after all, Go has it! But no, C++ keeps us on our toes. </p> 
 <p> Why Doesn’t C++ Support switch on strings? Because &#8220;you only pay for what you use,&#8221; which is the standard C++ mantra. The switch statement in C++ relies on integral types. Under the hood, it works by converting the case values into jump table indices for efficient execution. But <inl_code>std::string</inl_code> (or even <inl_code>std::string_view</inl_code>) is not an integral type—it’s a more complex data structure. That’s why you can’t simply do: <br /> 
<span id="more-3197"></span> </p> 
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>msg<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>get_value<span style="color: #000080;">&lt;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #666666;">// Nope, not possible :-(</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">case</span> <span style="color: #FF0000;">&quot;topology&quot;</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// Handle network topology</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">case</span> <span style="color: #FF0000;">&quot;broadcast&quot;</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// Handle network broadcast</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></div>
 <p> So… how do we work around this? We need a way to turn strings into something <inl_code>switch</inl_code> can handle—like an integer. And that’s where hashing comes in. If we can map strings to unique integer values at compile time, we can switch on those instead. To do so, we need a user-defined <strong>literal operator</strong> and compile-time hash function. Something like this: </p> 
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #0000ff;">constexpr</span> <span style="color: #0000ff;">uint64_t</span> hash<span style="color: #008000;">&#40;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">string_view</span> str<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">uint64_t</span> hash <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> chr <span style="color: #008080;">:</span> str<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; hash <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>hash <span style="color: #000040;">*</span> <span style="color: #0000dd;">131</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">+</span> chr<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> hash<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">constexpr</span> <span style="color: #0000ff;">uint64_t</span> operator<span style="color: #FF0000;">&quot;&quot;</span> _hash<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> str, <span style="color: #0000ff;">size_t</span> len<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> hash<span style="color: #008000;">&#40;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">string_view</span><span style="color: #008000;">&#40;</span>str, len<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></div>
 <p> And, no magic, we have <inl_code>switch</inl_code> on strings! </p> 
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>hash<span style="color: #008000;">&#40;</span>msg<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>get_value<span style="color: #000080;">&lt;</span>mf<span style="color: #008080;">::</span><span style="color: #007788;">data_type</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">case</span> <span style="color: #FF0000;">&quot;topology&quot;</span>_hash<span style="color: #008080;">:</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// Handle topology case</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">case</span> <span style="color: #FF0000;">&quot;broadcast&quot;</span>_hash<span style="color: #008080;">:</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// Handle broadcast case</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// Handle unknown case</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></div>
 <p> There are some downsides to using this approach, specifically regarding hash collisions. Hashing introduces a small, but non-zero, risk of collisions. The proposed hash function, which multiplies the current hash by 131 and adds each character, is sufficiently effective for this use case. It provides a fast, compile-time method to map short, distinct string literals to unique integer values. </p> 
 <p> The choice of 131 as a multiplier contributes to achieving a reasonable distribution of values, thus reducing the likelihood of collisions, especially for a limited set of keywords like &#8220;topology,&#8221; &#8220;broadcast,&#8221; and others. The number 131 is commonly used in simple hash functions because it is a prime number. This helps to spread out the hash values more evenly across the available space, minimizing clustering and improving distribution properties. Additionally, it is small enough to maintain fast calculations while ensuring sufficient entropy accumulation over short strings. </p> 
 <p> Since the hash is computed at compile-time (using <inl_code>constexpr</inl_code>), there is no runtime overhead, and the resulting integer comparisons in switch statements remain <strong>O(1)</strong>. This makes this approach both efficient and practical for situations involving a limited number of predefined strings. Furthermore, the risk of hash collisions is exceedingly low for a small number of strings. Using the Birthday Problem approximation, we can estimate that even with 1,000 unique strings, the collision probability remains below 0.000003%, making it practically irrelevant for most real-world applications where a switch statement would be used. </p> 
 <p> It’s ridiculous that in 2025, we still have to hack our way around something as basic as <inl_code>switch</inl_code> on strings in C++. But on the bright side, this was a perfect excuse to use a user-defined literal (operator&#8221;&#8221;) finally! It’s one of those C++ features you rarely use, but it feels like a wizard when you do. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/get-current-for-loop-count/" rel="bookmark" title="Как получить индекс в цикле for">Как получить индекс в цикле for</a></li>
<li><a href="https://sysdev.me/cpp-monitor-pattern/" rel="bookmark" title="Монитор от Герба Саттера">Монитор от Герба Саттера</a></li>
<li><a href="https://sysdev.me/branch-prediction/" rel="bookmark" title="Ускорение ветвления в C++">Ускорение ветвления в C++</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/c-still-lacks-switch-on-strings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3197</post-id>	</item>
		<item>
		<title>AI, Software Engineering, and the Evolution of Code Generation</title>
		<link>https://sysdev.me/ai-software-engineering-and-the-evolution-of-code-generation/</link>
					<comments>https://sysdev.me/ai-software-engineering-and-the-evolution-of-code-generation/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Wed, 05 Feb 2025 10:42:15 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Job notes]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3176</guid>

					<description><![CDATA[Mark Zuckerberg recently made a bold statement: AI will soon take over the work of mid-level engineers (Forbes). While this may sound like another tech CEO hyping AI, my latest experience with OpenAI’s o3-mini-high model suggests he might not be too far off. Thanks to DeepSeek, OpenAI was compelled to make o3-mini-high available in a... <a class="more-link" href="https://sysdev.me/ai-software-engineering-and-the-evolution-of-code-generation/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/cppcon-2016/" rel="bookmark" title="CppCon 2016">CppCon 2016</a></li>
<li><a href="https://sysdev.me/informative-errors-go/" rel="bookmark" title="Информативная обработка ошибок в Go">Информативная обработка ошибок в Go</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<div id="attachment_3179" style="width: 210px" class="wp-caption alignleft"><a href="https://sysdev.me/wp-content/uploads/2025/02/mountains.jpeg" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3179" class="wp-image-3179 size-medium" src="https://sysdev.me/wp-content/uploads/2025/02/mountains-200x300.jpeg" alt="" width="200" height="300" srcset="https://sysdev.me/wp-content/uploads/2025/02/mountains-200x300.jpeg 200w, https://sysdev.me/wp-content/uploads/2025/02/mountains-683x1024.jpeg 683w, https://sysdev.me/wp-content/uploads/2025/02/mountains-768x1152.jpeg 768w, https://sysdev.me/wp-content/uploads/2025/02/mountains-1024x1536.jpeg 1024w, https://sysdev.me/wp-content/uploads/2025/02/mountains-500x750.jpeg 500w, https://sysdev.me/wp-content/uploads/2025/02/mountains-150x225.jpeg 150w, https://sysdev.me/wp-content/uploads/2025/02/mountains-1200x1800.jpeg 1200w, https://sysdev.me/wp-content/uploads/2025/02/mountains-400x600.jpeg 400w, https://sysdev.me/wp-content/uploads/2025/02/mountains-800x1200.jpeg 800w, https://sysdev.me/wp-content/uploads/2025/02/mountains.jpeg 1365w" sizes="(max-width: 200px) 100vw, 200px" /></a><p id="caption-attachment-3179" class="wp-caption-text">From a weekend trip to a nearby gorge. Why is it here? Because I love the mountains of Kyrgyzstan! </p> </div>
 <p> Mark Zuckerberg recently made a bold statement: AI will soon take over the work of mid-level engineers <a href="https://www.forbes.com/sites/quickerbettertech/2025/01/26/business-tech-news-zuckerberg-says-ai-will-replace-mid-level-engineers-soon/" target="_blank" rel="noopener">(Forbes)</a>. While this may sound like another tech CEO hyping AI, my latest experience with OpenAI’s o3-mini-high model suggests he might not be too far off. </p> 
 <p> Thanks to DeepSeek, OpenAI was compelled to make o3-mini-high available in a regular ChatGPT subscription instead of locking it behind a steep $200 paywall. I would never pay original $200 for a model, but since I already have the regular ChatGPT subscription, it was an obvious choice to try it out. With this in mind, I decided to experiment: Could o3-mini-high generate a functional Go codebase for my <a href="https://github.com/astavonin/gfsm">GFSM library</a>? </p> 
<h2>The experiment</h2>
 <p> For context, <a href="https://github.com/astavonin/gfsm" target="_blank" rel="noopener">GFSM</a> is my Go Finite State Machine library, and I needed a new generator to extract and save state machines in formats like <a href="https://plantuml.com" target="_blank" rel="noopener">PlantUML</a> and <a href="https://mermaid.js.org" target="_blank" rel="noopener">Mermaid</a>. Writing such a generator requires a solid understanding of Go’s <a href="https://pkg.go.dev/go/ast" target="_blank" rel="noopener">Abstract Syntax Tree (AST) package</a>, something I hadn’t used in years. <br /> 
<span id="more-3176"></span> <br /> 
Instead of writing the code myself, I handed most of the heavy lifting to o3-mini-high. The result? Almost all the code for the generator was AI-generated, with minimal manual adjustments. You can check out the generated code in this <a href="https://github.com/astavonin/gfsm/commit/e9f6296ce6b52eefdaa9848cb1bbb8480c241611" target="_blank" rel="noopener">GitHub commit</a>. </p> 
<blockquote> <p> Code Quality: Mid-Level Engineer Competency (But Better Documentation) </p> </blockquote>
 <p> The AI-generated code was not just functional—it worked on the first attempt! Unfortunately, it still needed some refinements: </p> 
<ul>
<li>Improving logging and error handling</li>
<li>Refactoring functions for better readability and maintainability</li>
</ul>
 <p> Overall, the output quality was comparable to that of a solid mid-level engineer—not perfect, but good enough. But here’s the kicker: Mid-level engineers usually suck at writing documentation (if they write any at all), while the <a href="https://github.com/astavonin/gfsm/blob/main/GFSM_UML.md" target="_blank" rel="noopener">documentation generated by o3-mini-high</a> was actually pretty nice—clear, structured, and covering all the necessary details. </p> 
 <p> My productivity gains may not be impressive, but they are reasonably good for a first attempt: </p> 
<ul>
<li>Time spent “coding” with ChatGPT: 3 hours</li>
<li>The time it would have taken manually (my estimation): 6+ hours</li>
</ul>
 <p> The biggest time-saver? AI handled the AST package interactions, which would have required me to refresh my knowledge. </p> 
<h2>The Future of Software Engineering</h2>
 <p> What does this mean for engineers? I see this as an evolutionary shift rather than a revolutionary one—similar to previous transitions from Assembly to C or from C to Java. AI isn’t outright replacing engineers; it’s redefining what it means to be one. </p> 
 <p> The reality is that “boot camp engineers” and all other types of IT specialists without fundamental education are likely obsolete. Learning how to piece together APIs or follow tutorials won’t be enough when AI can do it better and faster, with approximately the same number of mistakes. Instead, fundamental Computer Science education—actual deep IT knowledge—becomes more critical than ever. </p> 
 <p> Why? Because understanding how and why a system works will distinguish those who can drive AI-assisted development from those who are replaced by it. Engineers with a strong foundation in algorithms, data structures, OS internals, networking, cybersecurity, and distributed systems will remain invaluable. </p> 
 <p> The AI-driven migration process will not be fast or simple. Even at first glance, there are a significant number of challenges ahead.  </p> 
 <p> The crucial part of the AI migration challenge is system verification. If AI is going to generate more and more of our code, who is going to verify that it actually works? This is where Software Development Engineers in Test (SDET), or rather their next evolution—Software Verification Engineers (SVE), become indispensable. SVE will focus not just on functional correctness but also on formal verification, property-based testing, and system reliability. AI can generate code, but it doesn’t inherently know if it’s correct, secure, or efficient—that’s where human engineers must step in. </p> 
 <p> Another major challenge? AI-generated code will include security vulnerabilities. It’s not a question of if but when. AI models don’t “understand” security—they just generate plausible-looking code. This means: </p> 
<ul>
<li>Secure coding practices must be enforced at the architecture level.</li>
<li>Penetration testing and threat modeling will be more crucial than ever.</li>
<li>Automated security analysis tools will need to evolve alongside AI-generated code.</li>
</ul>
 <p> Security engineers will no longer be an “optional” hire for big enterprises. Every AI-assisted development team will need a strong cybersecurity presence, or they risk shipping highly vulnerable software. </p> 
 <p> And the ultimate pain in the ass? AI suggests solutions for AI-generated code. This is where I start crying <span class="wp-font-emots-emo-grin"></span> Right now, AI is great at creating “reasonable-looking” code but lacks true reasoning about correctness and intent. This means: </p> 
<ol>
<li class="p5">AI suggests code that works—but may be subtly wrong.</li>
<li class="p5">The engineer spots a bug and asks AI for a fix.</li>
<li class="p5">AI proposes a fix—but does it actually solve the problem, or does it introduce new ones?</li>
<li class="p5">Repeat until frustration kicks in.</li>
</ol>
 <p> This loop is already frustrating enough when debugging human-written code. With AI generating both the problem and the solution, we might end up in an infinite AI-fix cycle, in which engineers waste more time validating AI’s reasoning than fixing it manually. </p> 
 <p> How do I see my future? It’s perfectly incredible! With AI tools, I can do more, build faster, and focus on higher-level problem-solving</span> instead of getting bogged down in boilerplate coding. AI is an amplifier, not a replacement—it extends my capabilities rather than diminishing my value. </p> 
 <p> And as for job security? I’m not worried in the slightest. With my specialization and experience in system architecture, distributed computing, and software engineering at scale, I will always have a place in this industry. If anything, AI clears the way for me to work on more interesting, complex problems—things AI alone can’t solve. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/cppcon-2016/" rel="bookmark" title="CppCon 2016">CppCon 2016</a></li>
<li><a href="https://sysdev.me/informative-errors-go/" rel="bookmark" title="Информативная обработка ошибок в Go">Информативная обработка ошибок в Go</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/ai-software-engineering-and-the-evolution-of-code-generation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3176</post-id>	</item>
		<item>
		<title>How to compile C++ in 2025. Bazel or CMake?</title>
		<link>https://sysdev.me/how-to-compile-cpp-in-2025/</link>
					<comments>https://sysdev.me/how-to-compile-cpp-in-2025/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Mon, 20 Jan 2025 10:56:14 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Tooling]]></category>
		<category><![CDATA[Bazel]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[CMake]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[Version Control Systems]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3136</guid>

					<description><![CDATA[Today, we’re examining two modern build systems for C++: CMake, the industry favorite, and Bazel, a powerful alternative. While CMake is often the default choice, I believe that approach warrants a bit more scrutiny—after all, we’re focusing on modern tools here (yep, not counting Make, right?). To explore this, I’ve created a practical demo project... <a class="more-link" href="https://sysdev.me/how-to-compile-cpp-in-2025/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/multi-language-projects-with-bazel/" rel="bookmark" title="Managing Multi-Language Projects with Bazel">Managing Multi-Language Projects with Bazel</a></li>
<li><a href="https://sysdev.me/bazel-and-rust/" rel="bookmark" title="Bazel and Rust: A Perfect Match for Scalable Development">Bazel and Rust: A Perfect Match for Scalable Development</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <a href="https://sysdev.me/wp-content/uploads/2025/01/cpp_bazel_and_cmake.png"><img decoding="async" class="size-thumbnail wp-image-3076 alignleft" src="https://sysdev.me/wp-content/uploads/2025/01/cpp_bazel_and_cmake-200x200.png" alt="" width="200" height="200" /></a>Today, we’re examining two modern build systems for C++: <a href="https://cmake.org" target="_blank">CMake</a>, the industry favorite, and <a href="https://bazel.build" target="_blank">Bazel</a>, a powerful alternative. While CMake is often the default choice, I believe that approach warrants a bit more scrutiny—after all, we’re focusing on modern tools here (yep, not counting Make, right?). To explore this, I’ve created a practical demo project showcasing how both systems manage a real-world scenario. </p> 
 <p> Using the <a href="https://github.com/astavonin/maelstrom-challenges" target="_blank">maelstrom-challenges</a> project as a starting point, I’ve extracted a C++ library called <a href="https://github.com/astavonin/maelstrom-node" target="_blank">maelstrom-node</a>. This library has been set up to work seamlessly with both <strong>Bazel</strong> and <strong>CMake</strong>, giving us a hands-on comparison of their approaches, strengths, and quirks. </p> 
<h2>The Project Structure</h2>
 <p> Here’s what the final directory layout for maelstrom-node looks like: </p> 
 <p> <span id="more-3136"></span> </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">➜ &nbsp;maelstrom-node git:<span style="color: #7a0874; font-weight: bold;">&#40;</span>main<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #c20cb9; font-weight: bold;">tree</span><br />
.<br />
├── BUILD.bazel<br />
├── CMakeLists.txt<br />
├── CMakePresets.json<br />
├── LICENSE<br />
├── MODULE.bazel<br />
├── MODULE.bazel.lock<br />
├── README.md<br />
├── include<br />
│ &nbsp; └── maelstrom-node<br />
│ &nbsp; &nbsp; &nbsp; ├── handler.hpp<br />
│ &nbsp; &nbsp; &nbsp; ├── message.hpp<br />
│ &nbsp; &nbsp; &nbsp; └── node.hpp<br />
├── src<br />
│ &nbsp; ├── CMakeLists.txt<br />
│ &nbsp; ├── message.cpp<br />
│ &nbsp; └── node.cpp<br />
├── vcpkg-configuration.json<br />
└── vcpkg.json</div></div>
 <p> With this structure in place, the library could seamlessly integrate with both Bazel and CMake while maintaining clarity and modularity. </p> 
<h2>Building with Bazel</h2>
 <p> Bazel provided a relatively straightforward approach to compile <a href="https://github.com/astavonin/maelstrom-node" target="_blank">maelstrom-node</a>. The key was to define two critical files: <strong>MODULE.bazel</strong> and <strong>BUILD.bazel</strong>. </p> 
<h3>MODULE.bazel</h3>
 <p> The <strong>MODULE.bazel</strong> file in Bazel serves as a central place to define project metadata and manage dependencies. In this file, we use <inl_code>bazel_dep</inl_code> for some dependencies like spdlog and nlohmann_json, but not for rules_boost. Why the difference? It all comes down to how these dependencies are distributed and managed in Bazel’s ecosystem. </p> 
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">module<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;maelstrom_node&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; version <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;1.0.0&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; compatibility_level <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><br />
<span style="color: black;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Dependencies</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Adding spdlog and nlohmann_json via Bazel Dependency Archive</span><br />
bazel_dep<span style="color: black;">&#40;</span>name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;spdlog&quot;</span><span style="color: #66cc66;">,</span> version <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;1.15.0.bcr.3&quot;</span><span style="color: black;">&#41;</span><br />
bazel_dep<span style="color: black;">&#40;</span>name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;nlohmann_json&quot;</span><span style="color: #66cc66;">,</span> version <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;3.11.3.bcr.1&quot;</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Adding rules_boost manually due to its unavailability in Bazel Central Registry</span><br />
bazel_dep<span style="color: black;">&#40;</span>name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;rules_boost&quot;</span><span style="color: #66cc66;">,</span> repo_name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;com_github_nelhage_rules_boost&quot;</span><span style="color: black;">&#41;</span><br />
archive_override<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; module_name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;rules_boost&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; integrity <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;sha256-ZLcmvYKc2FqgLvR96ApPXxp8+sXKqhBlCK66PY/uFIo=&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; strip_prefix <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;rules_boost-e3adfd8d6733c914d2b91a65fb7175af09602281&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; urls <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;https://github.com/nelhage/rules_boost/archive/e3adfd8d6733c914d2b91a65fb7175af09602281.tar.gz&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
<span style="color: black;">&#41;</span></div></div>
 <p> The <inl_code>bazel_dep</inl_code> function simplifies dependency management by fetching dependencies from the <a href="https://registry.bazel.build" target="_blank">Bazel Central Registry (BCR)</a>—a curated collection of Bazel-compatible packages. Dependencies like <strong>spdlog</strong> and <strong>nlohmann_json</strong> are available in the BCR, which makes adding them straightforward and efficient. Using BCR ensures version consistency and eliminates the need for custom configuration. </p> 
<h3>Why Not Use bazel_dep for rules_boost?</h3>
 <p> While popular, the <inl_code>rules_boost</inl_code> library is not often updated in the Bazel Central Registry, and while we have 1.86 release publicly available, BCR includes only 1.83. That&#8217;s why, we <em>may</em> need to configure its source using <inl_code>archive_override</inl_code> manually. This involves specifying details like the URL of the archive, the integrity hash, and the strip prefix. </p> 
 <p> Using <inl_code>bazel_dep</inl_code> wherever possible simplifies project configuration by leveraging the Bazel Central Registry, ensuring that dependencies are well-maintained and easy to integrate. However, when libraries like <inl_code>rules_boost</inl_code> aren’t available in the registry, Bazel’s manual configuration options, like <inl_code>archive_override</inl_code>, allow us to include them. This dual approach showcases Bazel’s flexibility and ability to adapt to different project needs. </p> 
<h3>BUILD.bazel</h3>
 <p> We cannot proceed without BUILD.bazel, as it serves as a location to store the actual app or library information. </p> 
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">cc_library<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;maelstrom_node&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; srcs <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;src/message.cpp&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;src/node.cpp&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; hdrs <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;include/maelstrom-node/**/*.hpp&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; copts <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;-std=c++23&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; includes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;include&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; visibility <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;//visibility:public&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; deps <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@boost//:algorithm&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@boost//:asio&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@nlohmann_json//:json&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@spdlog&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
<span style="color: black;">&#41;</span></div></div>
 <p> The <inl_code>includes = [&#8220;include&#8221;]</inl_code> directive ensures Bazel can resolve headers using shorter paths like <inl_code>#include &#8220;maelstrom-node/message.hpp&#8221;</inl_code> instead of full paths like <inl_code>#include &#8220;include/maelstrom-node/message.hpp&#8221;</inl_code>. </p> 
 <p> To build the library, simply run: </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel build <span style="color: #000000; font-weight: bold;">//</span>...</div></div>
<h2>Building with CMake</h2>
 <p> Adapting maelstrom-node for CMake brought its own set of challenges and solutions, exposing the limitations of this ancient technology. Despite its widespread use, even a straightforward migration effort highlighted CMake’s inherent bottlenecks and inefficiencies, reinforcing the idea that it might be time to consider moving on from it entirely. </p> 
<h3>Managing Includes</h3>
 <p> This is the first challenge you&#8217;ll face when trying to move from Bazel to CMake. CMake assumes <inl_code>#include</inl_code> paths are relative to the include directory, so you write: </p> 
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #339900;">#include &quot;maelstrom-node/message.hpp&quot;</span></div></div>
 <p> Bazel, on the other hand, often requires full paths from the project root unless explicitly configured using the includes property in the <inl_code>cc_library</inl_code> rule: </p> 
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #339900;">#include &quot;include/maelstrom-node/message.hpp&quot;</span></div></div>
 <p> While CMake’s shorter paths may appear cleaner within the source code and more natural for C++ developers, they abstract away the file hierarchy, making it harder to understand the project structure at a glance. As Bazel requires, full paths provide better context by explicitly showing where a file is located in the directory tree, making navigation and maintenance easier, especially in larger projects. </p> 
<h3>Setting Up CMake and VCPKG</h3>
 <p> Using <a href="https://vcpkg.io" target="_blank">vcpkg</a> as the package manager is one of the ways to simplify dependency management if you are a CMake fun. After installing vcpkg, I initialized the project and added the necessary ports. The following command will create <inl_code>vcpkg-configuration.json</inl_code> and <inl_code>vcpkg.json</inl_code> files: </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">vcpkg new <span style="color: #660033;">--application</span><br />
vcpkg add port boost-algorithm<br />
vcpkg add port boost-asio<br />
vcpkg add port nlohmann-json</div></div>
 <p> Another option for CMake dependency management is Conan. However, based on my experience, it&#8217;s even more complex than VCPKG, so I won’t discuss it in this post. </p> 
<h3>Making a CMakeLists.txt</h3>
 <p> Managing dependencies was relatively streamlined using the vcpkg package manager. The toolchain file was included dynamically to ensure compatibility, allowing for flexibility when configuring the build environment. This setup reduces manual configuration efforts while ensuring that dependencies are correctly integrated: </p> 
<div class="codecolorer-container cmake default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cmake codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #1f3f81; font-style: bold;">if</span><span style="color: #197d8b;">(</span><span style="color: #077807; font-sytle: italic;">NOT</span> <span style="color: #077807; font-sytle: italic;">DEFINED</span> CMAKE_TOOLCHAIN_FILE<span style="color: #197d8b;">)</span><br />
&nbsp; &nbsp; <span style="color: #1f3f81; font-style: bold;">set</span><span style="color: #197d8b;">(</span>CMAKE_TOOLCHAIN_FILE <span style="color: #912f11;">&quot;<span style="color: #b08000;">${CMAKE_SOURCE_DIR}</span>/vcpkg/scripts/buildsystems/vcpkg.cmake&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #077807; font-sytle: italic;">CACHE</span> <span style="color: #077807; font-sytle: italic;">STRING</span> <span style="color: #912f11;">&quot;Vcpkg toolchain file&quot;</span><span style="color: #197d8b;">)</span><br />
<span style="color: #1f3f81; font-style: bold;">endif</span><span style="color: #197d8b;">()</span></div></div>
 <p> The main part of the CMakeLists.txt file is standard for CMake projects. The maelstrom_node library is defined as a static library with its core functionality implemented in message.cpp and node.cpp. Dependencies such as Boost, nlohmann_json, and spdlog are configured using <inl_code>find_package</inl_code>, ensuring they are available during the build process. </p> 
<div class="codecolorer-container cmake default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cmake codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #1f3f81; font-style: bold;">add_library</span><span style="color: #197d8b;">(</span>maelstrom_node <span style="color: #077807; font-sytle: italic;">STATIC</span><br />
&nbsp; &nbsp; src/message.cpp<br />
&nbsp; &nbsp; src/node.cpp<br />
<span style="color: #197d8b;">)</span><br />
<br />
<span style="color: #1f3f81; font-style: bold;">find_package</span><span style="color: #197d8b;">(</span>Boost REQUIRED NO_MODULE<span style="color: #197d8b;">)</span><br />
<span style="color: #1f3f81; font-style: bold;">find_package</span><span style="color: #197d8b;">(</span>nlohmann_json REQUIRED<span style="color: #197d8b;">)</span><br />
<span style="color: #1f3f81; font-style: bold;">find_package</span><span style="color: #197d8b;">(</span>spdlog REQUIRED<span style="color: #197d8b;">)</span><br />
<br />
target_include_directories<span style="color: #197d8b;">(</span>maelstrom_node PUBLIC<br />
&nbsp; &nbsp; <span style="color: #b08000;">${CMAKE_SOURCE_DIR}</span>/include<br />
&nbsp; &nbsp; <span style="color: #b08000;">${Boost_INCLUDE_DIRS}</span><br />
<span style="color: #197d8b;">)</span><br />
<br />
<span style="color: #1f3f81; font-style: bold;">target_link_libraries</span><span style="color: #197d8b;">(</span>maelstrom_node PUBLIC<br />
&nbsp; &nbsp; nlohmann_json::nlohmann_json<br />
&nbsp; &nbsp; spdlog::spdlog<br />
&nbsp; &nbsp; Boost::headers<br />
<span style="color: #197d8b;">)</span></div></div>
 <p> The <inl_code>find_package</inl_code> command works seamlessly in this setup because the vcpkg toolchain file is integrated into the project configuration. This file, specified as <inl_code>CMAKE_TOOLCHAIN_FILE</inl_code>, ensures that CMake knows the paths to all dependencies installed via vcpkg. When find_package is called, it searches these paths for the necessary configuration files, allowing dependencies like Boost, nlohmann_json, and spdlog to be located and linked automatically. This integration eliminates manual dependency management and ensures consistency across environments. </p> 
 <p> Finally, the installation section of the file ensures that the library can be packaged and reused in other projects. This includes specifying where the compiled library should be installed and ensuring that headers are copied to the appropriate directories: </p> 
<div class="codecolorer-container cmake default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cmake codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #1f3f81; font-style: bold;">install</span><span style="color: #197d8b;">(</span>TARGETS maelstrom_node<br />
&nbsp; &nbsp; EXPORT maelstrom_nodeConfig<br />
&nbsp; &nbsp; ARCHIVE DESTINATION lib<br />
&nbsp; &nbsp; LIBRARY DESTINATION lib<br />
&nbsp; &nbsp; RUNTIME DESTINATION bin<br />
<span style="color: #197d8b;">)</span><br />
<br />
<span style="color: #1f3f81; font-style: bold;">install</span><span style="color: #197d8b;">(</span><span style="color: #077807; font-sytle: italic;">DIRECTORY</span> <span style="color: #b08000;">${CMAKE_SOURCE_DIR}</span>/include/maelstrom-node<br />
&nbsp; &nbsp; DESTINATION include/maelstrom-node<br />
<span style="color: #197d8b;">)</span></div></div>
 <p> This setup ensures the maelstrom-node library is compiled correctly and packaged in a way that makes it easy to integrate into other projects. While CMake offers much flexibility, its verbosity and reliance on external tools like vcpkg highlight some of its limitations in managing dependencies efficiently. CMake provides multiple approaches to configure and build the project. Ideally, you could use a preset configuration for simplicity, such as (based on the official documentation): </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">cmake <span style="color: #660033;">--preset</span>=vcpkg<br />
cmake <span style="color: #660033;">--build</span> build</div></div>
 <p> This approach is clean and convenient, leveraging a preset defined in CMakePresets.json. However, due to a <a href="https://stackoverflow.com/questions/78046929/cannot-use-environment-variable-in-cmakepresets-json-with-cmaketools-in-vscode-t" target="_blank">defect in Visual Studio Code’s CMake Tools</a>, environment variables like <inl_code>$VCPKG_ROOT</inl_code> cannot be directly used in CMakePresets.json. As a result, the preset may fail to locate the toolchain file correctly. </p> 
 <p> To address this issue, the following manual configuration proves reliable despite its ugliness: </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">cmake <span style="color: #660033;">-S</span> . <span style="color: #660033;">-B</span> build -DCMAKE_TOOLCHAIN_FILE=<span style="color: #007800;">$VCPKG_ROOT</span><span style="color: #000000; font-weight: bold;">/</span>scripts<span style="color: #000000; font-weight: bold;">/</span>buildsystems<span style="color: #000000; font-weight: bold;">/</span>vcpkg.cmake<br />
cmake <span style="color: #660033;">--build</span> build</div></div>
 <p> Both methods ultimately lead to the same result, but the manual approach is necessary in environments where preset limitations or toolchain file paths are not resolved automatically. This highlights a minor inconvenience in the CMake ecosystem that can complicate workflows when integrating with tools like vcpkg. </p> 
<h2>Let&#8217;s integrate it!</h2>
 <p> Let’s integrate maelstrom-node into our application! This is the final step to bring everything together, and it’s where the differences between Bazel and CMake really stand out in terms of setup, dependency management, and usability. Here’s how each approach handles this critical task. </p> 
<h3>Bazel Integration</h3>
 <p> In Bazel, the integration is streamlined by declaring the maelstrom-node library as a dependency using <inl_code>bazel_dep</inl_code> and providing a <inl_code>git_override</inl_code> to fetch the library from its repository: </p> 
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel_dep<span style="color: black;">&#40;</span>name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;maelstrom_node&quot;</span><span style="color: #66cc66;">,</span> version <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;1.0.0&quot;</span><span style="color: black;">&#41;</span><br />
git_override<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; module_name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;maelstrom_node&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; commit <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;004b1d793427838db32d5e175f1f474bec260766&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; remote <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;https://github.com/astavonin/maelstrom-node.git&quot;</span><span style="color: #66cc66;">,</span><br />
<span style="color: black;">&#41;</span></div></div>
 <p> The library is then added as a dependency in the build rule for the application: </p> 
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">cc_binary<span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;echo-cpp&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; srcs <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;main.cpp&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; copts <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;-std=c++23&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; visibility <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;//visibility:public&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; deps <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@maelstrom_node&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;@spdlog&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
<span style="color: black;">&#41;</span></div></div>
 <p> Bazel’s approach to dependencies is more declarative and centralized. Dependencies are fetched and managed globally at the repository level, ensuring consistency across the project. The use of <inl_code>bazel_dep</inl_code> and overrides simplifies versioning, and Bazel’s caching mechanism avoids redundant downloads and builds, leading to faster iterations. </p> 
 <p> The compilation process is still very straightforward for the final app: </p> 
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel build <span style="color: #000000; font-weight: bold;">//</span>...</div></div>
<h3>CMake Integration</h3>
 <p> The CMakeLists.txt file for the integration is relatively standard, with one notable addition: the use of <inl_code>FetchContent</inl_code> to fetch and include the maelstrom-node library directly from its Git repository. This setup is straightforward, as shown below. </p> 
<div class="codecolorer-container cmake default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="cmake codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #1f3f81; font-style: bold;">include</span><span style="color: #197d8b;">(</span>FetchContent<span style="color: #197d8b;">)</span><br />
<br />
FetchContent_Declare<span style="color: #197d8b;">(</span><br />
&nbsp; &nbsp; maelstrom_node<br />
&nbsp; &nbsp; GIT_REPOSITORY https://github.com/astavonin/maelstrom-node.git<br />
&nbsp; &nbsp; GIT_TAG v1.0.0<br />
<span style="color: #197d8b;">)</span><br />
<br />
FetchContent_MakeAvailable<span style="color: #197d8b;">(</span>maelstrom_node<span style="color: #197d8b;">)</span></div></div>
 <p> This snippet looks pretty and allows the library to be built alongside the application. But, it’s not without its drawbacks. Unlike Bazel, CMake relies heavily on external tools like vcpkg for dependency management. Unfortunately, vcpkg requires a complete list of dependencies to be declared for every project (is it a defect? It looks so to me.). In this case, both echo-cpp and maelstrom-node must redundantly list their dependencies in echo-cpp’s vcpkg.conf file. This duplication can be tedious and error-prone, especially in larger, more complex projects. </p> 
 <p> Another significant limitation is CMake’s lack of integration with other ecosystems like Rust and Cargo. If you already have existing integration tests written in Rust, as I have, CMake cannot reuse them natively. This inability to leverage cross-language infrastructure is one of CMake’s most significant downsides and a stark contrast to Bazel, which excels in mixed-language project support. </p> 
 <p> While this integration approach works, it highlights the challenges of relying on CMake for projects beyond simple use cases, especially when dealing with multiple dependencies or mixed-language ecosystems. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/multi-language-projects-with-bazel/" rel="bookmark" title="Managing Multi-Language Projects with Bazel">Managing Multi-Language Projects with Bazel</a></li>
<li><a href="https://sysdev.me/bazel-and-rust/" rel="bookmark" title="Bazel and Rust: A Perfect Match for Scalable Development">Bazel and Rust: A Perfect Match for Scalable Development</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/how-to-compile-cpp-in-2025/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3136</post-id>	</item>
		<item>
		<title>Managing Multi-Language Projects with Bazel</title>
		<link>https://sysdev.me/multi-language-projects-with-bazel/</link>
					<comments>https://sysdev.me/multi-language-projects-with-bazel/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Tue, 14 Jan 2025 06:18:45 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Tooling]]></category>
		<category><![CDATA[Bazel]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[tools]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3120</guid>

					<description><![CDATA[In today’s software development landscape, it’s rare to encounter a project built with just one programming language or platform. Modern applications often require integrating multiple technologies to meet diverse requirements. This complexity is both a challenge and an opportunity, demanding robust tools to manage dependencies, builds, and integrations seamlessly. Bazel, a powerful build system, is... <a class="more-link" href="https://sysdev.me/multi-language-projects-with-bazel/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/bazel-and-rust/" rel="bookmark" title="Bazel and Rust: A Perfect Match for Scalable Development">Bazel and Rust: A Perfect Match for Scalable Development</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
<li><a href="https://sysdev.me/minimal-ci-for-go-library-with-github-actions/" rel="bookmark" title="Minimal CI for Go library with GitHub actions">Minimal CI for Go library with GitHub actions</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <a href="https://sysdev.me/wp-content/uploads/2025/01/cpp-bazel.png"><img loading="lazy" decoding="async" class="size-thumbnail wp-image-3076 alignleft" src="https://sysdev.me/wp-content/uploads/2025/01/cpp-bazel-150x150.png" alt="" width="150" height="150" /></a>In today’s software development landscape, it’s rare to encounter a project built with just one programming language or platform. Modern applications often require integrating multiple technologies to meet diverse requirements. This complexity is both a challenge and an opportunity, demanding robust tools to manage dependencies, builds, and integrations seamlessly. Bazel, a powerful build system, is one such tool that has proven invaluable for multi-language projects. </p> 
 <p> Recently, I decided to extend my <a href="https://github.com/astavonin/maelstrom-challenges" target="_blank">Maelstrom challenges</a> with a C++-based test to explore how Bazel can simplify managing multi-language dependencies and streamline development workflows. </p> 
<h2>Why Bazel for Multi-Language Projects?</h2>
 <p> <span id="more-3120"></span> <br /> 
Bazel’s design philosophy emphasizes performance and scalability, making it an excellent choice for projects that involve multiple languages. With its support for Bazel modules, adding dependencies is as simple as declaring them in a MODULE.bazel file. For example, integrating the popular logging library spdlog is straightforward: </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel_dep(name = &quot;spdlog&quot;, version = &quot;1.15.0.bcr.3&quot;)</div></div>
 <p> However, not every library supports Bazel modules natively, which can complicate things. A case in point is BOOST, a widely used C++ library. Adding BOOST required a bit of additional setup, fortunately, we have <a href="https://github.com/nelhage/rules_boost" target="_blank">rules_boost</a> project: </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel_dep(name = &quot;rules_boost&quot;, repo_name = &quot;com_github_nelhage_rules_boost&quot;)<br />
<br />
archive_override(<br />
&nbsp; &nbsp; module_name = &quot;rules_boost&quot;,<br />
&nbsp; &nbsp; integrity = &quot;sha256-ZLcmvYKc2FqgLvR96ApPXxp8+sXKqhBlCK66PY/uFIo=&quot;,<br />
&nbsp; &nbsp; strip_prefix = &quot;rules_boost-e3adfd8d6733c914d2b91a65fb7175af09602281&quot;,<br />
&nbsp; &nbsp; urls = [&quot;https://github.com/nelhage/rules_boost/archive/e3adfd8d6733c914d2b91a65fb7175af09602281.tar.gz&quot;],<br />
)<br />
<br />
non_module_boost_repositories = use_extension(&quot;@com_github_nelhage_rules_boost//:boost/repositories.bzl&quot;, &quot;non_module_dependencies&quot;)<br />
use_repo(<br />
&nbsp; &nbsp; non_module_boost_repositories,<br />
&nbsp; &nbsp; &quot;boost&quot;,<br />
)</div></div>
 <p> While the setup for BOOST is less elegant than for spdlog, Bazel’s flexibility ensures that even complex dependencies can be integrated efficiently. </p> 
<h2>Improving Code Navigation with Hedron’s Compile Commands</h2>
 <p> Another critical aspect of C++ development is code navigation. Generating a <inl_code>compile_commands.json</inl_code> file makes life easier for developers using tools like Vim or Emacs. Thankfully, Bazel has a powerful solution: <a href="https://github.com/hedronvision/bazel-compile-commands-extractor" target="_blank">Hedron Compile Commands Extractor</a>. </p> 
 <p> It&#8217;s pretty easy to set it up: </p> 
 <p> 1. Add the dependency to your MODULE.bazel file: </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel_dep(name = &quot;hedron_compile_commands&quot;, dev_dependency = True)<br />
<br />
git_override(<br />
&nbsp; &nbsp; module_name = &quot;hedron_compile_commands&quot;,<br />
&nbsp; &nbsp; commit = &quot;4f28899228fb3ad0126897876f147ca15026151e&quot;,<br />
&nbsp; &nbsp; remote = &quot;https://github.com/hedronvision/bazel-compile-commands-extractor.git&quot;,<br />
)</div></div>
 <p> 2. Generate the compile_commands.json file by running: </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">bazel run @hedron_compile_commands//:refresh_all</div></div>
 <p> This simple addition dramatically improves the developer experience, making it easy to navigate and understand the C++ codebase. What I love even more there is NeoVim&#8217;s <a href="https://github.com/neovim/nvim-lspconfig" target="_blank">lsp-config</a> provides excellent navigation and auto-completion with the generated <inl_code>compile_commands.json</inl_code>. </p> 
<h2>Building C++ Support in Maelstrom challenges</h2>
 <p> The process of adding C++ support to the <a href="https://github.com/astavonin/maelstrom-challenges" target="_blank">Maelstrom challenges</a> project involved several key changes. In <a href="https://github.com/astavonin/maelstrom-challenges/commit/8814adbc613b37b6e143aeb1506b2d5660bded0a" target="_blank">this commit</a>, I outlined the required modifications to the MODULE.bazel file to set up the necessary dependencies. This provided the foundation for implementing a basic Maelstrom protocol in C++. </p> 
 <p> The implementation itself, along with a simple echo app as a proof of concept, can be seen in <a href="https://github.com/astavonin/maelstrom-challenges/commit/f0be5f8a2928a30af7614c157145fa2cab0accc9" target="_blank">this commit</a>. This example showcases how Bazel simplifies managing dependencies and building multi-language projects while allowing for robust testing and experimentation. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/bazel-and-rust/" rel="bookmark" title="Bazel and Rust: A Perfect Match for Scalable Development">Bazel and Rust: A Perfect Match for Scalable Development</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
<li><a href="https://sysdev.me/minimal-ci-for-go-library-with-github-actions/" rel="bookmark" title="Minimal CI for Go library with GitHub actions">Minimal CI for Go library with GitHub actions</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/multi-language-projects-with-bazel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3120</post-id>	</item>
		<item>
		<title>Bazel and Rust: A Perfect Match for Scalable Development</title>
		<link>https://sysdev.me/bazel-and-rust/</link>
					<comments>https://sysdev.me/bazel-and-rust/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Sun, 29 Dec 2024 15:23:22 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Tooling]]></category>
		<category><![CDATA[Bazel]]></category>
		<category><![CDATA[Rust programming language]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3093</guid>

					<description><![CDATA[Bazel never fails to impress, and its support for Rust demonstrates its versatility and commitment to modern development. Two distinct dependency management modes—Cargo—based and pure Bazel—allow developers to tailor workflows to their projects&#8217; needs. This adaptability is particularly valuable for integrating Rust applications into monorepos or scaling complex systems. I decided to explore how Bazel... <a class="more-link" href="https://sysdev.me/bazel-and-rust/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/multi-language-projects-with-bazel/" rel="bookmark" title="Managing Multi-Language Projects with Bazel">Managing Multi-Language Projects with Bazel</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
<li><a href="https://sysdev.me/%d1%8e%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d1%8b-%d0%b8-rust/" rel="bookmark" title="Юнит-тесты и Rust">Юнит-тесты и Rust</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <a href="https://sysdev.me/wp-content/uploads/2024/12/rust_and_bazel.png"><img loading="lazy" decoding="async" class="size-thumbnail wp-image-3076 alignleft" src="https://sysdev.me/wp-content/uploads/2024/12/rust_and_bazel-150x150.png" alt="" width="150" height="150" /></a>Bazel never fails to impress, and its support for Rust demonstrates its versatility and commitment to modern development. Two distinct dependency management modes—Cargo—based and pure Bazel—allow developers to tailor workflows to their projects&#8217; needs. This adaptability is particularly valuable for integrating Rust applications into monorepos or scaling complex systems. <br /> 
I decided to explore how Bazel supports Rust, including managing dependencies, migrating from <inl_code>Cargo.toml</inl_code> to <inl_code>BUILD.bazel</inl_code>, and streamlining integration testing. <br /> 
<span id="more-3093"></span> </p> 
<h2>Harnessing Cargo-Based Dependency Management</h2>
 <p> Bazel’s ability to integrate with Cargo, Rust’s native package manager, is a standout feature. This approach preserves compatibility with the Rust ecosystem while allowing projects to benefit from Bazel’s powerful build features. By using <a href="https://bazelbuild.github.io/rules_rust/" target="_blank">rules_rust</a>, a Bazel module can seamlessly import dependencies defined in <inl_code>Cargo.toml</inl_code> and <inl_code>Cargo.lock</inl_code> into its build graph. </p> 
 <p> It was pretty easy to feed dependency information from Cargo to Bazel. The only tricky part is Cargo workspaces. If you use a Cargo workspace like I do, you should list all <inl_code>Cargo.toml</inl_code> files under the <inl_code>manifests</inl_code> section in <inl_code>MODULE.bazel</inl_code> file. </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">crate = use_extension(&quot;@rules_rust//crate_universe:extensions.bzl&quot;, &quot;crate&quot;)<br />
crate.from_cargo(<br />
&nbsp; &nbsp; name = &quot;crate_index&quot;,<br />
&nbsp; &nbsp; cargo_lockfile = &quot;//:Cargo.lock&quot;,<br />
&nbsp; &nbsp; manifests = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;//:Cargo.toml&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;//:echo/Cargo.toml&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;//:tests/Cargo.toml&quot;,<br />
&nbsp; &nbsp; ],<br />
)<br />
use_repo(crate, &quot;crate_index&quot;)</div></div>
 <p> This setup allows Bazel to parse and manage dependencies from multiple <inl_code>Cargo.toml</inl_code> files. The <a href="https://bazelbuild.github.io/rules_rust/crate_universe.html" target="_blank">crate_universe</a> extension ensures that Bazel respects the dependency versions specified in the lockfile, providing reproducible builds. This approach is particularly practical in projects with nested crates or submodules, as Bazel automatically consolidates them into a unified build graph. </p> 
 <p> Integrating with Cargo in this way provides the best of both worlds. Developers can continue using Rust’s native tooling for development while leveraging Bazel for its scalability and advanced dependency management. Although this dual-system approach adds some complexity, the flexibility it offers is invaluable for scaling projects and ensuring compatibility with the broader Rust ecosystem. </p> 
<h2>Migrating from <inl_code>Cargo.toml</inl_code> to <inl_code>BUILD.bazel</inl_code></h2>
 <p> The next step after making a proper <inl_code>MODULE.bazel</inl_code> file is to create <inl_code>BUILD.bazel</inl_code>. It&#8217;s basically a translation of all component-level <inl_code>Cargo.toml</inl_code> files into <inl_code>BUILD.bazel</inl_code> one-by-one. </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">[package]<br />
name = &quot;echo&quot;<br />
version = &quot;0.1.0&quot;<br />
edition = &quot;2021&quot;<br />
<br />
[[bin]]<br />
path = &quot;src/main.rs&quot;<br />
name = &quot;echo&quot;<br />
<br />
[dependencies]<br />
async-trait = &quot;0.1.83&quot;<br />
maelstrom-node = &quot;0.1.6&quot;</div></div>
 <p> In Bazel, each <inl_code>bin</inl_code> section from <inl_code>Cargo.toml</inl_code> should be translated into a <inl_code>rust_binary</inl_code> definition in <inl_code>BUILD.bazel</inl_code>. Another important part here is <inl_code>@crate_index</inl_code> which refer to <inl_code>crate.from_cargo(name = &#8220;crate_index&#8221;, &#8230;)</inl_code> command from the <inl_code>MODULE.bazel</inl_code> described above. </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">load(&quot;@rules_rust//rust:defs.bzl&quot;, &quot;rust_binary&quot;)<br />
<br />
rust_binary(<br />
&nbsp; &nbsp; name = &quot;echo&quot;,<br />
&nbsp; &nbsp; srcs = [&quot;src/main.rs&quot;],<br />
&nbsp; &nbsp; proc_macro_deps = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;@crate_index//:async-trait&quot;,<br />
&nbsp; &nbsp; ],<br />
&nbsp; &nbsp; deps = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;@crate_index//:maelstrom-node&quot;,<br />
&nbsp; &nbsp; ],<br />
)</div></div>
 <p> This shift ensures that Bazel can handle the entire build lifecycle, from compiling dependencies to linking final binaries. While <inl_code>Cargo.toml</inl_code> defines dependencies and build metadata, <inl_code>BUILD.bazel</inl_code> brings this into Bazel’s optimized dependency graph. This transition is seamless for developers familiar with both systems and ensures scalability as the project grows. </p> 
<h2>Simplifying Integration Testing with Bazel</h2>
 <p> Integration testing is another area where Bazel simplifies workflows compared to Cargo. In Rust’s native system, it’s not straightforward to ensure that an application is built before a test requiring that application is executed. With Bazel, this process becomes effortless. </p> 
 <p> Consider a <inl_code>BUILD.bazel</inl_code> setup for integration tests: </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;height:400px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">load(&quot;@rules_rust//rust:defs.bzl&quot;, &quot;rust_library&quot;, &quot;rust_test&quot;)<br />
<br />
rust_library(<br />
&nbsp; &nbsp; name = &quot;utils&quot;,<br />
&nbsp; &nbsp; srcs = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;utils/lib.rs&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;utils/paths.rs&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;utils/runner.rs&quot;,<br />
&nbsp; &nbsp; ],<br />
)<br />
<br />
rust_test(<br />
&nbsp; &nbsp; name = &quot;test_echo&quot;,<br />
&nbsp; &nbsp; size = &quot;small&quot;,<br />
&nbsp; &nbsp; srcs = [&quot;echo/test_echo.rs&quot;],<br />
&nbsp; &nbsp; data = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;:maelstrom/lib/maelstrom.jar&quot;,<br />
&nbsp; &nbsp; ],<br />
&nbsp; &nbsp; deps = [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;:utils&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &quot;//echo&quot;,<br />
&nbsp; &nbsp; ],<br />
)</div></div>
 <p> This configuration defines a <inl_code>rust_test</inl_code> that explicitly depends on the <inl_code>//echo</inl_code> binary. Bazel ensures that the binary is built before the test is executed, avoiding any manual coordination. Shared utilities used during the tests are included in a <inl_code>rust_library</inl_code>, promoting code reuse. Additionally, test resources like <inl_code>:maelstrom/lib/maelstrom.jar</inl_code> are specified as data, ensuring they are available during execution. </p> 
 <p> It took some Googling to figure out how to access external resources like <inl_code>maelstrom.jar</inl_code> for the Rust integration test. However, it&#8217;s simpler than it appears at first. We basically need to retrieve the value from the <inl_code>RUNFILES_DIR</inl_code> environment variable, which points to a temporary Bazel-managed directory, and then add the <inl_code>&#8220;_main&#8221;</inl_code> folder on top of it. </p> 
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">pub fn bazel_runfiles_dir() -&gt; PathBuf {<br />
&nbsp; &nbsp; PathBuf::from(env::var_os(&quot;RUNFILES_DIR&quot;).unwrap()).join(&quot;_main&quot;)<br />
}<br />
<br />
pub fn maelstrom_dir() -&gt; PathBuf {<br />
&nbsp; &nbsp; bazel_runfiles_dir()<br />
&nbsp; &nbsp; &nbsp; &nbsp; .join(&quot;tests&quot;)<br />
&nbsp; &nbsp; &nbsp; &nbsp; .join(&quot;maelstrom&quot;)<br />
&nbsp; &nbsp; &nbsp; &nbsp; .join(&quot;lib&quot;)<br />
}</div></div>
 <p> Bazel’s approach eliminates the need for custom scripts or workarounds, streamlining the test lifecycle and ensuring reliable, reproducible results. This simplicity becomes increasingly important as projects grow, where manual processes can hinder productivity and introduce inconsistencies. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/multi-language-projects-with-bazel/" rel="bookmark" title="Managing Multi-Language Projects with Bazel">Managing Multi-Language Projects with Bazel</a></li>
<li><a href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/" rel="bookmark" title="Returning to Rust: A Journey Through Tooling, Performance">Returning to Rust: A Journey Through Tooling, Performance</a></li>
<li><a href="https://sysdev.me/%d1%8e%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d1%8b-%d0%b8-rust/" rel="bookmark" title="Юнит-тесты и Rust">Юнит-тесты и Rust</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/bazel-and-rust/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3093</post-id>	</item>
		<item>
		<title>Returning to Rust: A Journey Through Tooling, Performance</title>
		<link>https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/</link>
					<comments>https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Tue, 10 Dec 2024 15:10:27 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Tooling]]></category>
		<category><![CDATA[Bazel]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[CMake]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Rust programming language]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3081</guid>

					<description><![CDATA[When I started tackling the Maelstrom challenges, my initial thought was to use C++. It’s a language I know inside out, and its performance is hard to beat. However, as I contemplated setting up the project, I realized I couldn’t justify fighting with the C++ pipeline for free. Crafting a proper CMake or Bazel configuration... <a class="more-link" href="https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/cmake-clang/" rel="bookmark" title="CMake &#038; Clang">CMake &#038; Clang</a></li>
<li><a href="https://sysdev.me/rust-experements/" rel="bookmark" title="Эксперименты с Rust">Эксперименты с Rust</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <a href="https://github.com/astavonin/maelstrom-challenges" target="_blank" rel="noopener">When I started tackling</a> the <a href="https://github.com/jepsen-io/maelstrom/tree/main" target="_blank" rel="noopener">Maelstrom challenges</a>, my initial thought was to use C++. It’s a language I know inside out, and its performance is hard to beat. However, as I contemplated setting up the project, I realized I couldn’t justify fighting with the C++ pipeline for free. Crafting a proper CMake or Bazel configuration might be worthwhile for large-scale projects or when compensated, but for personal experiments? It’s an unnecessary headache. </p> 
<h3>Why Go is My Default Choice</h3>
 <p> For most non-performance critical scenarios, Go is my default, no-brainer choice. It has a clean build system, excellent tooling, and a developer experience that doesn’t make me dread the setup process. Go’s simplicity allows me (and <strong>any</strong> level team) to focus on solving the problem rather than wrestling with the environment. Yet, this time, I decided to take a different path. <br /> 
<span id="more-3081"></span> </p> 
<h3>Revisiting Rust</h3>
 <p> My relationship with Rust has been a journey of highs and lows. I was initially drawn to it during its early days, around Rust 0.1, when the language was brimming with potential. What captivated me back then was its promise to be a kind of “Erlang on steroids”—a language that combined Erlang&#8217;s lightweight concurrency model and fault-tolerant programming paradigms with the performance and control of a systems language. </p> 
 <p> Unfortunately, with the release of Rust 1.0, much of that original vision shifted. Green threads—a key feature that enabled lightweight concurrency and aligned closely with the “Erlang on steroids” dream—were abandoned. The decision to remove them in favor of direct integration with the OS threading model made sense for speeding up the 1.0 release. Still, it marked a significant departure from the language’s earlier aspirations. </p> 
 <p> Adding to the change was a complete overhaul of Rust’s memory model, which moved toward its now-iconic ownership system. While the new model introduced unparalleled safety and performance guarantees, it also made the language more complex and less approachable, particularly for those who were excited about its initial simplicity. </p> 
 <p> These shifts left me feeling that Rust had transformed into “just another overcomplicated C++-like language,” albeit with better safety features and tooling. Over time, I moved away from Rust, drawn instead to more straightforward and developer-friendly languages for most of my work. </p> 
 <p> But now, years later, I’m giving Rust another shot while having plenty of free time. Its strong presence in emerging fields like Web3 has made it impossible to ignore. The language has clearly matured, and while its evolution may not have aligned with my initial hopes, I’m curious to explore how its modern ecosystem can contribute to my work. Rust may no longer be the “Erlang on steroids” I once envisioned, but it’s carving out a unique space for itself, and I’m eager to see how it fits into my technical journey moving forward. </p> 
<h3>Comparing Tooling and Developer Experience</h3>
 <p> My return to Rust brought some pleasant surprises—and a few frustrations. Here’s a breakdown of my observations: </p> 
 <p> Cargo vs. Build Systems </p> 
<ul>
<li>Cargo, Rust’s build system and package manager, is undeniably better than CMake—but then again, that’s not a high bar. Let’s be honest: CMake is an exercise of frustration for most developers.</li>
<li>Comparing Cargo to Bazel: Cargo feels more straightforward and approachable, but it requires more power and flexibility than Bazel. In that sense, Bazel is still the gold standard for me in large, complex projects.</li>
<li>Go’s build system, however, remains my favorite. Its simplicity and convention-over-configuration philosophy are unmatched.</li>
</ul>
<h3>IDEs and Editor Support</h3>
 <p> Tools like RustRover have evolved to deliver an exceptional development experience, far surpassing the likes of CLion or most other C++ IDEs. The level of integration with Cargo, code analysis, and developer assistance is simply stellar. </p> 
<h3>Compiler Diagnostics</h3>
<p class="p1">One of Rust’s standout features is its compiler diagnostics. The clarity and detail in Rust’s error messages are leagues ahead of what you get with <span class="s1">Clang</span> or <span class="s1">GCC</span>. It’s an area where Rust truly shines, making debugging and iteration smoother. However, it’s not all perfect. </p> 
<p class="p1">When it comes to <b>borrowing-related errors</b>, the story changes. These errors often feel nonintuitive, even for developers familiar with Rust’s ownership model. Despite the compiler’s best efforts to provide explanations, deciphering and resolving these errors frequently requires external help. You’ll find yourself Googling extensively or turning to tools like ChatGPT (model 4.0 preferred) to figure out what’s going wrong and how to fix it. This aspect of the Rust learning curve remains a significant hurdle for newcomers and a source of frustration even for experienced developers. </p> 
<p class="p1">While the error diagnostics are still better than those offered by C++, the borrowing system’s complexity can sometimes undermine the excellent developer experience. </p> 
<h3>Reflections and Future Plans</h3>
<p class="p1">Sometimes, stepping back into an ecosystem with a fresh perspective can reveal how much has changed—for better or worse. <br /> 
Rust is no longer just the “overcomplicated” C++ sibling I left behind. It’s still a language with comparable complexity to C++ (which means it&#8217;s overcomplicated) but with a critical difference: compile-time sanitizers you need in C++ baked into its Rust core. This feature transforms those complexities into tools that actively guide you toward safer, more robust code. </p> 
 <p> Last but not least, as I&#8217;d mentioned above, I do not want to setup a proper C++ pipeline either <span class="wp-font-emots-emo-grin"></span> </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/cmake-clang/" rel="bookmark" title="CMake &#038; Clang">CMake &#038; Clang</a></li>
<li><a href="https://sysdev.me/rust-experements/" rel="bookmark" title="Эксперименты с Rust">Эксперименты с Rust</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/returning-to-rust-a-journey-through-tooling-performance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3081</post-id>	</item>
		<item>
		<title>Minimal CI for Go library with GitHub actions</title>
		<link>https://sysdev.me/minimal-ci-for-go-library-with-github-actions/</link>
					<comments>https://sysdev.me/minimal-ci-for-go-library-with-github-actions/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Thu, 05 Dec 2024 02:35:42 +0000</pubDate>
				<category><![CDATA[Tooling]]></category>
		<category><![CDATA[CI]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[tools]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3054</guid>

					<description><![CDATA[Continuous Integration (CI) has become an essential part of modern software development, and for good reason. It ensures code quality, speeds up development, and catches potential issues early. However, you can get started without an elaborate CI setup. Even a minimal CI setup can significantly improve your workflow. Here&#8217;s why every project should have at... <a class="more-link" href="https://sysdev.me/minimal-ci-for-go-library-with-github-actions/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/informative-errors-go/" rel="bookmark" title="Информативная обработка ошибок в Go">Информативная обработка ошибок в Go</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[ <p> <a href="https://sysdev.me/wp-content/uploads/2024/11/actions_and_go.png"><img loading="lazy" decoding="async" class="size-thumbnail wp-image-3076 alignleft" src="https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-150x150.png" alt="" width="150" height="150" srcset="https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-150x150.png 150w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-300x300.png 300w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-768x768.png 768w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-500x500.png 500w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-400x400.png 400w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-800x800.png 800w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-200x200.png 200w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-57x57.png 57w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-72x72.png 72w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-114x114.png 114w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-144x144.png 144w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go-120x120.png 120w, https://sysdev.me/wp-content/uploads/2024/11/actions_and_go.png 1024w" sizes="auto, (max-width: 150px) 100vw, 150px" /></a>Continuous Integration (CI) has become an essential part of modern software development, and for good reason. It ensures code quality, speeds up development, and catches potential issues early. However, you can get started without an elaborate CI setup. Even a minimal CI setup can significantly improve your workflow. Here&#8217;s why every project should have at least minimal CI and how to implement it effectively using GitHub Actions. </p> 
<h1>What Constitutes Minimal CI?</h1>
 <p> For a project to benefit from CI without excessive complexity, it should include the following essential components: </p> 
 <p> 1. <strong>Project Compilation:</strong> Verify that the codebase is always in a buildable state. <br /> 
2. <strong>Unit Test Execution:</strong> Ensure the core functionality works as expected. <br /> 
3. <strong>Static Code Analysis:</strong> Catch bugs and enforce coding standards before they become an issue. </p> 
 <p> <span id="more-3054"></span> </p> 
<h1>Why GitHub Actions?</h1>
 <p> GitHub Actions offers a simple yet powerful CI/CD platform that integrates seamlessly with GitHub repositories. Its ease of use makes it accessible even for developers without extensive DevOps experience. In fact, with just a few workflows, you can have a robust CI pipeline for small projects. </p> 
 <p> For example, for my small open-source Go library <a href="https://github.com/astavonin/gfsm" target="_blank">GFSM</a>, three workflows—<strong>build</strong>, <strong>static-check</strong>, and <strong>publish</strong>—are sufficient. </p> 
 <p>  <!--more-->  </p> 
<h1>Setting Up Your Workflows</h1>
<div class="alert info">A fully functional GitHub Actions-based CI example from <a href="https://github.com/astavonin/gfsm/tree/main/.github" target="_blank">GFSM</a>.</div>
<h2>1. Build Workflow</h2>
 <p> The build workflow ensures your code compiles and passes tests on every <inl_code>push</inl_code> or <inl_code>pull_request</inl_code> to any branch: </p> 
<div class="codecolorer-container yaml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="yaml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: green;">on</span><span style="font-weight: bold; color: brown;">: </span><span class="br0">&#91;</span><span style="color: #CF00CF;">&quot;push&quot;</span>, <span style="color: #CF00CF;">&quot;pull_request&quot;</span><span class="br0">&#93;</span><br />
<span style="color: #007F45;"><br />
jobs</span>:<span style="color: #007F45;"><br />
&nbsp; build</span>:<span style="color: green;"><br />
&nbsp; &nbsp; runs-on</span><span style="font-weight: bold; color: brown;">: </span>ubuntu-latest<span style="color: #007F45;"><br />
&nbsp; &nbsp; steps</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - uses</span><span style="font-weight: bold; color: brown;">: </span>actions/checkout@v4<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>prepare-env<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; uses</span><span style="font-weight: bold; color: brown;">: </span>./.github/env<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>Build<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; run</span><span style="font-weight: bold; color: brown;">: </span>go build -v ./<span style="color: cyan;">...</span><span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>Test<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; run</span><span style="font-weight: bold; color: brown;">: </span>go test -v ./<span style="color: cyan;">...</span></div></div>
<h2>2. Static Code Analysis</h2>
 <p> Static analysis helps maintain code quality by catching potential issues early. The best Go linter at the moment &#8211; <a href="https://staticcheck.dev" target="_blank">staticcheck</a>, provides an excellent integration with GitHub actions out of the box. Like the build workflow, this workflow runs on every <inl_code>push</inl_code> or <inl_code>pull_request</inl_code>: </p> 
<div class="codecolorer-container yaml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="yaml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #007F45;">jobs</span>:<span style="color: #007F45;"><br />
&nbsp; ci</span>:<span style="color: green;"><br />
&nbsp; &nbsp; name</span><span style="font-weight: bold; color: brown;">: </span><span style="color: #CF00CF;">&quot;Run CI&quot;</span><span style="color: green;"><br />
&nbsp; &nbsp; runs-on</span><span style="font-weight: bold; color: brown;">: </span>ubuntu-latest<span style="color: #007F45;"><br />
&nbsp; &nbsp; steps</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - uses</span><span style="font-weight: bold; color: brown;">: </span>actions/checkout@v2<span style="color: #007F45;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; with</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch-depth</span><span style="font-weight: bold; color: brown;">: </span>1<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>prepare-env<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; uses</span><span style="font-weight: bold; color: brown;">: </span>./.github/env<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - uses</span><span style="font-weight: bold; color: brown;">: </span>dominikh/staticcheck-action@v1<span style="color: #007F45;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; with</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; version</span><span style="font-weight: bold; color: brown;">: </span><span style="color: #CF00CF;">&quot;latest&quot;</span></div></div>
<h2>3. Publish Workflow</h2>
 <p> Publishing a new version to <a href="https://pkg.go.dev" target="_blank">pkg.go.dev</a> ensures that users always have access to the latest updates. The tricky part is triggering the <a href="https://pkg.go.dev" target="_blank">pkg.go.dev</a> proxy to update its cache for new versions. On comparison with <inl_code>build</inl_code> and <inl_code>static-check</inl_code> workflows, we should trigger new version publication only on a new tag push in a semantic versioning format. Here&#8217;s how you can set up this workflow to track new tags and ping the proxy: </p> 
<div class="codecolorer-container yaml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="yaml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #007F45;">on</span>:<span style="color: #007F45;"><br />
&nbsp; push</span>:<span style="color: #007F45;"><br />
&nbsp; &nbsp; tags</span><span style="font-weight: bold; color: brown;">:<br />
</span> &nbsp; &nbsp; &nbsp;- 'v<span class="br0">&#91;</span>0-9<span class="br0">&#93;</span>+.<span class="br0">&#91;</span>0-9<span class="br0">&#93;</span>+.<span class="br0">&#91;</span>0-9<span class="br0">&#93;</span>+'<br />
<span style="color: #007F45;"><br />
jobs</span>:<span style="color: #007F45;"><br />
&nbsp; publish</span>:<span style="color: green;"><br />
&nbsp; &nbsp; name</span><span style="font-weight: bold; color: brown;">: </span><span style="color: #CF00CF;">&quot;pkg.go.dev publishing&quot;</span><span style="color: green;"><br />
&nbsp; &nbsp; runs-on</span><span style="font-weight: bold; color: brown;">: </span>ubuntu-latest<span style="color: #007F45;"><br />
&nbsp; &nbsp; steps</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>Publishing new version<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; run</span><span style="font-weight: bold; color: brown;">: |<br />
</span><span style="color: #303050;background-color: #F5F5F5"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;curl https://sum.golang.org/lookup/github.com/astavonin/gfsm@${{ github.ref_name }}</span></div></div>
<h1> Reusable Composite Actions</h1>
 <p> Both the <inl_code>build</inl_code> and <inl_code>static-check</inl_code> workflows require the same environment setup. To avoid duplicating this logic, use GitHub Actions&#8217; <a href="https://docs.github.com/en/actions/sharing-automations/creating-actions/creating-a-composite-action" target="_blank">composite</a> feature to create a reusable setup action: </p> 
<div class="codecolorer-container yaml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="yaml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #007F45;">runs</span>:<span style="color: green;"><br />
&nbsp; using</span><span style="font-weight: bold; color: brown;">: </span>composite<span style="color: #007F45;"><br />
&nbsp; steps</span>:<span style="color: green;"><br />
&nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>Setup Go<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; uses</span><span style="font-weight: bold; color: brown;">: </span>actions/setup-go@v5<span style="color: #007F45;"><br />
&nbsp; &nbsp; &nbsp; with</span>:<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; &nbsp; go-version</span><span style="font-weight: bold; color: brown;">: </span>1.23.x<span style="color: green;"><br />
&nbsp; &nbsp; - name</span><span style="font-weight: bold; color: brown;">: </span>Generate<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; shell</span><span style="font-weight: bold; color: brown;">: </span>bash<span style="color: green;"><br />
&nbsp; &nbsp; &nbsp; run</span><span style="font-weight: bold; color: brown;">: |<br />
</span><span style="color: #303050;background-color: #F5F5F5"> &nbsp; &nbsp; &nbsp; &nbsp;go get golang.org/x/tools/cmd/stringer@latest<br />
&nbsp; &nbsp; &nbsp; &nbsp; go install golang.org/x/tools/cmd/stringer@latest<br />
&nbsp; &nbsp; &nbsp; &nbsp; go generate ./...</span></div></div>
 <p> This composite action ensures consistency and simplifies workflow maintenance. </p> 
<h1>Looking Ahead</h1>
 <p> Go currently relies on the <inl_code>tools.go</inl_code> file for dependencies, which I find a too ugly approach and prefer to have some extra <inl_code>go get/install/generate</inl_code> in my environment setup yaml file. But Go 1.24 promises a much cleaner approach with its &#8220;<a href="https://github.com/golang/go/issues/48429" target="_blank">track tool dependencies in go.mod (#48429)</a>&#8221; feature. Once available, it will streamline dependency management much more excellently. </p> 
<h1> Final Thoughts</h1>
 <p> Implementing minimal CI with GitHub Actions requires minimal effort but yields significant benefits. By automating builds, tests, and static analysis, you can ensure your project maintains high quality and is always ready for deployment. For small projects, this setup is a no-brainer, and GitHub Actions makes it easy to get started. </p> 
<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/informative-errors-go/" rel="bookmark" title="Информативная обработка ошибок в Go">Информативная обработка ошибок в Go</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/minimal-ci-for-go-library-with-github-actions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3054</post-id>	</item>
		<item>
		<title>GFSM: A Simple and Fast Finite State Machine for Go</title>
		<link>https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/</link>
					<comments>https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Stavonin]]></dc:creator>
		<pubDate>Mon, 25 Nov 2024 14:12:49 +0000</pubDate>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Software Architecture]]></category>
		<guid isPermaLink="false">https://sysdev.me/?p=3010</guid>

					<description><![CDATA[Design patterns are not widely used in Go, as they can often lead to unnecessary complexity in the codebase. However, the Finite State Machine (FSM) is an exception that proves to be incredibly useful. When I set out to design GFSM, I aimed to create a fast and straightforward FSM implementation for Go. I initially... <a class="more-link" href="https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/">Continue reading <span class="meta-nav">&#8594;</span></a><div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/go-and-project-quality/" rel="bookmark" title="Go и контроль качества проекта">Go и контроль качества проекта</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<a href="https://sysdev.me/wp-content/uploads/2024/11/fsm.png"><img loading="lazy" decoding="async" class="align left size-thumbnail wp-image-3049 alignleft" src="https://sysdev.me/wp-content/uploads/2024/11/fsm-150x150.png" alt="" width="150" height="150" srcset="https://sysdev.me/wp-content/uploads/2024/11/fsm-150x150.png 150w, https://sysdev.me/wp-content/uploads/2024/11/fsm-300x300.png 300w, https://sysdev.me/wp-content/uploads/2024/11/fsm-768x768.png 768w, https://sysdev.me/wp-content/uploads/2024/11/fsm-500x500.png 500w, https://sysdev.me/wp-content/uploads/2024/11/fsm-400x400.png 400w, https://sysdev.me/wp-content/uploads/2024/11/fsm-800x800.png 800w, https://sysdev.me/wp-content/uploads/2024/11/fsm-200x200.png 200w, https://sysdev.me/wp-content/uploads/2024/11/fsm-57x57.png 57w, https://sysdev.me/wp-content/uploads/2024/11/fsm-72x72.png 72w, https://sysdev.me/wp-content/uploads/2024/11/fsm-114x114.png 114w, https://sysdev.me/wp-content/uploads/2024/11/fsm-144x144.png 144w, https://sysdev.me/wp-content/uploads/2024/11/fsm-120x120.png 120w, https://sysdev.me/wp-content/uploads/2024/11/fsm.png 1024w" sizes="auto, (max-width: 150px) 100vw, 150px" /></a> Design patterns are not widely used in Go, as they can often lead to unnecessary complexity in the codebase. However, the Finite State Machine (FSM) is an exception that proves to be incredibly useful. When I set out to design <a href="https://github.com/astavonin/gfsm" target="_blank">GFSM</a>, I aimed to create a fast and straightforward FSM implementation for Go.
 </p> 
I initially sought a quick and straightforward FSM solution for Go, but I couldn&#8217;t find anything that met my needs. Drawing inspiration from the speed-focused and minimalistic principles of C++ while remaining true to Go&#8217;s idioms, I developed <a href="https://github.com/astavonin/gfsm" target="_blank">GFSM</a> to fill this gap. The outcome is GFSM—a library that distinguishes itself from alternatives like <a href="https://github.com/looplab/fsm" target="_blank">looplab/fsm</a> by prioritizing speed and simplicity.
 </p> 
Whether orchestrating microservices, handling distributed systems, or designing embedded systems, <a href="https://github.com/astavonin/gfsm" target="_blank">GFSM</a> brings the reliability and efficiency needed to keep things running smoothly.

<h1>Real-World Use Case: Two-Phase Commit Protocol</h1>

One of the best showcases for FSMs is the <a href="https://en.wikipedia.org/wiki/Two-phase_commit_protocol" target="_blank">Two-Phase Commit protocol</a> (TPC), widely used in distributed systems to ensure atomic transactions. Let’s explore how GFSM can model this protocol step by step.

<span id="more-3010"></span>

<h2>1. Define Your State Machine</h2>

To build a TPC protocol FSM, we start with a basic state machine:


<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">graph TD;
    Init-->Wait;
    Wait-->Abort;
    Wait-->Commit;</pre></div>


This state machine has four states: </p> 

&#8211; <inl_code>Init</inl_code>: The initialization phase. <br /> 
&#8211; <inl_code>Wait</inl_code>: Waiting for votes. <br /> 
&#8211; <inl_code>Abort</inl_code>: Aborting the transaction. <br /> 
&#8211; <inl_code>Commit</inl_code>: Committing the transaction.

<h2>2. Enumerate All Possible States</h2>

GFSM allows any <inl_code>comparable</inl_code> type as state identifiers, but integer-based enumerations keep things clean and fast. For TPC, here’s how the states are defined:
 <p> 

<div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #b1b100; font-weight: bold;">type</span> State <span style="color: #993333;">int</span><br />
<span style="color: #b1b100; font-weight: bold;">const</span> <span style="color: #339933;">(</span><br />
&nbsp; &nbsp; Init State <span style="color: #339933;">=</span> iota<br />
&nbsp; &nbsp; Wait<br />
&nbsp; &nbsp; Abort<br />
&nbsp; &nbsp; Commit<br />
<span style="color: #339933;">)</span></div></div>

<h2>3. Define State Behaviors</h2>

Each state in GFSM is represented by an action handler implementing the <inl_code>StateAction</inl_code> interface:
 <p> 

<div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #b1b100; font-weight: bold;">type</span> StateAction<span style="color: #339933;">[</span>StateIdentifier comparable<span style="color: #339933;">]</span> <span style="color: #993333;">interface</span> <span style="color: #339933;">{</span><br />
&nbsp; &nbsp; OnEnter<span style="color: #339933;">(</span>smCtx StateMachineContext<span style="color: #339933;">)</span><br />
&nbsp; &nbsp; OnExit<span style="color: #339933;">(</span>smCtx StateMachineContext<span style="color: #339933;">)</span><br />
&nbsp; &nbsp; Execute<span style="color: #339933;">(</span>smCtx StateMachineContext<span style="color: #339933;">,</span> eventCtx EventContext<span style="color: #339933;">)</span> StateIdentifier<br />
<span style="color: #339933;">}</span></div></div>

 <p> 
&#8211; <inl_code>OnEnter</inl_code>: Called when entering the state. <br /> 
&#8211; <inl_code>OnExit</inl_code>: Called when leaving the state. <br /> 
&#8211; <inl_code>Execute</inl_code>: Handles events and determines the next state. <br /> 
 <p> 
For example, the <inl_code>initState</inl_code> implementation might look like this:

<div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;"><span style="color: #993333;">func</span> <span style="color: #339933;">(</span>s <span style="color: #339933;">*</span>initState<span style="color: #339933;">)</span> Execute<span style="color: #339933;">(</span>smCtx gfsm<span style="color: #339933;">.</span>StateMachineContext<span style="color: #339933;">,</span> eventCtx gfsm<span style="color: #339933;">.</span>EventContext<span style="color: #339933;">)</span> State <span style="color: #339933;">{</span><br />
&nbsp; &nbsp; cCtx <span style="color: #339933;">:=</span> smCtx<span style="color: #339933;">.</span><span style="color: #339933;">(</span><span style="color: #339933;">*</span>coordinatorContext<span style="color: #339933;">)</span><br />
&nbsp; &nbsp; req<span style="color: #339933;">,</span> ok <span style="color: #339933;">:=</span> eventCtx<span style="color: #339933;">.</span><span style="color: #339933;">(</span>commitRequest<span style="color: #339933;">)</span><br />
&nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">if</span> <span style="color: #339933;">!</span>ok <span style="color: #339933;">{</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Handle invalid event</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> Init<br />
&nbsp; &nbsp; <span style="color: #339933;">}</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Transition logic</span><br />
&nbsp; &nbsp; <span style="color: #b1b100; font-weight: bold;">return</span> Wait<br />
<span style="color: #339933;">}</span></div></div>

<h2>4. Build the State Machine</h2>

Using the <inl_code>StateMachineBuilder</inl_code>, you can define the states, their transitions, and the associated context:
 <p> 

<div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">sm <span style="color: #339933;">:=</span> gfsm<span style="color: #339933;">.</span>NewBuilder<span style="color: #339933;">[</span>State<span style="color: #339933;">]()</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; SetDefaultState<span style="color: #339933;">(</span>Init<span style="color: #339933;">)</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; SetSmContext<span style="color: #339933;">(</span>&amp;coordinatorContext<span style="color: #339933;">{</span>partCnt<span style="color: #339933;">:</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">})</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; RegisterState<span style="color: #339933;">(</span>Init<span style="color: #339933;">,</span> &amp;initState<span style="color: #339933;">{},</span> <span style="color: #339933;">[]</span>State<span style="color: #339933;">{</span>Wait<span style="color: #339933;">})</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; RegisterState<span style="color: #339933;">(</span>Wait<span style="color: #339933;">,</span> &amp;waitState<span style="color: #339933;">{},</span> <span style="color: #339933;">[]</span>State<span style="color: #339933;">{</span>Abort<span style="color: #339933;">,</span> Commit<span style="color: #339933;">})</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; RegisterState<span style="color: #339933;">(</span>Abort<span style="color: #339933;">,</span> &amp;responseState<span style="color: #339933;">{</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; keepResp<span style="color: #339933;">:</span> Abort<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #339933;">},</span> <span style="color: #339933;">[]</span>State<span style="color: #339933;">{</span>Init<span style="color: #339933;">})</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; RegisterState<span style="color: #339933;">(</span>Commit<span style="color: #339933;">,</span> &amp;responseState<span style="color: #339933;">{</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; keepResp<span style="color: #339933;">:</span> Commit<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #339933;">},</span> <span style="color: #339933;">[]</span>State<span style="color: #339933;">{</span>Init<span style="color: #339933;">})</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; Build<span style="color: #339933;">()</span></div></div>

 <p> 
Here, <inl_code>coordinatorContext</inl_code> holds transaction details, such as the number of participants and the commit ID.

<h2>5. Run the State Machine</h2>

Once constructed, the FSM is ready to process events. Start the state machine, handle events, and gracefully terminate it:
 <p> 

<div class="codecolorer-container go default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:100%;"><div class="go codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap;">sm<span style="color: #339933;">.</span>Start<span style="color: #339933;">()</span><br />
<span style="color: #b1b100; font-weight: bold;">defer</span> sm<span style="color: #339933;">.</span>Stop<span style="color: #339933;">()</span><br />
<br />
err <span style="color: #339933;">:=</span> sm<span style="color: #339933;">.</span>ProcessEvent<span style="color: #339933;">(</span>commitRequest<span style="color: #339933;">{</span><span style="color: #cc66cc;">&quot;commit_1&quot;</span><span style="color: #339933;">})</span><br />
<span style="color: #b1b100; font-weight: bold;">if</span> err <span style="color: #339933;">!=</span> <span style="color: #000000; font-weight: bold;">nil</span> <span style="color: #339933;">{</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// Handle error</span><br />
<span style="color: #339933;">}</span></div></div>

During event processing, the FSM delegates logic to the current state’s <inl_code>Execute</inl_code> method, determining whether to transition or remain in the current state.

<h2>Learn More</h2>
Ready to integrate GFSM into your project? Check out the <a href="https://pkg.go.dev/github.com/astavonin/gfsm" target="_blank">documentation on pkg.go.dev</a> and explore the <a href="https://github.com/astavonin/gfsm/tree/main/examples" target="_blank">examples</a> for hands-on guidance.<div class='yarpp yarpp-related yarpp-related-rss yarpp-template-list'>
<!-- YARPP List -->
<h3> Related posts:</h3><ol>
<li><a href="https://sysdev.me/go-and-project-quality/" rel="bookmark" title="Go и контроль качества проекта">Go и контроль качества проекта</a></li>
<li><a href="https://sysdev.me/cmake-temp-dir-redirection/" rel="bookmark" title="Перенаправление временных файлов CMake">Перенаправление временных файлов CMake</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://sysdev.me/gfsm-a-simple-and-fast-fsm-for-go/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3010</post-id>	</item>
	</channel>
</rss>
