{"id":52,"date":"2026-02-08T01:50:39","date_gmt":"2026-02-08T01:50:39","guid":{"rendered":"https:\/\/mattbick.dev\/?p=52"},"modified":"2026-02-08T02:17:29","modified_gmt":"2026-02-08T02:17:29","slug":"its-not-your-language-slowing-you-down-its-your-architecture","status":"publish","type":"post","link":"https:\/\/mattbick.dev\/?p=52","title":{"rendered":"It\u2019s Not Your Language Slowing You Down \u2014 It\u2019s Your Architecture"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Recently I made the decision to rewrite a portion of my Lipsey&#8217;s distributor integration in good ole C using libcurl. I didn&#8217;t need to do this, but I was under the &#8220;it must be faster because it&#8217;s C&#8221; mindset. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So I went ahead and and flexed my C muscles, something that I haven&#8217;t done in a LONG time, and put together a small little implementation that calls that Catalog data endpoint using a POST request:<\/p>\n\n\n\n<pre data-line=\"\" class=\"wp-block-prismatic-blocks\"><code class=\"language-c\">#include &lt;curl\/curl.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;string.h&gt;\n#include &lt;time.h&gt;\n\n\/\/ ----------------------\n\/\/ Timing helpers (because &quot;it feels slow&quot; is not a metric)\n\/\/ ----------------------\nstatic double now_ms(void) {\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC, &amp;ts);\n    return (double)ts.tv_sec * 1000.0 + (double)ts.tv_nsec \/ 1000000.0;\n}\n\n\/\/ ----------------------\n\/\/ Dynamic response buffer (cheap, simple, works)\n\/\/ ----------------------\ntypedef struct {\n    char *data;\n    size_t size;\n} Memory;\n\n\/\/ Curl streams data into here. We just keep realloc\u2019ing like animals.\n\/\/ Totally fine for API responses.\nstatic size_t write_cb(void *contents, size_t size, size_t nmemb, void *userp) {\n    size_t realsize = size * nmemb;\n    Memory *mem = (Memory *)userp;\n\n    char *ptr = realloc(mem-&gt;data, mem-&gt;size + realsize + 1);\n    if (!ptr) return 0; \/\/ malloc said nope\n\n    mem-&gt;data = ptr;\n    memcpy(mem-&gt;data + mem-&gt;size, contents, realsize);\n    mem-&gt;size += realsize;\n    mem-&gt;data[mem-&gt;size] = &#039;\\0&#039;;\n\n    return realsize;\n}\n\n\/\/ ----------------------\n\/\/ Extremely lazy JSON helpers (string searching &gt; writing parser today)\n\/\/ ----------------------\n\nstatic int json_contains(const char *json, const char *needle) {\n    return (json &amp;&amp; needle &amp;&amp; strstr(json, needle) != NULL);\n}\n\n\/\/ We only care if econtact.success is true or 1. Not building a schema validator today.\nstatic int json_econtact_success_is_true_or_one(const char *json) {\n    const char *p = strstr(json, &quot;\\&quot;econtact\\&quot;&quot;);\n    if (!p) return 0;\n\n    \/\/ Only scan a window after econtact so we don&#039;t match random success fields later\n    const size_t WINDOW = 800;\n    size_t len = strlen(p);\n    if (len &gt; WINDOW) len = WINDOW;\n\n    char *tmp = (char *)malloc(len + 1);\n    if (!tmp) return 0;\n\n    memcpy(tmp, p, len);\n    tmp[len] = &#039;\\0&#039;;\n\n    int ok = 0;\n    if (strstr(tmp, &quot;\\&quot;success\\&quot;:true&quot;) ||\n        strstr(tmp, &quot;\\&quot;success\\&quot;: true&quot;) ||\n        strstr(tmp, &quot;\\&quot;success\\&quot;:1&quot;) ||\n        strstr(tmp, &quot;\\&quot;success\\&quot;: 1&quot;)) {\n        ok = 1;\n    }\n\n    free(tmp);\n    return ok;\n}\n\n\/\/ Pulls token out of `&quot;token&quot;:&quot;value&quot;`\n\/\/ Yes this is brittle. No I do not care for this use case.\nstatic int extract_token(const char *json, char *out_token, size_t max_len) {\n    if (!json || !out_token || max_len == 0) return -1;\n\n    const char *t = strstr(json, &quot;\\&quot;token\\&quot;&quot;);\n    if (!t) return -1;\n\n    t = strchr(t, &#039;:&#039;);\n    if (!t) return -1;\n    t++;\n\n    while (*t == &#039; &#039; || *t == &#039;\\t&#039;) t++;\n\n    if (*t != &#039;&quot;&#039;) return -1;\n    t++;\n\n    const char *end = strchr(t, &#039;&quot;&#039;);\n    if (!end) return -1;\n\n    size_t n = (size_t)(end - t);\n    if (n == 0 || n &gt;= max_len) return -1;\n\n    memcpy(out_token, t, n);\n    out_token[n] = &#039;\\0&#039;;\n    return 0;\n}\n\n\/\/ Try to dump API error array if present. Otherwise just dump tail and move on.\nstatic void print_api_errors_best_effort(const char *json) {\n    const char *p = strstr(json, &quot;\\&quot;errors\\&quot;&quot;);\n    if (!p) {\n        fprintf(stderr, &quot;No \\&quot;errors\\&quot; array found.\\n&quot;);\n        return;\n    }\n\n    const char *lb = strchr(p, &#039;[&#039;);\n    const char *rb = lb ? strchr(lb, &#039;]&#039;) : NULL;\n\n    if (lb &amp;&amp; rb &amp;&amp; rb &gt;= lb) {\n        fprintf(stderr, &quot;API errors: &quot;);\n        fwrite(lb, 1, (size_t)(rb - lb + 1), stderr);\n        fputc(&#039;\\n&#039;, stderr);\n    } else {\n        fprintf(stderr, &quot;API errors (raw tail): %s\\n&quot;, p);\n    }\n}\n\n\/\/ ----------------------\n\/\/ Curl helpers\n\/\/ ----------------------\n\n\/\/ Because env vars are nice when you don\u2019t want creds in source\nstatic int env_truthy(const char *name, int default_val) {\n    const char *v = getenv(name);\n    if (!v || !*v) return default_val;\n\n    if (strcmp(v, &quot;1&quot;) == 0 || strcasecmp(v, &quot;true&quot;) == 0 || strcasecmp(v, &quot;yes&quot;) == 0)\n        return 1;\n\n    if (strcmp(v, &quot;0&quot;) == 0 || strcasecmp(v, &quot;false&quot;) == 0 || strcasecmp(v, &quot;no&quot;) == 0)\n        return 0;\n\n    return default_val;\n}\n\n\/\/ Applies shared curl config so we don&#039;t copy\/paste 40 lines everywhere\nstatic void apply_common_opts(CURL *curl, int insecure, Memory *out) {\n    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);\n    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L);\n    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);\n    curl_easy_setopt(curl, CURLOPT_USERAGENT, &quot;bickhamfirearms-lipseys\/0.1&quot;);\n    curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1);\n\n    \/\/ Equivalent to PHP CURLOPT_ENCODING &quot;&quot;\n    curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, &quot;&quot;);\n\n    \/\/ Match vendor PHP behavior exactly (yes this disables TLS validation)\n    if (insecure) {\n        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);\n        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);\n    } else {\n        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);\n        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);\n    }\n\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);\n}\n\n\/\/ ----------------------\n\/\/ MAIN PROGRAM\n\/\/ ----------------------\n\nint main(void) {\n\n    const double t_program_start = now_ms();\n\n    \/\/ You can swap these to getenv if you want later\n    const char *email = &quot;fulfillment@bickhamfirearms.com&quot;;\n    const char *password = &quot;Lacro$$e1&quot;;\n\n    if (!email || !password) {\n        fprintf(stderr,\n            &quot;Missing credentials.\\n&quot;\n            &quot;Set:\\n&quot;\n            &quot;export LIPSEYS_EMAIL=...\\n&quot;\n            &quot;export LIPSEYS_PASSWORD=...\\n&quot;);\n        return 1;\n    }\n\n    \/\/ Default insecure to match vendor PHP exactly\n    int insecure = env_truthy(&quot;LIPSEYS_INSECURE&quot;, 1);\n\n    curl_global_init(CURL_GLOBAL_DEFAULT);\n\n    CURL *curl = curl_easy_init();\n    if (!curl) {\n        fprintf(stderr, &quot;curl init failed\\n&quot;);\n        curl_global_cleanup();\n        return 1;\n    }\n\n    const char *BASE = &quot;https:\/\/api.lipseys.com\/api\/&quot;;\n    const char *LOGIN_PATH = &quot;integration\/authentication\/login&quot;;\n    const char *CATALOG_PATH = &quot;integration\/items\/CatalogFeed&quot;;\n\n    \/\/ ---------------- LOGIN ----------------\n    const double t_login_start = now_ms();\n\n    char login_url[512];\n    snprintf(login_url, sizeof(login_url), &quot;%s%s&quot;, BASE, LOGIN_PATH);\n\n    char json_body[1024];\n    snprintf(json_body, sizeof(json_body),\n        &quot;{\\&quot;Email\\&quot;:\\&quot;%s\\&quot;,\\&quot;Password\\&quot;:\\&quot;%s\\&quot;}&quot;,\n        email, password);\n\n    Memory login_resp = {0};\n\n    curl_easy_reset(curl);\n    apply_common_opts(curl, insecure, &amp;login_resp);\n\n    struct curl_slist *login_headers = NULL;\n    login_headers = curl_slist_append(login_headers, &quot;Content-Type: application\/json&quot;);\n    login_headers = curl_slist_append(login_headers, &quot;Accept: application\/json&quot;);\n    login_headers = curl_slist_append(login_headers, &quot;Token: &quot;); \/\/ vendor sends even if blank\n\n    curl_easy_setopt(curl, CURLOPT_URL, login_url);\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, login_headers);\n    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, &quot;POST&quot;);\n    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body);\n\n    printf(&quot;Logging in...\\n&quot;);\n\n    CURLcode rc = curl_easy_perform(curl);\n\n    long http_code = 0;\n    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &amp;http_code);\n\n    const double t_login_end = now_ms();\n\n    if (rc != CURLE_OK) {\n        fprintf(stderr, &quot;Login failed: %s\\n&quot;, curl_easy_strerror(rc));\n        fprintf(stderr, &quot;[PROFILE] login %.2f ms\\n&quot;, t_login_end - t_login_start);\n        goto cleanup;\n    }\n\n    printf(&quot;[HTTP] Login status: %ld\\n&quot;, http_code);\n    printf(&quot;[PROFILE] Login took %.2f ms\\n&quot;, t_login_end - t_login_start);\n\n    char token[512] = {0};\n\n    int token_ok = extract_token(login_resp.data, token, sizeof(token)) == 0;\n    int econtact_ok = json_econtact_success_is_true_or_one(login_resp.data);\n\n    if (!token_ok || !econtact_ok) {\n        fprintf(stderr, &quot;Login rejected\\n&quot;);\n        print_api_errors_best_effort(login_resp.data);\n        goto cleanup;\n    }\n\n    printf(&quot;Token extracted OK (len=%zu)\\n&quot;, strlen(token));\n\n    \/\/ ---------------- CATALOG ----------------\n    const double t_catalog_start = now_ms();\n\n    char catalog_url[512];\n    snprintf(catalog_url, sizeof(catalog_url), &quot;%s%s&quot;, BASE, CATALOG_PATH);\n\n    Memory catalog_resp = {0};\n\n    curl_easy_reset(curl);\n    apply_common_opts(curl, insecure, &amp;catalog_resp);\n\n    char token_header[1024];\n    snprintf(token_header, sizeof(token_header), &quot;Token: %s&quot;, token);\n\n    struct curl_slist *catalog_headers = NULL;\n    catalog_headers = curl_slist_append(catalog_headers, token_header);\n    catalog_headers = curl_slist_append(catalog_headers, &quot;cache-control: no-cache&quot;);\n    catalog_headers = curl_slist_append(catalog_headers, &quot;Accept: application\/json&quot;);\n\n    curl_easy_setopt(curl, CURLOPT_URL, catalog_url);\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, catalog_headers);\n    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, &quot;GET&quot;);\n    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, &quot;&quot;);\n\n    printf(&quot;\\nFetching catalog...\\n&quot;);\n\n    rc = curl_easy_perform(curl);\n\n    long catalog_http = 0;\n    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &amp;catalog_http);\n\n    const double t_catalog_end = now_ms();\n\n    if (rc == CURLE_OK) {\n        printf(&quot;[HTTP] Catalog status: %ld\\n&quot;, catalog_http);\n        printf(&quot;[PROFILE] Catalog took %.2f ms\\n&quot;, t_catalog_end - t_catalog_start);\n\n        printf(&quot;\\nCatalog preview (first 2000 chars):\\n&quot;);\n        if (catalog_resp.data) {\n            size_t n = catalog_resp.size &gt; 2000 ? 2000 : catalog_resp.size;\n            fwrite(catalog_resp.data, 1, n, stdout);\n            printf(&quot;\\n&quot;);\n        }\n    }\n\n    \/\/ ---------------- TOTAL ----------------\n    const double t_program_end = now_ms();\n    printf(&quot;\\n[PROFILE] TOTAL PROGRAM TIME: %.2f ms (%.2f sec)\\n&quot;,\n        t_program_end - t_program_start,\n        (t_program_end - t_program_start) \/ 1000.0);\n\ncleanup:\n    curl_slist_free_all(login_headers);\n    curl_easy_cleanup(curl);\n    curl_global_cleanup();\n    free(login_resp.data);\n    return 0;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So, all of this code&#8230; what did it result in? Here ya go:<\/p>\n\n\n\n<pre data-line=\"\" class=\"wp-block-prismatic-blocks\"><code class=\"language-\">Catalog response preview (first 2000 chars):\n{&quot;success&quot;:true,&quot;authorized&quot;:true,&quot;errors&quot;:[],&quot;data&quot;:[{&quot;itemNo&quot;:&quot;RU1022RB&quot;,&quot;description1&quot;:&quot;10\/22 CARBINE 22LR BL\/WD 10+1#&quot;,&quot;description2&quot;:&quot;1103&quot;,&quot;upc&quot;:&quot;736676011032&quot;,&quot;manufacturerModelNo&quot;:&quot;1103&quot;,&quot;msrp&quot;:349.0,&quot;model&quot;:&quot;10\/22 Carbine&quot;,&quot;caliberGauge&quot;:&quot;22 LR&quot;,&quot;manufacturer&quot;:&quot;Ruger&quot;,&quot;type&quot;:&quot;Rifle&quot;,&quot;action&quot;:&quot;Semi-Auto&quot;,&quot;barrelLength&quot;:&quot;18.5\\&quot;&quot;,&quot;capacity&quot;:&quot;10 + 1&quot;,&quot;finish&quot;:&quot;Satin Black&quot;,&quot;overallLength&quot;:&quot;37\\&quot;&quot;,&quot;receiver&quot;:null,&quot;safety&quot;:null,&quot;sights&quot;:&quot;Gold Bead Front\/Folding Rear&quot;,&quot;stockFrameGrips&quot;:&quot;Wood Stock Hardwood&quot;,&quot;magazine&quot;:&quot;1 10 rd.&quot;,&quot;weight&quot;:&quot;5 lbs.&quot;,&quot;imageName&quot;:&quot;1103534d.jpg&quot;,&quot;chamber&quot;:null,&quot;drilledAndTapped&quot;:true,&quot;rateOfTwist&quot;:&quot;1-in-16&quot;,&quot;itemType&quot;:&quot;Firearm&quot;,&quot;additionalFeature1&quot;:&quot;Includes Scope Base&quot;,&quot;additionalFeature2&quot;:&quot;Barrel Band Stock&quot;,&quot;additionalFeature3&quot;:null,&quot;shippingWeight&quot;:6.25,&quot;boundBookManufacturer&quot;:&quot;Ruger&quot;,&quot;boundBookModel&quot;:&quot;10\/22&quot;,&quot;boundBookType&quot;:&quot;Rifle&quot;,&quot;nfaThreadPattern&quot;:null,&quot;nfaAttachmentMethod&quot;:null,&quot;nfaBaffleType&quot;:null,&quot;silencerCanBeDisassembled&quot;:false,&quot;silencerConstructionMaterial&quot;:null,&quot;nfaDbReduction&quot;:null,&quot;silencerOutsideDiameter&quot;:null,&quot;nfaForm3Caliber&quot;:null,&quot;opticMagnification&quot;:null,&quot;maintubeSize&quot;:null,&quot;adjustableObjective&quot;:false,&quot;objectiveSize&quot;:null,&quot;opticAdjustments&quot;:null,&quot;illuminatedReticle&quot;:false,&quot;reticle&quot;:null,&quot;exclusive&quot;:false,&quot;quantity&quot;:0,&quot;allocated&quot;:false,&quot;canDropship&quot;:false,&quot;onSale&quot;:false,&quot;price&quot;:199.0,&quot;currentPrice&quot;:199.0,&quot;retailMap&quot;:0.0,&quot;fflRequired&quot;:true,&quot;sotRequired&quot;:false,&quot;exclusiveType&quot;:&quot;&quot;,&quot;scopeCoverIncluded&quot;:false,&quot;special&quot;:null,&quot;sightsType&quot;:&quot;Adjustable Sights&quot;,&quot;case&quot;:null,&quot;choke&quot;:null,&quot;dbReduction&quot;:null,&quot;family&quot;:&quot;10\/22 Series&quot;,&quot;finishType&quot;:&quot;Blued&quot;,&quot;frame&quot;:null,&quot;gripType&quot;:&quot;Hardwood&quot;,&quot;handgunSlideMaterial&quot;:null,&quot;countryOfOrigin&quot;:&quot;US&quot;,&quot;itemLength&quot;:&quot;40.50&quot;,&quot;itemWidth&quot;:&quot;6.50&quot;,&quot;itemHeight&quot;:&quot;14.50&quot;,&quot;packageLength&quot;:&quot;40.0000&quot;,&quot;packageWidth&quot;:&quot;5.9000&quot;,&quot;packageHeight&quot;:&quot;2.9000&quot;,&quot;itemGroup&quot;:&quot;Sporting Semi-Auto Rimfire Rifles&quot;},{&quot;itemNo&quot;:&quot;SP0011710305-F&quot;,&quot;description1&quot;:&quot;PH3 6MMCR MOUNTAIN SHADOW 20\\&quot;&quot;,&quot;description2&quot;:&quot;0011710305-F&quot;,&quot;upc&quot;:&quot;811\n\n[PROFILE] TOTAL PROGRAM TIME: 7309.60 ms (7.31 sec)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A total run time of 7.3 seconds&#8230; the exact same as the PHP implementation that is within our current code. But how can this be? <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Well, like most software engineers, I took the arrogant perspective that I TOTALLY could write something faster than what the default PHP implementation could be. In reality, the PHP implementation uses the SAME EXACT curl calls that are all C under the hood. I spent all this time writing this code only to write the exact code that was running this entire time. Funny. At the end of the day, this Catalog refresh pipeline is dominated by the 7 second response time it takes to grab all that sweet, sweet catalog data. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Reality Most Developers Don\u2019t Want to Hear<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If your program:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Calls remote APIs<\/li>\n\n\n\n<li>Waits on databases<\/li>\n\n\n\n<li>Pulls files over FTP \/ HTTPS<\/li>\n\n\n\n<li>Talks to third-party vendors<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Then your performance is dominated by:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Network latency<\/li>\n\n\n\n<li>Remote server processing<\/li>\n\n\n\n<li>TLS handshakes<\/li>\n\n\n\n<li>Payload transfer time<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Not your language.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can rewrite PHP \u2192 C \u2192 Rust \u2192 Assembly \u2192 Hand-written transistor logic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the server takes 7 seconds to respond, you\u2019re still waiting 7 seconds. Period. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Hidden Truth: You\u2019re Probably Already Running C Anyway<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s the funny part.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lipsey\u2019s PHP example uses the PHP cURL extension as I stated above. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The PHP cURL extension is just a wrapper around:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>libcurl (C)<\/strong><\/li>\n\n\n\n<li><strong>OpenSSL (C)<\/strong><\/li>\n\n\n\n<li>OS networking stack (C \/ kernel space)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">So the real execution path looks like:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">PHP Version<\/h3>\n\n\n\n<pre data-line=\"\" class=\"wp-block-prismatic-blocks\"><code class=\"language-\">PHP Script\n \u2193\nPHP cURL Extension\n \u2193\nlibcurl (C)\n \u2193\nOpenSSL (C)\n \u2193\nKernel TCP Stack\n \u2193\nInternet<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">My C Version<\/h3>\n\n\n\n<pre data-line=\"\" class=\"wp-block-prismatic-blocks\"><code class=\"language-\">My C Program\n \u2193\nlibcurl (C)\n \u2193\nOpenSSL (C)\n \u2193\nKernel TCP Stack\n \u2193\nInternet<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So once the request leaves your process\u2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>You\u2019re in C anyway.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where The Time Actually Goes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When you break down HTTP requests, time is usually spent in:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">DNS Lookup<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Usually tiny.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">TCP Connect<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Usually small unless cross-region.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">TLS Handshake<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Moderate but predictable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Time To First Byte (TTFB)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is usually the killer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">TTFB includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Vendor backend processing<\/li>\n\n\n\n<li>Cache lookups<\/li>\n\n\n\n<li>DB queries<\/li>\n\n\n\n<li>Internal microservice calls<\/li>\n\n\n\n<li>Queue waits<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If TTFB is 5 seconds, you\u2019re done. That\u2019s your bottleneck. No more speedups or optimizations for you past this hard wall. Think of it like having 10 seconds of work, but only 5 seconds of it can be parallelizable. You are now stuck with 5 seconds of sequential runtime that wont be going away. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Actually Makes Systems Faster<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Not rewriting in C.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Usually:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Fewer Requests<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Don\u2019t poll APIs that update every 4 hours\u2026 every 5 minutes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Smarter Scheduling<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Run ingestion when vendor data actually changes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Caching<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Token caching. Response caching. Etc.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Connection Reuse<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Keep TCP + TLS sessions alive.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Streaming Instead of Buffering<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Especially for giant feeds. I ended up getting massive memory savings as explained in my last post by streaming to a TSV. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Dangerous Developer Trap<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Developers love optimizing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Language choice<\/li>\n\n\n\n<li>Micro-allocations<\/li>\n\n\n\n<li>Loop performance<\/li>\n\n\n\n<li>Branch prediction<\/li>\n\n\n\n<li>SIMD tricks<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Meanwhile:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They make 5 redundant API calls per request.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Architecture Mindset Shift<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Good performance thinking sometimes actually boils down to this:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cHow do I make this code faster?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Ask:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cHow do I do less work?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cHow do I optimize this loop?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Ask:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cWhy does this loop exist?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cShould I rewrite this in C?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Ask:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cWhy am I making this network call at all?\u201d<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Real Lesson<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">My goal was to beat PHP with C. Then it quickly was not my goal when I realized the folly of my ways. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In reality, we answered:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u201cIs my architecture the bottleneck?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The answer was yes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And that\u2019s valuable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because now I know where my real speed-ups occur:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Caching vendor feeds<\/li>\n\n\n\n<li>Reducing unnecessary logins<\/li>\n\n\n\n<li>Scheduling ingestion intelligently<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Thankfully, I already had the foresight to implement these things, but only after banging my head against the wall when I saw that my VPS CPU time was being eaten 24\/7. But you live and you learn I suppose. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thought<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Languages matter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But <strong>architecture matters more<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you\u2019re I\/O bound:<br>Language gains are noise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you\u2019re CPU bound:<br>Language matters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Most modern backend systems?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Are I\/O bound.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I made the decision to rewrite a portion of my Lipsey&#8217;s distributor integration in good ole C using libcurl. I didn&#8217;t need to do this, but I was under the &#8220;it must be faster because it&#8217;s C&#8221; mindset. So I went ahead and and flexed my C muscles, something that I haven&#8217;t done in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-52","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/posts\/52","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mattbick.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=52"}],"version-history":[{"count":8,"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/posts\/52\/revisions"}],"predecessor-version":[{"id":65,"href":"https:\/\/mattbick.dev\/index.php?rest_route=\/wp\/v2\/posts\/52\/revisions\/65"}],"wp:attachment":[{"href":"https:\/\/mattbick.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=52"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mattbick.dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=52"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mattbick.dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=52"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}