<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Another Mad World]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://www.anothermadworld.com/</link><image><url>https://www.anothermadworld.com/favicon.png</url><title>Another Mad World</title><link>https://www.anothermadworld.com/</link></image><generator>Ghost 3.15</generator><lastBuildDate>Thu, 15 Feb 2024 12:53:26 GMT</lastBuildDate><atom:link href="https://www.anothermadworld.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Our Firebase Tech Stack]]></title><description><![CDATA[How we built Ayrshare using Firebase, Firestore, and Cloud Functions.]]></description><link>https://www.anothermadworld.com/our-firebase-tech-stack/</link><guid isPermaLink="false">5f9a281b72923438c27182fe</guid><category><![CDATA[Firebase]]></category><category><![CDATA[Programming]]></category><category><![CDATA[Tech]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Thu, 29 Oct 2020 12:00:00 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/10/radek-grzybowski-8tem2WpFPhM-unsplash-1-150x150.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/10/radek-grzybowski-8tem2WpFPhM-unsplash-1-150x150.jpg" alt="Our Firebase Tech Stack"><p>When we started <a href="https://www.ayrshare.com">Ayrshare</a> we were keen on using an infrastructure as a service platform and avoid server setup, SSL certs, opening ports, etc. Time to market, right. Amongst the many platforms out there we choose <a href="https://www.firebase.com/">Firebase</a>. It was an easy decision for us since we are very comfortable with Firebase having built, and even sold, apps built upon it. If not Firebase our second choice would have been <a href="https://www.netlify.com/">Netlify</a>.</p><h2 id="today-and-tomorrow-requirements">Today and Tomorrow Requirements</h2><p>The first question we asked was, “What we need today?” If came down to a few criteria:</p><ul><li>Authentication, ideally having SSO with the major networks</li><li>Hosting a static single page app (React)</li><li>Hosting a landing page. We generally don’t like to build the landing pages in React.</li><li>A database, preferably noSQL</li><li>Back-end running NodeJS, preferably serverless</li><li>Event tracking, e.g. Google Analytics</li><li>Email service</li><li>Payment service</li></ul><p>Second, we asked, “What we might need tomorrow?”</p><ul><li>iOS and Android apps</li><li>Mobile app push notifications</li><li>ML (machine learning)</li></ul><h2 id="our-stack">Our Stack</h2><p>We have built on many platform: AWS, Heroku, under our desk (not kidding), and Digital Ocean. We ended up choosing Firebase since it meets a lot of our needs, but certainly not all.</p><figure class="kg-card kg-image-card"><img src="https://ayrshare.positorgroup.com/wp-content/uploads/2020/08/stack3-1-1024x667.png" class="kg-image" alt="Our Firebase Tech Stack"></figure><p>Firebase is a good choice for SPA React hosting and <a href="https://firebase.google.com/docs/firestore">Firestore</a> as a noSQL database. Google Analytics comes built into Firebase. Also, using Firebase’s <a href="https://firebase.google.com/docs/auth/web/firebaseui">authentication UI</a> system allowed us to have a secure registration and login process integrated with major SSO providers like Google, Facebook, and GitHub.</p><p>The landing page we built in WordPress hosted on Siteground. There are so many great templates and plugins available for WordPress that we see no reason to recreate the wheel in React. Another option we considered was <a href="https://www.gatsbyjs.org/">Gatsby</a> hosted on separate Firebase project.</p><p>Sending emails requires a mail provider and we are accustomed to using Mailgun. Firebase has recently introduced <a href="https://firebase.google.com/products/extensions">Extensions</a>, prebuilt cloud functions. One of our favorite is the <a href="https://www.anothermadworld.com/emailing-with-firebase-trigger-email-extension/">Email Trigger extension</a> that facilitates sending email from your cloud functions.</p><p>For a payment system, we choose <a href="https://www.stripe.com/">Stripe</a>. Stripe has a really nice <a href="https://www.npmjs.com/package/stripe">NPM package</a> that makes integration relatively easy.</p><p>Finally, we decided right before launch to add a <a href="https://docs.ayrshare.com/rest-api/endpoints/shorten">link shortener,</a> which is very useful when publishing to networks like Twitter that limit the characters. At first we were going to go with bit.ly, but it would soon become more expensive than what we were charging users. We ultimately went with Firebase’s <a href="https://firebase.google.com/products/dynamic-links">Dynamic Links</a>, Google’s replacement for goo.gl. Dynamic Links real power are with mobile apps, but it can also be used as a link shortener if you are willing use the RESTful API calls.</p><h3 id="firebase-cloud-functions-apis">Firebase Cloud Functions &amp; APIs</h3><p>Ayrshare is build as an API first platform, so it is critical to have a robust API system. Building a Cloud Function for each API endpoint is not flexible or secure. However, you can add <a href="https://expressjs.com/">Express</a> to Cloud Function and it is an excellent and battle tested framework to build and expose APIs.</p><p>For example, you can add several security and API facilitating packages such as:</p><pre><code class="language-javascript">const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");</code></pre><p>If you do add Express, you can add the “app” as an http function and export it.</p><pre><code class="language-javascript">const app = express();
exports.api = functions.https.onRequest(app);</code></pre><p>And then add you typical express functions.</p><pre><code class="language-javascript">app.get("/fun", (req, res) =&gt; {
  console.log("hello fun");
  return res.send('"Hi fun");
});</code></pre><h3 id="looking-towards-the-future">Looking Towards the Future</h3><p>In the future we plan on building mobile apps, especially for allowing Instagram posting, and will require push notifications. In previous projects we used <a href="https://firebase.google.com/docs/cloud-messaging">Firebase’s Cloud Messaging</a> (FCM) system and found it easy, reliable, and free!</p><p>And if we really look ahead, we want to add some ML analysis on ideal posting times. The current Firebase ML offering doesn’t seem a great fit, but perhaps it will be in the future.</p><h3 id="note-on-rate-limit"><strong><strong>Note on Rate Limit</strong></strong></h3><p>We had an interesting discussion on <a href="https://www.reddit.com/r/Firebase/comments/iqvoyj/our_firebase_tech_stack/g4wl9zc/?context=3">Reddit</a> regarding the use of express-rate-limit. See the code above for details.</p><p>We use express-rate-limit to manage API requests per IP so a user doesn’t make 1000 requests a minute. If you use the express-rate-limit default in-memory state storage, every time Cloud Functions re-initializes your code (and cold starts) and all modules are reloaded and the in-memory rate count starts from zero. For example, if you specify the rate limit to be 20 requests per hour and a user hits their limit, but a cold start occurs, the user could make another 20 calls within that hour.</p><p>The right way is to use an external storage for rate limit tracking. Luckly, there are packages that integrate with <a href="https://www.npmjs.com/package/rate-limit-redis">Redis</a>, <a href="https://www.npmjs.com/package/rate-limit-memcached">Memcache</a>, and <a href="https://www.npmjs.com/package/rate-limit-mongo">MongoDB</a>.</p><hr><p>Thank you for reading 🙏</p><p>Post originally appeared at: <a href="https://www.ayrshare.com/our-firebase-tech-stack/">https://www.ayrshare.com/our-firebase-tech-stack/</a></p>]]></content:encoded></item><item><title><![CDATA[How to Put a CDN in Front of Firebase Cloud Storage]]></title><description><![CDATA[A work-around to put Firebase Cloud Storage behind a CDN.]]></description><link>https://www.anothermadworld.com/how-to-put-a-cdn-in-front-of-firebase-cloud-storage/</link><guid isPermaLink="false">5ebb435772923438c27181aa</guid><category><![CDATA[Firebase]]></category><category><![CDATA[CDN]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Wed, 13 May 2020 01:07:13 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/05/marc-szeglat-VbP9v1rh-sc-unsplash--1--1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/05/marc-szeglat-VbP9v1rh-sc-unsplash--1--1.jpg" alt="How to Put a CDN in Front of Firebase Cloud Storage"><p>A lot of people have been asking if you can put a Content Delivery Network (CDN) like Cloudflare in front of Firebase Cloud Storage. Unfortunately, Firebase doesn't allow custom domains, so there is no easy way to add a CDN. </p><p>So officially, no.</p><p>In fact, Firebase itself doesn't put a CDN in front of Cloud Storage:</p><blockquote>Cloud Storage has no built-in CDN; the less short answer is: when your Cloud Storage is "multi-regional", it means that "hot content" (frequently accessed content) is available on different locations, but that is limited to multi-regional locations, and it applies only to the "jurisdiction" of the location, so, for example, if your project is in "us-central", then your multi-regional Storage will be stored only in the US data centers, so when accessed from Toronto, it will be served from the nearest US datacenter.</blockquote><p>But all is not lost. There is a way to add to have both a custom domain and a CDN.</p><h2 id="a-work-around-to-add-a-custom-domain-and-cloudflare-to-cloud-storage">A Work-Around to Add a Custom Domain and Cloudflare to Cloud Storage</h2><p>Here are the steps to put Cloudflare in front of Firebase Cloud Storage. This assumes you have Cloudflare or a similar CDN like Fastly setup.</p><ol><li>In Cloudflare create a new CNAME pointing your subdomain to <code>c.storage.googleapis.com.</code> For example: <code>CNAME images.firerun.io <code>c.storage.googleapis.com.</code></code></li><li>In the Firebase console -&gt; Storage, create a new bucket named the subdomain. In the example above, the bucket name would be "images.firerun.io". This is restriction where only the bucket named the same as the subdomain will work.</li><li>Add a test file, for example: keep-calm.jpg</li><li>Next, give public access to the bucket the Google Console. Note, this is different from Firebase security rules where you should set the security rules to allow externally allow read: </li><li>Go to <a href="https://console.cloud.google.com/projectselector2/storage/browser?supportedpurview=project">Storage Management</a> in the Google Console. Select your Firebase project.</li><li>Click on your new bucket (e.g. images.firerun.io) and click on the tab "permissions."</li><li>Click the "Add Members" button.</li><li>Enter New Member as "allUsers" and Role as Cloud Storage -&gt; <strong><strong>Storage Legacy Object Reader</strong></strong>". The <strong><strong>Storage Legacy Object Reader</strong></strong> prevents external users from doing a directory listing.</li><li>Click "Save" and accept the warning that this is publicly accessible.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.anothermadworld.com/content/images/2020/05/addmember.jpg" class="kg-image" alt="How to Put a CDN in Front of Firebase Cloud Storage"><figcaption>Cloud Storage Public Access Permissions</figcaption></figure><p>And that is it.</p><p>Now go to your subdomain with the file appended. For example: <a href="https://images.firerun.io/keep-calm.jpg">https://images.firerun.io/keep-calm.jpg</a></p><p>If there were issues it might be because you have custom SSL certificates at Cloudflare. Try with just http to see if SSL causes problems.</p><hr><p>Thank you for reading. 🙏</p><h3 id="about-author">About Author</h3><p>Geoff is co-founder of <a href="https://www.ayrshare.com/" rel="noopener nofollow"><strong><strong>Ayrshare</strong></strong></a>, an API-first platform to automate your social media posts with a few lines of code.</p>]]></content:encoded></item><item><title><![CDATA[Emailing with Firebase: The Trigger Email Extension]]></title><description><![CDATA[How to send emails from Firebase with the Trigger Email extension.]]></description><link>https://www.anothermadworld.com/emailing-with-firebase-trigger-email-extension/</link><guid isPermaLink="false">5e319acfefbbb21e59fae285</guid><category><![CDATA[Firebase]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Thu, 02 Apr 2020 12:00:00 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/05/firebase-email.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/05/firebase-email.jpg" alt="Emailing with Firebase: The Trigger Email Extension"><p>We've all done it 1,000 times: you build a new app and need to add dynamic email functionality. But is seem like every time you're re-inventing the wheel; setup a new email provider, install <a href="https://handlebarsjs.com/">Handlebars</a> (if you're not using handlebars your really should be), logging, etc.</p><p>The Firebase team has recently introduced a slightly simpler email process that I found removes about 20% of the pain. It is a part of the "extensions" suite of pre-built functions: <a href="https://firebase.google.com/products/extensions/firestore-send-email">Trigger Email Extension</a>. Note: the extension is officially in Beta, but we've been using it at <a href="https://www.ayrshare.com">Ayrshare</a> successfully without issue.</p><h2 id="the-good-the-not-so-good">The Good, the Not So Good</h2><p>Before we get into the setup of Trigger Email, I'll highlight what I like about the extension and what is a pain.</p><h3 id="the-good">The Good</h3><ul><li>Easy to setup and make use of.</li><li>Supports text and html emails, plus Handlebar templates.</li><li>Keeps a record of all email in a collection and logs sending/errors.</li></ul><h3 id="the-not-so-good">The Not So Good</h3><ul><li>Loss of functionality the email sender provides. For example, Mailgun support delayed sending times. There is no way to do with via the extension.</li><li>Handlebar templates stored in a collection. This requires an extra step to insert/update in the collection. I've forgotten a few times and wondered why my email didn't reflect my latest changes.</li><li>Possible additional costs because you're accessing the database and running a cloud function every time you send an email. If you're sending a lot of emails this could incur a large expense.</li></ul><h2 id="how-the-trigger-email-extension-works">How the Trigger Email Extension Works</h2><p>Quite simply, in fact. You're inserting the email you want to send in the Firestore database and a Cloud Function (provided by the Firebase team) runs on document write. The function takes the email data, applies the Handlebar template (if applicable), and sends it via the email provider you specify during setup.</p><p>You can even see the function listed under the Functions tab in the Firebase console.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.anothermadworld.com/content/images/2020/03/email_trigger.jpg" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"><figcaption>Trigger Email function in the Firebase console</figcaption></figure><h2 id="setting-up-the-trigger-email-extension">Setting Up the Trigger Email Extension</h2><ol><li>Click on the "Extension" link in the lower left corner of your Firebase console.</li></ol><figure class="kg-card kg-image-card"><img src="https://www.anothermadworld.com/content/images/2020/03/image-1.png" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"></figure><p>2. Choose "Install" of the Trigger Email card. Or choose "Learn more" to get a full overview of the extension.</p><figure class="kg-card kg-image-card"><img src="https://www.anothermadworld.com/content/images/2020/03/trigger.jpg" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"></figure><p>3. You'll find yourself at the 4-step wizard. You can view the function's <a href="https://github.com/firebase/extensions/tree/master/firestore-send-email">source code</a> if you're curious. The important parts of this wizard are setting up billing (meaning <strong>if you're in the Spark plan you need to upgrade to the Blaze plan</strong>) granting access to the email function, and configuring the extension (see step #4).</p><figure class="kg-card kg-image-card"><img src="https://www.anothermadworld.com/content/images/2020/03/wizard.jpg" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"></figure><p>4. Configuring the extension requires you to have an email provider such as <a href="https://sendgrid.com/docs/API_Reference/SMTP_API/getting_started_smtp.html">Sendgrid</a>, <a href="https://help.mailgun.com/hc/en-us/articles/203380100-Where-Can-I-Find-My-API-Key-and-SMTP-Credentials-">Mailgun</a>, or <a href="https://postmarkapp.com/developer/user-guide/sending-email/sending-with-smtp">Postmark</a>. At your email provider get the SMTP URI. This usually contains the providers domain and API key. Once you have the SMTP URI from your provider, insert it into the field <code>SMTP connection URI</code>. If you run into trouble, so through your providers documentation.</p><p>Next, set the email document collection where you'll be writing your emails to send (most people just use "mail"). Don't worry about creating the "mail" collection ahead of time. It will automatically be created the first time you write to it. </p><figure class="kg-card kg-image-card"><img src="https://www.anothermadworld.com/content/images/2020/03/config2.jpg" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"></figure><p>You also need to set your FROM email and REPLY-TO emails addresses. </p><p><em><strong>Quick tip:</strong> </em>the latest version of Email Trigger function allows you to specify a From name such as "John Smith." Simply use this format in the FROM field:</p><!--kg-card-begin: markdown--><pre><code>John Smith &lt;john@smith.com&gt;
</code></pre>
<!--kg-card-end: markdown--><p>Finally, you can optionally give a Users Collection or a Template Collection.</p><blockquote><strong>User Collection:</strong> A collection of documents keyed by user UID. If the <code>toUids</code>, <code>ccUids</code>, and/or <code>bccUids</code> recipient options are used in the added email document, this extension delivers email to the <code>email</code> field based on lookups in this collection.</blockquote><blockquote><strong>Template Collection:</strong> A collection of email templates keyed by name. This extension can render an email using a <a href="https://handlebarsjs.com/" rel="noopener">Handlebar</a> template, if the template is specified in the added email document.</blockquote><p>We will talk more about the template collection later. Also see below in the reference section for the available fields.</p><p>And that is it. Your Trigger Email is setup.</p><h2 id="send-your-first-email">Send Your First Email</h2><p>Now it is time to send your first email. Let's start with a simple text/html email. We will be giving the example from the server-side or Cloud Function.</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">admin.firestore().collection('mail').add({
  to: 'someone@example.com',
  message: {
    subject: 'Hello from Firebase!',
    text: 'This is the plaintext section of the email body.',
    html: 'This is the &lt;code&gt;HTML&lt;/code&gt; section of the email body.',
  }
}).then(() =&gt; console.log('Queued email for delivery!'));
</code></pre>
<!--kg-card-end: markdown--><p>In this example, we store our email in the "mail" collection as an object containing the "to" string (or array if multiple emails) and "message" object that contains the email subject and HTML content.</p><p>And once your store your email in the collection, you're done. The Trigger Email Cloud Function will pick up the email, processes it, and send it to your mail provider.</p><h2 id="add-a-handlebars-template">Add a Handlebars Template</h2><p>Let's take it up a notch and use a Handlebars template, really the best way to go when sending dynamic emails. </p><ol><li>Create your email as a Handlebars template. If you need help, follow a <a href="https://mandrill.zendesk.com/hc/en-us/articles/205582537-Using-Handlebars-for-Dynamic-Content">guide</a>.</li><li>Create a new Firestore collection called <code>email_templates</code> and a document in the collection called <code>welcome</code>. As you can guess, we'll first be sending a welcome email.</li><li>Into the Firestore <code>welcome</code> document, create a new String field called <code>html</code> and set the value as the content of your Handlebars template. Also add a second field <code>subject</code> and set the value to whatever you want the subject of the email to be. You can also use Handlebar expressions in the subject {{ ... }}.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.anothermadworld.com/content/images/2020/04/welcome_report.jpg" class="kg-image" alt="Emailing with Firebase: The Trigger Email Extension"><figcaption>Firestore "email_template" and "welcome" document</figcaption></figure><p>4. Now you're ready to send an email. Here is an example, again on the server-side.</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">admin.firestore().collection('mail').add({
  to: 'john@smith.com,
  template: {
    name: 'welcome',
    data: {
      fname: 'John',
      msg: 'Welcome to the fun.'
    }
  }
});
</code></pre>
<!--kg-card-end: markdown--><p>The Trigger Email will look for the template <code>welcome</code> and pass in the <code>data</code> object to apply to the Handlebar expressions. And your email is sent.</p><h2 id="email-security">Email Security</h2><p>As the Firebase team states:</p><blockquote>This extension can be used to trigger email delivery directly from client applications. However, you should carefully control client access to the <code>mail</code> collection to avoid potential abuse (you don’t want users able to send arbitrary emails from your company’s address!).</blockquote><p>The best way I found is to use templates and only send emails from the server-side. You can write a universal function that takes the UID and template name to restrict who gets the emails and what can be sent.</p><hr><p>Thank you for reading. 🙏</p><hr><h2 id="firebase-trigger-email-reference">Firebase Trigger Email Reference</h2><h3 id="available-sender-and-recipient-fields">Available Sender and Recipient Fields</h3><ul><li><strong>from:</strong> The sender’s email address. If not specified in the document, uses the configured “Default FROM address” parameter.</li><li><strong>replyTo:</strong> The reply-to email address. If not specified in the document, uses the configured “Default REPLY-TO address” parameter.</li><li><strong>to:</strong> A single recipient email address or an array containing multiple recipient email addresses.</li><li><strong>toUids:</strong> An array containing the recipient UIDs.</li><li><strong>cc:</strong> A single recipient email address or an array containing multiple recipient email addresses.</li><li><strong>ccUids:</strong> An array containing the CC recipient UIDs.</li><li><strong>bcc:</strong> A single recipient email address or an array containing multiple recipient email addresses.</li><li><strong>bccUids:</strong> An array containing the BCC recipient UIDs.</li><li><strong>headers:</strong> An object of additional header fields (for example, <code>{"X-Custom-Header": "value", "X-Second-Custom-Header": "value"}</code>).</li></ul><p><strong>NOTE:</strong> The <code>toUids</code>, <code>ccUids</code>, and <code>bccUids</code> options deliver emails based on user UIDs keyed to email addresses within a Cloud Firestore document. To use these recipient options, you need to specify a Cloud Firestore collection for the extension’s “Users collection” parameter. The extension can then read the <code>email</code> field for each UID specified in the <code>toUids</code>, <code>ccUids</code>, and/or <code>bccUids</code> fields.</p><h3 id="template-available-fields">Template Available Fields</h3><p>The template document can include any of the following fields:</p><ul><li><strong>subject:</strong> A template string for the subject of the email.</li><li><strong>text:</strong> A template string for the plaintext content of the email.</li><li><strong>html:</strong> A template string for the HTML content of the email.</li><li><strong>amp:</strong> A template string for the <a href="https://amp.dev/documentation/guides-and-tutorials/learn/email-spec/amp-email-format/" rel="noopener">AMP4EMAIL</a> content of the email.</li></ul>]]></content:encoded></item><item><title><![CDATA[Why You Should Put a CDN Like Cloudflare in Front of Firebase]]></title><description><![CDATA[There are three good reasons you should consider putting a CDN like Cloudflare in front of Firebase.]]></description><link>https://www.anothermadworld.com/why-you-should-put-a-cdn-like-cloudflare-in-front-of-firebase/</link><guid isPermaLink="false">5e73cd9e1d4aec6f80f0a32a</guid><category><![CDATA[Firebase]]></category><category><![CDATA[CDN]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Thu, 19 Mar 2020 20:59:47 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/03/firerunIO.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/03/firerunIO.jpg" alt="Why You Should Put a CDN Like Cloudflare in Front of Firebase"><p>Firebase is an amazing comprehensive platform that takes care of a lot of your infrastructure needs without you needing to lift a finger. It even comes with it's own CDN (content delivery network) that servers up your static content from edge servers. This means your content will theoretically load nice and fast for your users since it is on servers closer to them.</p><p>However, I'm a big fan of putting Cloudflare (or another CDN provider of your choice like Fastly) in front of Firebase, especially because most the functionality you need is free. </p><p><em>Note:</em> I have no association with Cloudflare, just a user.</p><h2 id="why-use-cloudflare-with-firebase">Why use Cloudflare with Firebase?</h2><p>At first glance you might think, "why make things more complicated, especially since Firebase already comes with a CDN?" Fair point, but there are three reasons why I think it makes sense to insert Cloudflare in front of Firebase:</p><ol><li>Security &amp; Protection</li><li>Cost Savings &amp; Prevention</li><li>Speed</li></ol><h2 id="security-protection">Security &amp; Protection</h2><p>While Firebase does have a CDN, it doesn't offer you distributed denial of service attacks (DDoS) prevention, web application firewall (WAF), or rate limiting. All of these are incredibly important to prevent malicious actors from breaking your system or stealing your data.</p><p>And if you don't stop someone at your CDN, your Firebase costs could skyrocket.</p><h2 id="cost-savings-prevention">Cost Savings &amp; Prevention</h2><p>Have your heard about the infamous<a href="https://startupsventurecapital.com/firebase-costs-increased-by-7-000-81dc0a27271d?gi=ec496fbcbbdb"> 7000% increase</a> in Firebase costs? If you are on the Blaze Plan, you will pay-as-you-go. If you don't carefully monitor your costs, you might get an unwelcome bill at the end of the month.</p><p>For example, you will pay <a href="https://firebase.google.com/pricing">$0.15 per GB transferred</a> from hosting over your free 10 GB monthly limit. By having a CDN like Cloudflare in front of Firebase, you'll rarely hit your Firebase hosting server, thus reducing your potential charges.</p><p>And going back to Security &amp; Protection, if a bad actor does a DDoS attack, you'll stop them at Cloudflare and not start racking up charges.</p><h2 id="speed">Speed</h2><p>This one might surprise you since why would Cloudflare be any after than Firebase's CDN. Truth is, they are probably equivalent. However, Cloudflare offers several speed enhancements I've found valuable.</p><ol><li><em>Brotli Compression:</em> Speed up page load times for your user's HTTPS traffic by applying Brotli compression (a slightly better compression technique).</li><li><em>Optimize Delivery:</em> Rocket Loader - free and improves paint time especially for pages with Javascript, Railgun - requires paid business plan and gives faster dynamic content delivery, Control of Caching - free and you can set how long your content will be cached for.</li><li><em>Argo Routing:</em> Argo is a service that uses optimized routes across the Cloudflare network to deliver responses to your users more quickly, reliably, and securely. It costs me about $5/month and my test have shown a 25% load time improvement.</li></ol><p>Overall, it takes about 10 minutes to set up a CDN in front of Firebase and I've found it well worth the effort.</p><h2 id="update-on-cloudflare-with-cloud-storage">Update on Cloudflare with Cloud Storage</h2><p>Since publishing the article several questions have been asked about putting Cloudflare or a CDN in front of Firebase Cloud Storage. Unfortunately, Firebase doesn't allow custom domains, so there is no easy way to add a CDN.</p><p>In fact, Firebase itself doesn't put a CDN in front of Cloud Storage:</p><blockquote>Cloud Storage has no built-in CDN; the less short answer is: when your Cloud Storage is "multi-regional", it means that "hot content" (frequently accessed content) is available on different locations, but that is limited to multi-regional locations, and it applies only to the "jurisdiction" of the location, so, for example, if your project is in "us-central", then your multi-regional Storage will be stored only in the US data centers, so when accessed from Toronto, it will be served from the nearest US datacenter.</blockquote><p>But all is not lost. There is <a href="https://www.anothermadworld.com/how-to-put-a-cdn-in-front-of-firebase-cloud-storage/">a way to add to have both</a> a custom domain and a CDN.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.anothermadworld.com/how-to-put-a-cdn-in-front-of-firebase-cloud-storage/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to Put a CDN in Front of Firebase Cloud Storage</div><div class="kg-bookmark-description">A work-around to put Firebase Cloud Storage behind a CDN.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.anothermadworld.com/favicon.png" alt="Why You Should Put a CDN Like Cloudflare in Front of Firebase"><span class="kg-bookmark-author">Geoffrey Bourne</span><span class="kg-bookmark-publisher">Another Mad World</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.anothermadworld.com/content/images/2020/05/marc-szeglat-VbP9v1rh-sc-unsplash--1--3.jpg" alt="Why You Should Put a CDN Like Cloudflare in Front of Firebase"></div></a></figure><p></p><hr><p>Thank you for reading. 🙏</p><p>If you're looking to post to social media with an API for yourself or on behalf of your users, check out our app <a href="https://www.ayrshare.com"><strong>Ayrshare</strong></a>. With a few lines of code, you'll be posting to Twitter, Instagram, Facebook, and more.</p>]]></content:encoded></item><item><title><![CDATA[Organizing Your Firebase Client-Side Configuration File]]></title><description><![CDATA[How best to organize your Firebase configuration information with examples in React.]]></description><link>https://www.anothermadworld.com/firebase-client-side-config-file/</link><guid isPermaLink="false">5e318babefbbb21e59fae191</guid><category><![CDATA[Firebase]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Wed, 29 Jan 2020 14:02:58 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/05/firebase-config.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/05/firebase-config.jpg" alt="Organizing Your Firebase Client-Side Configuration File"><p><em>Note:</em> The following examples are in React, but you can adapt them to your language of choice.</p><p>When you implement client-side Firebase, you need to add in the <a href="https://firebase.google.com/docs/web/setup">configuration goodies</a> Firebase gives you at setup to initialize the Firebase object.</p><figure class="kg-card kg-code-card"><pre><code class="language-JavaScript">var firebaseConfig = {
  apiKey: "api-key",
  authDomain: "project-id.firebaseapp.com",
  databaseURL: "https://project-id.firebaseio.com",
  projectId: "project-id",
  storageBucket: "project-id.appspot.com",
  messagingSenderId: "sender-id",
  appId: "app-id",
  measurementId: "G-measurement-id",
};</code></pre><figcaption>Example Firebase Config: <a href="https://firebase.google.com/docs/web/setup">https://firebase.google.com/docs/web/setup</a></figcaption></figure><p>Typically you do not want to repeat this config info in multiple places. Furthermore, you want to initialize the various Firebase objects, such as firebase, firestore, performance, and analytics, your app will make use of.</p><h2 id="firebase-js">firebase.js</h2><p>In my React apps, I create one file called <em>firebase.js</em> and place it in the main directory. Within this file I house the Firebase config info, initialize my objects, and export them. I then import the object from this file where ever I need access to Firebase resources.</p><figure class="kg-card kg-code-card"><pre><code class="language-JavaScript">import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";

import "firebase/analytics";
import "firebase/performance";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID
};

firebase.initializeApp(firebaseConfig);
const performance = firebase.performance();
const db = firebase.firestore();
const analytics = firebase.analytics();

export default firebase;
export { db, firebaseConfig, analytics, performance };</code></pre><figcaption>Example firebase.js</figcaption></figure><p>Note that by initializing the analytics object, you're now <a href="https://firebase.google.com/docs/analytics/get-started?platform=web">tracking basic user behavior</a>. If you want to record specific events you will use the analytics object.</p><p>Now I'm set to go and can import my firebase.js file where ever I need access to the Firebase objects.</p><pre><code class="language-JavaScript">import firebase, { db, analytics } from "./firebase";</code></pre><h2 id="-env">.env</h2><p>You might have noticed the <code>process.env.REACT_APP_FIREBASE_KEY</code>. Instead of hardcoding config values in my firebase.js file (but you are welcome to do so), I instead utilize the .env file that React (using <a href="https://reactjs.org/docs/create-a-new-react-app.html">create-react-app</a> or manually with <a href="https://webpack.js.org/guides/environment-variables/">Webpack</a>) to manage the different environments.</p><p>Create a <code>.env.development</code>, <code>.env.staging</code>, and <code>.env.production</code> files to house your config files for your various environments. When you deploy, you can use the right config files for your environment. See <a href="https://www.anothermadworld.com/firebase-deploy-to-different-projects-with-different-configs/">Deploy Firebase</a> for more information. </p><hr><p>If you enjoyed, please consider <strong><a href="https://anothermadworld.com/signup/">subscribing</a></strong> to be kept informed. </p><p>Also check out my <a href="https://firebase.substack.com/"><strong>Firebase Substack Newsletter</strong></a><strong> </strong>🔥 for even more great Firebase articles and videos.</p>]]></content:encoded></item><item><title><![CDATA[Deploy Firebase Different Hosting Environments]]></title><description><![CDATA[Use different configs for each of your Firebase hosting environments.]]></description><link>https://www.anothermadworld.com/firebase-deploy-to-different-projects-with-different-configs/</link><guid isPermaLink="false">5dcafe38efbbb21e59fae108</guid><category><![CDATA[Firebase]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Tue, 12 Nov 2019 19:14:14 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1503455876088-69e73d67c258?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1503455876088-69e73d67c258?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Deploy Firebase Different Hosting Environments"><p>Google's Firebase is a great platform to quickly build apps. However, there are a few tricky things one must around, such as managing and deploying to different hosting environments.</p><p>While there are many ways to create and manage different Firebase environments, such as using Firebase’s <a href="https://firebase.google.com/docs/functions/config-env" rel="noopener">env config</a> variables, I'll show you my favorite and easiest way using NodeJS and ReactJS.</p><h2 id="an-environment-for-every-occasion">An Environment for Every Occasion</h2><p>Here is what I do to create a dev, staging, and production environments with different configurations in Firebase.</p><p><strong>1.</strong> Setup a unique Firebase project in the Firebase console for each environment, e.g. Production, Staging, and Development.</p><p><strong>2. </strong>At a command prompt, assign an alias for each project with:</p><!--kg-card-begin: markdown--><p><code>firebase use --add</code></p>
<!--kg-card-end: markdown--><p>You will be prompted to select a project and an alias name to associate - use something simple like dev, staging, and prod. You can see all the aliases in the <code>.firebaserc</code> file or by typing <code>firebase use</code></p><p><strong>3.</strong> Install "dotenv" with:</p><!--kg-card-begin: markdown--><p><code>npm i --save-dev dotenv</code></p>
<!--kg-card-end: markdown--><p><strong>4.</strong> Create a different .env file for each environment: .env.production, .env.staging, .env.development. Place your environment configurations in the appropriate .env files, such as your Firebase staging project config into .env.staging.</p><p><strong>5.</strong> Add a build script "build-staging" to your package.json file (or build-dev) for each environment. For example:</p><!--kg-card-begin: markdown--><p><code>&quot;build-staging&quot;: &quot;dotenv -e .env.staging react-scripts build&quot;</code></p>
<!--kg-card-end: markdown--><p><strong>6.</strong> Build with the script you just created:</p><!--kg-card-begin: markdown--><p><code>npm run build-staging</code></p>
<!--kg-card-end: markdown--><p>This creates a static build of your React project using the environment variables you set in your .env file.</p><p><strong>7.</strong> Deploy to the F<a href="https://twitter.com/hashtag/firebase?src=hashtag_click">irebase</a> environment using <code>-P</code> followed by the alias name:</p><!--kg-card-begin: markdown--><p><code>firebase deploy -P staging</code></p>
<!--kg-card-end: markdown--><p><strong>8.</strong> Head to your project URL and verify the deployment was successful.</p><p></p><p>When you want to build and deploy to a different hosting environment, simply run the build script for that environment and deploy with that environment's alias.</p><p>Happy coding!</p><hr><p></p><p>Thank you for reading. 🙏</p><p><strong>But before you go:</strong> if you're a Firebase user, you're probably concerned about a surprise month-end bill or being suddenly shut off if your free tier runs out. </p><p>If this resonates with you, check out our app 🔥<a href="https://www.firerun.io"><strong>fireRun.io</strong></a>🔥 - the only way to monitor and control your Firebase spend and usage. Try it for <a href="https://www.firerun.io">Free</a>.</p>]]></content:encoded></item><item><title><![CDATA[If you can't code, you have no business managing engineers]]></title><description><![CDATA[Why it is important to be technical if you manage engineers or programmers.]]></description><link>https://www.anothermadworld.com/if-you-cant-code-you-have-no-business-managing-engineers/</link><guid isPermaLink="false">5ebab71072923438c271816a</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Tue, 15 Oct 2019 14:49:00 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/05/keep-calm.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/05/keep-calm.jpg" alt="If you can't code, you have no business managing engineers"><p>Do you run an organization with Engineers (i.e. Programmers, Developers, Hackers, Code Ninjas)? Is your title Technical Manager, Development Manager, Head of Technology, CTO, CIO, or any other sort of title that communicates “I’m in charge of technology”? If so, congrats on reaching the apogee of the tech department — yeah career! Nerds rule!</p><p>However, are you able to answer this quick question? What is the output of the following function?</p><!--kg-card-begin: markdown--><pre><code class="language-python">def function(x: Int): Int = {  
    def loop(y: Int, total: Int): Int = {    
        if(y == 0) total    
        else loop(y - 1, total * y)  
    }  
    loop(x, 1)
}
function(5)
</code></pre>
<!--kg-card-end: markdown--><p>or a less efficient (non-tail recursive), but easier to understand function</p><!--kg-card-begin: markdown--><pre><code class="language-python">def function(x: Int): Int = {  
    if(x == 0) 1  
    else x * function(x - 1)
}
function(5)
</code></pre>
<!--kg-card-end: markdown--><p>Did you get it? Great! Would you be able to write this in your programming language of choice (this was written in Scala, by the way)? Awesome! You can save your time and stop reading this article now, and perhaps go back to reading <a href="https://news.ycombinator.com" rel="noopener">Hacker News</a>. Note: if you’re in infrastructure, hardware, or another technology area, you can use an equivalent example such as being able to create a circuit diagram, grep logs, mount a drive, setup a server, run Puppet, setup a cluster, etc.</p><p>However, if you were confused, had no clue what this function did, didn’t get the answer 120 (5 factorial), or couldn’t write something like this in any programming language, please remove the word “Technology” or “Technical” or even “Information” from your title. To be blunt, until you brush up on your skills, you just don’t deserve to be called technical anymore (or maybe you never did).</p><p>Yes, I know, you think I’m crazy. At your level (responsibilities) you don’t need to know how to program or how the technology works. People do it for you. I get it. I’ve been told many times by non-technical managers who had those titles, and couldn’t figure out the simple function above, that being a “good” technology manager doesn’t require you to be technically skilled. Sorry, but I gotta call bullshit. Only people without technical skills make that sort of weak argument. The rest embrace their technical skills to be amazing leaders.</p><h2 id="leading-the-troops">Leading the Troops</h2><p>Let’s run through the a common argument and see if I can defend that being a technology manager requires <em>actual</em> technical expertise.</p><p><em>“I manage a big org, so I don’t need to know the how to code or the technical details.”</em></p><p><em>“I have good people who do the tech.”</em></p><p><em>“I lead and inspire.”</em></p><p>Leaders lead by example. How do you expect to “lead” or “inspire” an Engineer when you are unwilling or unable to get in the trenches with them? Do you know why George Washington’s troops loved him to the point that they would die for him? Sure, he was in charge, wore the fancy outfits, and had a cool title (General and Commander-in-Chief — awesome!), did the big picture stuff, etc, etc. But that didn’t convince his troops to boldly charge into battle. They did so because they felt he was one of them. He understood them. For example, Washington walked, ate, and lived amongst his troops when they camped at Valley Forge during the brutal winter of 1777–1778. He could have stayed in a big house with a warm fireplace, but he didn't. He didn’t because he was still a soldier, just like he had been many years ago during the French-Indian war, and was <em>still</em> able to be a soldier.</p><p>Code something, no matter how small, and release it to production.</p><p>I’m not saying you need to be coding all day, but the test is have you ever released to production at your company? Have you experienced what your team does daily? If you must, are you still able to still get into the trenches? Code something, no matter how small, and release it to production.</p><h2 id="get-coding-again">Get Coding Again</h2><p>When I worked at Goldman Sachs, my first day there a Super Senior Managing Director (un-official title: SSMD) sat me down and personally gave me an overview of the code structure. He knew how the systems worked and what it took to build them. Awesome! Know what, he had my absolute respect from that moment on. Even more importantly, a lot of his success came from being able to make the right decisions because of his deep understanding of the technology. I found out later that at Goldman every person in technology must be technical. At Google and Ladders (where I work) even Product Managers get programming questions (albeit simple ones) during their interview. Why? Because if you are going to work with Engineers, have the respect of Engineers, and truly understand Engineers, you need to be technically proficient.</p><p>ThoughtWorks <a href="https://www.thoughtworks.com/insights/blog/5-tips-being-effective-tech-lead" rel="noopener">furthers</a> the idea of needing to stay technical (for a Tech Lead, but can be applied to anyone with a “Technical” title):</p><p><em>If you do not spend time with the code, you run the risk of invoking the “Ivory Tower Architect” anti-pattern, leading technical decisions without understanding their real implications for implementation or maintenance. This anti-pattern has numerous side effects including destroying trust with developers, increasing the development time of new features, and increasing the accidental complexity of your software systems.</em></p><p>Just like my previous manager (SSMD), you probably ended up being a technical leader because you love technology, and probably coding. The trick is you can’t let that part of your skill set wither away. It is easy to let your tech skills rot when your day is 90% meetings and 10% budget planning exercises. Luckily, no one is asking you to be the best Javascript developer. However, if Javascript is one of your team’s primary languages, for goodness’ sake, take a <a href="https://www.coursera.org/learn/html-css-javascript" rel="noopener">course</a> or crack open a <a href="https://www.amazon.com/Eloquent-JavaScript-Modern-Introduction-Programming/dp/1593275846/ref=sr_1_11?ie=UTF8&amp;qid=1489689942&amp;sr=8-11&amp;keywords=javascript" rel="noopener">book</a> or launch <a href="https://atom.io" rel="noopener">Atom</a> to stay technical for the sake of your team, your company, and yourself.</p><p>And, by all mean, get coding again!</p><h3 id="about-the-author"><strong><strong>About the Author</strong></strong></h3><p>Geoffrey Bourne is the founder of <a href="https://www.firerun.io/">fireRun.io</a> - helping you manage and control your Firebase costs - and  <a href="https://www.retirety.com/">Retirety</a> — helping people in or near retirement find a better way to retire.</p>]]></content:encoded></item><item><title><![CDATA[The Man Who Knew Infinity: Coding Ramanujan’s Taxi]]></title><description><![CDATA[Coding Ramanujan’s Taxi problem in Scala.]]></description><link>https://www.anothermadworld.com/the-man-who-knew-infinity-coding-ramanujans-taxi/</link><guid isPermaLink="false">5ebab15b72923438c271812b</guid><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Geoffrey Bourne]]></dc:creator><pubDate>Tue, 01 Oct 2019 14:44:00 GMT</pubDate><media:content url="https://www.anothermadworld.com/content/images/2020/05/infinity.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://www.anothermadworld.com/content/images/2020/05/infinity.jpeg" alt="The Man Who Knew Infinity: Coding Ramanujan’s Taxi"><p>Have you see the movie (or read the book) <a href="http://www.imdb.com/title/tt0787524/" rel="noopener nofollow">The Man Who Knew Infinity</a>?</p><p>This movie — which stars Dev Patel and Jeremy Irons — explores Indian mathematician Srinivasa Ramanujan and his profound understanding, ingenuity, and love of math.</p><p>The film inspired me on both an intellectual and emotional level. But what really drew my attention was a particular five second scene.</p><p>The scene takes place in 1918. Ramanujan‘s mentor and friend G.H. Hardy quips that he had just taken taxi number 1729 and finds the number “a rather dull one.”</p><p>Ramanujan passionately replies, “No, Hardy, it’s a very interesting number! It’s the smallest number expressible as the sum of two cubes in two different ways.”</p><p>Ramanujan was able to see beyond the simple taxi cab number and into the depths of the expression behind it: a³ + b³ = c³ + d³…better known as <a href="https://en.wikipedia.org/wiki/Taxicab_number" rel="noopener nofollow">Ramanujan’s Taxi</a>. I thought this problem was fascinating and wondered how the code implementation would look. Little did I realize there were many optimization layers to this algorithm onion.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.anothermadworld.com/content/images/2020/05/taxi.jpeg" class="kg-image" alt="The Man Who Knew Infinity: Coding Ramanujan’s Taxi"><figcaption>The taxi Ramanujan took — at least in the movie</figcaption></figure><h2 id="first-crack-at-implementing-ramanujan-s-taxi">First Crack at Implementing Ramanujan’s Taxi</h2><p>I started with a straightforward implementation written in Scala. The code, with performance timings, can be found on <a href="https://github.com/gbourne1/Ramanujan_Taxi" rel="noopener nofollow">GitHub</a>:</p><!--kg-card-begin: html--><script src="https://gist.github.com/gbourne1/5d8691ad3f481bfa2ef1760150f54d3f.js"></script><!--kg-card-end: html--><p>We begin with a brute-force implementation by looping though all combinations to find where a³ + b³ = c³ + d³. We achieve O(n⁴) performance because of the four loops used to calculate all values of a³, b³, c³, and d³ equal or less than parameter n, which bounds our search field.</p><p>This brute-force implementation, with O(n⁴) performance, kinda sucks. So, how can we do better?</p><h2 id="we-can-do-better">We Can Do Better</h2><p>First question to ask is: do we always need to calculate all the values of a³, b³, c³, and d³? Remember, the equation we are using is a³ + b³ = c³ + d³. If we solve for d³, we get d³ = a³ + b³ - c³. Thus, once we know a³, b³, and c³, we can calculate the value of d³ directly instead looping through all values of d³.</p><p>My next implementation, again in Scala, replaces the fourth loop with the calculation d³ = a³ + b³ — c³:</p><!--kg-card-begin: html--><script src="https://gist.github.com/gbourne1/f0892b3291c126b5d6795757588525b9.js"></script><!--kg-card-end: html--><p>The 2nd version has O(n³) performance since we get to skip that final loop. Neat!</p><h2 id="third-time-s-a-charm">Third Time’s A Charm</h2><p>We’re not done yet. There is a third, and the best yet, enhancement to consider. What if we don’t need to solve for all values of not only d³, but c³ too? A few things to understand:</p><ol><li>If we calculate all values of a³ and b³ equal to or less than n, we essentially have all possible values of not only a³ and b³, but also c³ and d³.</li><li>The sum of a³ + b³ is equal to the sum of c³ + d³</li><li>If the sum of #2 above for a given pair of integers (a³, b³) matches the sum of another pair of integers (a³, b³), we have in essence found the c³ and d³ pair.</li></ol><p>If we store every combination of the sum of a³ + b³ and the corresponding pair (a³, b³), any sum that has two pairs means we have found a³ + b³ = c³ + d³ where the first pair in the list can be considered (a³, b³) and the next (c³, d³).</p><p>For example, if we iterate through the combinations of a³ + b³, we will store the sum 1729 with the pair (1³, 12³). Continuing to iterate, we will see another sum of 1729 arise, but this time with the pair (9³, 10³). Because we have two different pairs both summing to 1729, we have found a Ramanujan Taxi that solves for a³ + b³ = c³ + d³.</p><p>In the third version, we use a Hashmap to store the sum (key) and the corresponding list of pairs as a Sorted Set (value). If the list contains more than one pair, we’ve got a winner!</p><!--kg-card-begin: html--><script src="https://gist.github.com/gbourne1/09e7e5661c8919de694b185d87c34d36.js"></script><!--kg-card-end: html--><p>This implementation has O(n²) performance since we only need two loops to calculate the combinations for a³ and b³. Very neat!</p><p>I suspect there is a fourth optimization where we only need to calculate values of a³ and derive b³ from a³ (the ‘b’ loop is just an offset of the ‘a’ loop) with O(n) performance.</p><p>Also, another challenge is to re-write the implementations as a functional programming pattern. I’ll leave that for you to explore.</p><h2 id="an-amazing-movie-an-amazing-man">An Amazing Movie, an Amazing Man</h2><p>After watching The Man Who Knew Infinity, I was in awe of Ramanujan’s genius. By implementing his taxi algorithm — with its several performance optimizations — I got a glimpse of the beauty he saw in “No, Hardy, it’s a very interesting number!”</p><p>Ramanujan’s Taxi, at almost a century old, is still making new discoveries. Mathematicians at Emory University have <a href="http://phys.org/news/2015-10-mathematicians-magic-key-ramanujan-taxi-cab.html" rel="noopener nofollow">found</a> the number 1729 relates to elliptic curves and K3 surfaces — objects important today in string theory and quantum physics.</p><p>I expect we have only scratched the surface of Ramanujan’s taxi cab number and the man’s amazing genius.</p><h3 id="about-the-author"><strong>About the Author</strong></h3><p>Geoffrey Bourne is the founder of <a href="https://www.firerun.io">fireRun.io</a> - helping you manage and control your Firebase costs - and  <a href="https://www.retirety.com">Retirety</a> — helping people in or near retirement find a better way to retire.</p>]]></content:encoded></item></channel></rss>