<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yurii Rashkovskii</title>
    <description>The latest articles on DEV Community by Yurii Rashkovskii (@yrashk).</description>
    <link>https://dev.to/yrashk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F28182%2Fab2e482c-169d-4ddf-8c9c-6fa22c9a0eaa.jpg</url>
      <title>DEV Community: Yurii Rashkovskii</title>
      <link>https://dev.to/yrashk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yrashk"/>
    <language>en</language>
    <item>
      <title>Firing Developers Won’t Make Software Cheaper</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Tue, 08 Jul 2025 17:31:22 +0000</pubDate>
      <link>https://dev.to/omnigres/firing-developers-wont-make-software-cheaper-4p3j</link>
      <guid>https://dev.to/omnigres/firing-developers-wont-make-software-cheaper-4p3j</guid>
      <description>&lt;p&gt;Everyone cheering AI coding tools says the quiet part out loud eventually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“So… when can I fire my developers?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the real subtext no one puts in their blog posts.&lt;/p&gt;

&lt;p&gt;“A new class of builders is emerging” → (Translation: maybe we don’t need expensive engineers?)&lt;br&gt;
“Focus on outcomes, not methods” → (Translation: maybe we don’t need people who care about methods?)&lt;/p&gt;

&lt;p&gt;Under the polished veneer of empowerment, the motivation is clear: cut costs, move faster. And there’s nothing inherently wrong with that.&lt;/p&gt;

&lt;p&gt;Except we’re focusing on the visible output of software developers, and confusing that with their value. Simulating the output doesn’t eliminate the role — it just replaces developers with something fast, unpredictable, and equally expensive in other ways.&lt;/p&gt;

&lt;p&gt;You're still left with messy, brittle, over-complicated systems – just built faster and broken differently.&lt;/p&gt;

&lt;p&gt;The real move isn’t to replace developers with AI.&lt;/p&gt;

&lt;p&gt;It’s to stop needing so much software engineering, operations, and maintenance in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fantasy of Fewer Engineers
&lt;/h3&gt;

&lt;p&gt;Every few years, a new wave of tooling arrives that promises to make engineers obsolete. Even in the early days. COBOL. 4GLs. Visual Basic. No-code. Now, AI.&lt;/p&gt;

&lt;p&gt;Each time, the hope is the same: let someone else (or something else) do the building. But the underlying complexity doesn’t go away. It just gets hidden. Until it leaks.&lt;/p&gt;

&lt;p&gt;AI today is like hiring a half-drunk junior developer: fast, tireless, and unaware of consequences. It can spit out working code, but it can’t reason about tradeoffs, edge cases, evolving requirements, or failure modes.&lt;/p&gt;

&lt;p&gt;Software isn't expensive because of syntax. It's expensive because systems live for years, not minutes.&lt;/p&gt;

&lt;p&gt;The Problem Isn’t Developers. It’s Over-Engineering&lt;br&gt;
If you're trying to build business systems cheaper, the goal shouldn't be firing developers.&lt;/p&gt;

&lt;p&gt;The goal should be to need less bespoke code in the first place.&lt;/p&gt;

&lt;p&gt;Too many products are weighed down by:&lt;/p&gt;

&lt;p&gt;Separation of concerns&lt;br&gt;
Over-abundant, over-dependent microservices&lt;br&gt;
Ongoing maintenance and migration tax&lt;/p&gt;

&lt;p&gt;We've been chasing clever architectures instead of asking whether we need this much architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data, Not Software, Is the Core of Business Systems
&lt;/h3&gt;

&lt;p&gt;That’s what I’m working on.&lt;/p&gt;

&lt;p&gt;Since 2004, for over 20 years, I haven’t been able to shake the belief that the real heart of most business systems isn’t the code.&lt;/p&gt;

&lt;p&gt;It’s the data.&lt;/p&gt;

&lt;p&gt;Business workflows are usually just data state machines: records moving through stages, reacting to events, triggering outcomes.&lt;/p&gt;

&lt;p&gt;But data has been:&lt;/p&gt;

&lt;p&gt;Misunderstood by app developers&lt;br&gt;
Constrained by layers of abstractions&lt;br&gt;
Boxed away in the realm of DBAs and managed services&lt;/p&gt;

&lt;p&gt;What if we stopped pushing data to the edges of the system? What if we started with data and let systems emerge from there?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Future: Data-Native Architectures
&lt;/h3&gt;

&lt;p&gt;Not AI-generated code. Not yet another abstraction layer. But a fundamental shift in how we model, build, and reason about systems.&lt;/p&gt;

&lt;p&gt;If we want cheaper, more maintainable business software, we need to stop repeating the cycle: new tool, same mess, slightly better.&lt;/p&gt;

&lt;p&gt;We must reduce the need for software and understand that data is not buckets of "things" but a structured and fluid representation of reality. &lt;/p&gt;

&lt;p&gt;Let’s stop asking, "When can I fire my developers?"&lt;/p&gt;

&lt;p&gt;Let’s ask, "What can we build so we don’t need as many developers in the first place?"&lt;/p&gt;

&lt;p&gt;Let’s stop hiding the complexity.&lt;/p&gt;

&lt;p&gt;Let’s eliminate it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What happens if you put HTTP server inside Postgres?</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Mon, 06 Feb 2023 15:53:36 +0000</pubDate>
      <link>https://dev.to/omnigres/what-happens-if-you-put-http-server-inside-postgres-33kd</link>
      <guid>https://dev.to/omnigres/what-happens-if-you-put-http-server-inside-postgres-33kd</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@clarktibbs?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Clark Tibbs&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/oqStl2L5oxI?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Benchmarks and performance claims are attention-grabbers, but that's not what drew me to work on Omnigres. When I first built a prototype of its HTTP server, I didn't foresee the desire to share the numbers. As we all know, getting benchmarks right is hard, and everybody's mileage may vary. But I'll show you some numbers here anyway. It'll be great to validate or invalidate my findings!&lt;/p&gt;

&lt;p&gt;But first, what's Omnigres? The shortest definition I came up with is "Postgres as a Platform."&lt;/p&gt;

&lt;p&gt;What do I mean by this? Well, this comes from the idea that much of your application and its infrastructure can live inside or next to Postgres. Your business logic, deployment orchestration, caching, job queues, API endpoints, form handlers, HTTP server, you name it. Instead of building a system composed of multiple services, you only need one server that takes care of it. And if it can scale, you've got something great!&lt;/p&gt;

&lt;p&gt;I am not the only one intrigued by this idea (and many don't like it, either): check out &lt;a href="https://news.ycombinator.com/item?id=33934139" rel="noopener noreferrer"&gt;this HN thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And it is not "one-size-fits-all." But it fits a good set of problems. Anyway, that's a subject for another conversation.&lt;/p&gt;

&lt;p&gt;In the past weeks, I've taken the task of adding an embedded HTTP server to Omnigres. Since Omnigres is &lt;a href="https://dev.to/omnigres/why-not-rust-for-omnigres-43ak"&gt;implemented in C &lt;/a&gt;, it was only natural for me to choose &lt;a href="https://github.com/h2o/h2o" rel="noopener noreferrer"&gt;libh2o&lt;/a&gt; to implement the functionality of an HTTP server. It did help that H2O is known for its good performance characteristics. &lt;/p&gt;

&lt;p&gt;The idea was relatively simple: initialize a few HTTP worker processes, each quickly handing off details of the incoming HTTP requests to a Postgres instance in the same process. &lt;/p&gt;

&lt;p&gt;Sounds a bit weird, right? But bear with me, I will try to explain what's going on.&lt;/p&gt;

&lt;p&gt;Below is a sample piece of code of how an HTTP request can be handled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;omni_httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;omni_httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Hello, &amp;lt;b&amp;gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;/b&amp;gt;!'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;
       &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
       &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;string_to_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;UNION&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;omni_httpd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json_build_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'method'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'path'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'query_string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;
       &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first query in the union joins the request path of &lt;code&gt;/users/:user&lt;/code&gt; with the &lt;code&gt;users&lt;/code&gt; table on &lt;code&gt;users.handle&lt;/code&gt; column and serves an HTML response with that user's name.&lt;/p&gt;

&lt;p&gt;The second query, being lower in priority, simply returns a 404 Not Found response with a JSON that contains some of the request details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ http POST localhost:9000/users/johndoe
HTTP/1.1 200 OK
Connection: keep-alive
Server: omni_httpd-0.1
content-type: text/html
transfer-encoding: chunked

Hello, &amp;lt;b&amp;gt;John&amp;lt;/b&amp;gt;!

$ http POST localhost:9000/test\?q
HTTP/1.1 404 OK
Connection: keep-alive
Server: omni_httpd-0.1
content-type: text/json
transfer-encoding: chunked

{
    "method": "POST",
    "path": "/test",
    "query_string": "q"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all this worked, I decided to try benchmark it (mostly because I wanted to see how bad would it be):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wrk http://localhost:9000/users/johndoe -c 20 -t 10
Running 10s test @ http://localhost:9000/users/johndoe
  10 threads and 20 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   354.85us    1.40ms  47.24ms   97.05%
    Req/Sec    12.51k     2.37k   25.01k    73.84%
  1256199 requests in 10.10s, 179.70MB read
Requests/sec: 124366.73
Transfer/sec:     17.79MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's on MacBook Pro M1 Max. I've also ran the same test on an older x86_64-based Linux machine and got about 70K/sec.&lt;/p&gt;

&lt;p&gt;For reference, I decided to try comparing this with a similar (but quick-and-dirty-written) Node.js implementation that goes to the database for the same effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="cm"&gt;/* connection details */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;idleTimeMillis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestListener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;q&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT users.name FROM users WHERE users.handle = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]}).&lt;/span&gt;
        &lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;qres&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qres&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello, &amp;lt;b&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;qres&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/b&amp;gt;!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestListener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is running on http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I re-ran the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wrk http://localhost:8000/users/johndoe -c 20 -t 10
Running 10s test @ http://localhost:8000/users/johndoe
  10 threads and 20 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.11ms    0.99ms  33.09ms   99.15%
    Req/Sec     1.89k   166.30     2.19k    92.18%
  190319 requests in 10.10s, 33.76MB read
Requests/sec:  18838.56
Transfer/sec:      3.34MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the surface, it looks like omni_httpd is faster for the time being! I am sure with time it'll get slower and I did not explore enough optimizations available for the Node.js experiment (please contribute to make this picture fairer!). But it shows what bundling can do to performance!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As &lt;a href="https://lobste.rs/s/39ao1j/what_happens_if_you_put_http_server_inside#c_ipefyz" rel="noopener noreferrer"&gt;someone pointed out&lt;/a&gt;, using TCP locally brings unnecessary overhead where UNIX sockets would have performed better. So, I re-ran the Node.js test over UNIX sockets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wrk http://localhost:8000/users/johndoe -c 20 -t 10
Running 10s test @ http://localhost:8000/users/johndoe
  10 threads and 20 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   663.15us  224.77us   9.87ms   93.24%
    Req/Sec     3.05k   139.17     3.30k    88.71%
  306649 requests in 10.10s, 54.39MB read
Requests/sec:  30361.88
Transfer/sec:      5.39MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's indeed &lt;em&gt;quite a bit&lt;/em&gt; faster but still way below the numbers I was able to get with &lt;code&gt;omni_httpd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I want to emphasize that performance was not and is not a primary goal behind this work. What I think is more important there is changing the way we think about serving HTTP clients, doing data-aware routing, etc. There's still a lot of research to be done on this end.&lt;/p&gt;

&lt;p&gt;I also want to mention that this is still early work. There's a lot to be done to make this server production-grade (starting from &lt;a href="https://github.com/omnigres/omnigres/issues/44" rel="noopener noreferrer"&gt;enabling HTTPS support&lt;/a&gt;, and improving the architecture to make &lt;a href="https://github.com/omnigres/omnigres/issues/40" rel="noopener noreferrer"&gt;HTTP2 multiplexing really work&lt;/a&gt;, but not ending there), as well as building out other extensions to make building applications really easy and convenient.&lt;/p&gt;

&lt;p&gt;If you want to chat more, join us on &lt;a href="https://discord.gg/Jghrq588qS" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; or &lt;a href="http://t.me/omnigres" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>devto</category>
      <category>announcement</category>
      <category>community</category>
      <category>career</category>
    </item>
    <item>
      <title>Why not Rust for Omnigres?</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Fri, 06 Jan 2023 17:19:09 +0000</pubDate>
      <link>https://dev.to/omnigres/why-not-rust-for-omnigres-43ak</link>
      <guid>https://dev.to/omnigres/why-not-rust-for-omnigres-43ak</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/omnigres/omnigres" rel="noopener noreferrer"&gt;Omnigres&lt;/a&gt; is a new project to turn Postgres into a complete development and production deployment platform. I've started it to reflect on the complexity and inefficiencies plaguing modern business software development. &lt;/p&gt;

&lt;p&gt;As an aging (and sometimes cranky!) developer, I crave simplicity. But that's a topic for another post. Here I wanted to address a common question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why didn't you implement this in Rust?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's a great question, considering I've been using Rust for a number of years now, and I generally advocate its use for its rich ecosystem, safety and tooling. I &lt;a href="https://github.com/tcdi/pgx/pulls?q=is%3Apr+author%3Ayrashk+" rel="noopener noreferrer"&gt;actively contribute&lt;/a&gt; to &lt;a href="https://github.com/tcdi/pgx" rel="noopener noreferrer"&gt;pgx&lt;/a&gt;, a library for building Postgres extensions in Rust. Yet, Omnigres appears to be all done in C.&lt;/p&gt;

&lt;p&gt;Here's why.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Beware: the list has a lot of subjective and controversial opinions.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making a good wrapper (pgx) is a lot of work
&lt;/h3&gt;

&lt;p&gt;While it's getting there, when you try to build something pushing the boundaries, pgx may not yet provide sufficient API coverage, so you have to resort to unsafe FFI. It drove me to make a number of contributions to it. Still, since it takes a while to refine them enough to be considered well-rounded, it impedes general development velocity.&lt;/p&gt;

&lt;p&gt;Making a good, safe wrapper for such a complex project as Postgres is a significant undertaking. It'll take however long it takes. That's why I am wholeheartedly supporting it and spending time evolving it.&lt;/p&gt;

&lt;p&gt;But as of today, I want to be able to move fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Postgres is [quirky] C
&lt;/h3&gt;

&lt;p&gt;Its whole internal API is designed to be consumed by C code, and Postgres doesn't know anything about your other language.&lt;/p&gt;

&lt;p&gt;It uses &lt;code&gt;setjmp/longjmp&lt;/code&gt; for exceptions (so you'd have to roll your own guards to unwind the stack). It has its own memory management system. It manages the SPI stack. It has lots of mutable global variables!&lt;/p&gt;

&lt;p&gt;So, to consume it from C is only natural, even though it can be dangerous.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependencies
&lt;/h3&gt;

&lt;p&gt;Between not really knowing what's inside of your dependencies and obnoxious compile times, there's a reason for having less dependencies.&lt;/p&gt;

&lt;p&gt;Rust's Cargo makes it terribly easy to add dependencies, so there's no tax on adding yet another library. This is generally seen as a good thing in the industry, but I keep coming back to the idea that less is better.&lt;/p&gt;

&lt;p&gt;If, however, you had to pay for every dependency, we'd use a lot less of them, only when necessary. C is excellent in this department! I gave up on a number of dependencies simply because I had difficulties integrating them into my build system. So I see this is a filter for the need &lt;em&gt;and&lt;/em&gt; the quality of the dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast compile times
&lt;/h3&gt;

&lt;p&gt;Rust compiler is notoriously slow. Pgx brings its own complexity that makes rapid iteration nearly impossible. My builds are extremely fast with C. It's a simple language, and I tend to add very few dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex language fatigue
&lt;/h3&gt;

&lt;p&gt;I've been developing software for a few decades now and am growing tired of complex languages. Going back to C feels like taking a vacation and stopping chasing ideals and just focusing on the problem at hand.&lt;/p&gt;

&lt;p&gt;If Postgres (or Linux kernel) can be done in C, I am sure a few extensions could, too!&lt;/p&gt;

&lt;h3&gt;
  
  
  Formal verification methods
&lt;/h3&gt;

&lt;p&gt;There are projects that are focusing on bringing this to Rust, but there are some great static analysis and formal verification tools that have been used in C for quite a while. I fancy &lt;a href="https://frama-c.com" rel="noopener noreferrer"&gt;Frama-C&lt;/a&gt; and try to add it &lt;a href="https://github.com/omnigres/omnigres/blob/a291b00172a5ce430a9536c21f4a78f2f98a0114/libgluepg_curl/libgluepg_curl.c#L46-L64" rel="noopener noreferrer"&gt;bit&lt;/a&gt; by bit to Omnigres where I think it may be necessary. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rust safeties are slightly less relevant in Postgres
&lt;/h3&gt;

&lt;p&gt;Postgres is inherently &lt;strong&gt;single-threaded&lt;/strong&gt; and therefore, "fearless concurrency" is not buying us much. Sure, you can build an extension that'll communicate with other processes and threads over shared memory, but this is not much of a concern at the core database level.&lt;/p&gt;

&lt;p&gt;Postgres has its own &lt;strong&gt;memory management&lt;/strong&gt; story, which is quite good. Instead of having a single allocation pool, it has memory contexts that are established temporarily or for a scope. When they are deleted, all the memory allocated in them is released. So memory leaks are not necessarily a concern. Rust doesn't necessarily consider leaks a safety issue, but it's nice to know we will not crash the server with an OOM.&lt;/p&gt;

&lt;p&gt;Of course, there's still use-after-free, which you have to be careful about. This is where tools like AddressSanitizer can come in very handy.&lt;/p&gt;

&lt;p&gt;I've seen that most of my crashes in the extensions were coming from misusing some Postgres API, and I was getting a lot of them in Rust as well.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;But Yurii, isn't C a dangerous and flawed language?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, it is both dangerous and flawed. In general, I wouldn't build new projects in C, but after months of going back on forth on this, I think, ultimately, building a project on top of Postgres in C is reasonable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you consider Zig?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I absolutely did. I am very interested in Zig (and have previously developed some small projects in it) and I keep track of its development. But I ultimately didn't want to fight both Postgres and Zig at the same time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you consider Nim?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You bet! The attraction was that it compiles to C, and I can emit C code where necessary, obliterating the need to replicate certain tricks. But it's a complex, big language, and I am not confident about its own bugs, obscurities and upgrade stories (Nim 2 is coming!)&lt;/p&gt;




&lt;p&gt;Knowing how Rust crowd behaves sometimes, there may be those inclined to persuade me to change my opinion or prove me wrong. Of course, they are free to do so, but I'd prefer to focus on getting things done!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ultimately&lt;/strong&gt;, I think Rust is great. Omnigres will have first-class support for it and will promote its use and the use of &lt;a href="https://github.com/tcdi/pgx" rel="noopener noreferrer"&gt;pgx&lt;/a&gt; for building extensions.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>postgres</category>
      <category>c</category>
    </item>
    <item>
      <title>HackerIntro Insights Newsletter</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Fri, 23 Jul 2021 00:41:27 +0000</pubDate>
      <link>https://dev.to/hackerintro/hackerintro-insights-newsletter-h3e</link>
      <guid>https://dev.to/hackerintro/hackerintro-insights-newsletter-h3e</guid>
      <description>&lt;p&gt;Today, we're announcing a new take on presenting companies to software engineers. Instead of old and tired format of job ads (which are only read when somebody is actively looking), HackerIntro Insights newsletter is made of articles about companies — their challenges, history, culture. One can get an insight on things and projects before they even start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HlCDzLrf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtcyz05f5elrfl3pji1i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HlCDzLrf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtcyz05f5elrfl3pji1i.png" alt="Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have one rule: it &lt;strong&gt;must&lt;/strong&gt; be interesting. Doesn't matter if you're looking to find a new opportunity or not. This is something that would allow you to be aware of what's going on.&lt;/p&gt;

&lt;p&gt;We're working with our first cohort of companies and signing up first subscribers. Exciting times ahead!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hackerintro.com/insights"&gt;Join HackerIntro Insights&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Don't Leave Your Career to Chance</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Wed, 21 Jul 2021 17:50:37 +0000</pubDate>
      <link>https://dev.to/hackerintro/don-t-leave-your-career-to-chance-3nea</link>
      <guid>https://dev.to/hackerintro/don-t-leave-your-career-to-chance-3nea</guid>
      <description>&lt;p&gt;Hi, my name is Yurii. I am an entrepreneur, software engineer and I run &lt;a href="https://hackerintro.com"&gt;HackerIntro&lt;/a&gt;. I built it out of personal frustration over how inefficient tech talent recruitment is — on both sides.&lt;/p&gt;

&lt;p&gt;Have you ever felt unsure about how to deal with recruiting emails?&lt;/p&gt;

&lt;p&gt;Say, with something like this:&lt;/p&gt;

&lt;blockquote&gt;
Hey, found your GitHub account and was really impressed. We at Amazing Company are building X and I thought you might be a good match. Let me know if you want to chat!
&lt;/blockquote&gt;

&lt;p&gt;Should you respond? It seems to be a polite thing to do. On the other hand, engaging takes time and energy and saying "no" doesn't always feel good.&lt;/p&gt;

&lt;p&gt;In fact, at the right time, it might have been an interesting opportunity for you. But instead it becomes an email you never replied to.&lt;/p&gt;

&lt;p&gt;At HackerIntro, we want to create new relationships that work out great. And we do this by giving you a way to communicate your availability, interests and aspirations to most qualified matching opportunities.&lt;/p&gt;

&lt;p&gt;Today, it starts with a specialized &lt;code&gt;@hackerintro.com&lt;/code&gt; mailbox that gives you control over who can communicate with you and when. This is something you can leave out in public (your GitHub account, LinkedIn, etc.) and give recruiters and companies that are hiring a strong signal that you might be interested, without having to get inundated with mass-sent emails.&lt;/p&gt;

&lt;p&gt;Tomorrow depends on you. There are a lot of ideas that are being experimented on, like compensation for screening calls,&lt;br&gt;
auto-tailored resumes, anonymous profiles and so on. Whatever works out best for everybody will stay!&lt;/p&gt;

</description>
      <category>recruitment</category>
      <category>jobs</category>
      <category>gigs</category>
      <category>email</category>
    </item>
    <item>
      <title>Showing Some Love To Go Packages</title>
      <dc:creator>Yurii Rashkovskii</dc:creator>
      <pubDate>Wed, 05 May 2021 22:07:50 +0000</pubDate>
      <link>https://dev.to/yrashk/showing-some-love-to-go-packages-332m</link>
      <guid>https://dev.to/yrashk/showing-some-love-to-go-packages-332m</guid>
      <description>&lt;p&gt;Last month, I wanted to figure out the nicest way to make my Go package import URL look nice and short. First thing was to change the go.mod file and set the name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module bpxe.org

go 1.16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then I had to figure out how to make go get respect that, so that it actually works.The way importing from arbitrary URLs works is that go get will try fetching the URL and look for meta tags in the HTML page at that address. If you check the HTML source behind any repository’s page on GitHub, you’ll find go-import meta tag in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt; &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"go-import"&lt;/span&gt;
        &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"github.com/bpxe/bpxe git https://github.com/bpxe/bpxe.git"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is well-known and documented behavior. But as you can see, it still refers to the github.com namespaced URL (and rightfully so).&lt;/p&gt;

&lt;p&gt;I searched for the best way to enable a web server on my domain to serve such tags. Between running one of the micro tools that do just that, using GitHub Pages or simple web hosting, none of the options seemed streamline enough.&lt;/p&gt;

&lt;p&gt;Being slightly obsessed with making things neat (&lt;em&gt;my wife teaches me to be neat almost every day — and I’ll never reach her level!&lt;/em&gt;), I thought “wouldn’t it be cool to have a small service that handles this and just this thing nicely?”&lt;/p&gt;

&lt;p&gt;But alas, there was no such a service that I can find.&lt;/p&gt;

&lt;p&gt;This meant I either forget about it and do something that kind of works, or I spend my weekend hacking away! As if working on my main project during the weekdays wasn’t enough. But there was no stopping…&lt;/p&gt;

&lt;p&gt;It needed it to be so simple I can launch it within a day or so. So I decided to forego much of the complexity associated with setting up package prefix mapping in the UI (&lt;em&gt;it’s such a rabbit hole&lt;/em&gt;) and figured there’s a much easier way to do this: DNS records! So, if you own a domain and want to use it for your packages, you can simply use TXT records to store it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F700%2F1%2AF5L_KvxQOTYz7rhu__SNJw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F700%2F1%2AF5L_KvxQOTYz7rhu__SNJw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way, it’s easy to establish the exact configuration and mapping that needs to get rendered for &lt;code&gt;go get&lt;/code&gt; — making it (&lt;em&gt;and me&lt;/em&gt;) happy.&lt;/p&gt;

&lt;p&gt;Late Saturday, the proof of concept worked! But I couldn’t leave it at that. I needed the entire weekend to be spent hunched over keyboard.&lt;/p&gt;

&lt;p&gt;This is how Gopkg was born. I decided that the utility of it is sufficient to share it with others. So I took the rest of the weekend (and some more) to make it presentable and at least somewhat useful to other. I even commissioned a cute logo with Go’s mascot!&lt;/p&gt;

&lt;blockquote&gt;Also, it turned out that using DNS records is a great way to establish authenticity of HTML meta tags are being generated by the service: simply look up the TXT records and see if they match, since these records are under original author’s control and not Gopkg’s.&lt;/blockquote&gt;

&lt;p&gt;Now that it’s out and in public beta (what do these words mean nowadays, anyway?) I can go back to more work. I’ll be updating Gopkg to make it better and even more useful in the coming weeks (&lt;em&gt;there’s going to be some feature creep!&lt;/em&gt;)&lt;/p&gt;




&lt;p&gt;Do you have a Go package and you want its import URL look better? Do you want to get some package use statistics? Get a nicely looking site and multi-version documentation hosted at package’s URL? Then go check &lt;a href="https://gopkg.co" rel="noopener noreferrer"&gt;Gopkg&lt;/a&gt; out and maybe you’ll be as happy as I am!&lt;/p&gt;

</description>
      <category>go</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
