Joshua Wood (Daily Notes)2022-02-19T17:17:57+00:00https://www.joshuawood.net/feeds/daily-notes.xmlJoshua Woodjosh@joshuawood.netFebruary 15th, 20222022-02-15T08:00:00+00:002022-02-15T16:57:24+00:00https://www.joshuawood.net/notes/february-15th-2022<div class="block" id="block-4MSImWh0s"><p><a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a></p>
<div class="block" id="block-pRdoyx5Kn"><p><a href="https://www.poweredbysearch.com/blog/saas-marketing-budget/">What Most SaaS Companies Get Wrong About Marketing Budgets</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/saas'>#SaaS</a> <a data-prefetch='true' class='internal-link muted' href='/notes/marketing'>#Marketing</a></p>
<div class="block" id="block-Q9byrXFzY"><p>A strategy to find the right marketing budget for a B2B SaaS company:</p>
<div class="block" id="block-6WAS1VC-G"><p>Identify a target for MRR growth</p>
</div><div class="block" id="block-l1i3qtcPN"><p>Determine the number of new users required to hit that target</p>
</div><div class="block" id="block-MTaGPegHO"><p>Identify the rate of trial conversion</p>
</div><div class="block" id="block-ie3JRES-b"><p>Use the trial conversion rate to calculate the trials required to reach the needed number of new users</p>
</div><div class="block" id="block-KB9-bU5Bo"><p>Identify the fraction of website visitors that convert to trials</p>
</div><div class="block" id="block-ZuPizp0m-"><p>Calculate a click goal by dividing the number of trials required to hit the MRR growth target by the trial conversion rate</p>
</div><div class="block" id="block-8wEiW3NKc"><p>Test traffic channels to find the best customer-channel fit</p>
</div><div class="block" id="block-61YcNPkoS"><p>Calculate a marketing budget by multiplying the click goal by the blended average cost per click across effective channels</p>
</div></div></div><div class="block" id="block-U0v6xcWxu"><p><a href="https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection">Terraform: github_branch_protection</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/terraform'>#Terraform</a> <a data-prefetch='true' class='internal-link muted' href='/notes/oss-automation'>#OSS Automation</a></p>
</div></div>November 11th, 20212021-11-11T08:00:00+00:002021-11-11T21:02:57+00:00https://www.joshuawood.net/notes/november-11th-2021<div class="block" id="block-tWk_XKrrU"><p>“We are currently using [alternative] for monitoring our exceptions in both rails and react/angular applications. We are not very happy with the interface that [alternative] provides us with and we would like to support a developer-orientated product like Honeybadger.” <a data-prefetch='true' class='internal-link muted' href='/notes/honeybadger'>#Honeybadger</a> <a data-prefetch='true' class='internal-link muted' href='/notes/quotes'>#Quotes</a></p>
</div>August 18th, 20212021-08-18T07:00:00+00:002021-08-18T15:12:38+00:00https://www.joshuawood.net/notes/august-18th-2021<div class="block" id="block-0X2U0ELxA"><p><a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a></p>
<div class="block" id="block-fGljV_n_W"><p><a href="https://github.com/afomera/fathom_api">fathom_api Ruby Gem</a> — Access the new <a data-prefetch='true' class='internal-link' href='/notes/fathom-analytics'>Fathom Analytics</a> API in Ruby <a data-prefetch='true' class='internal-link muted' href='/notes/ruby'>#Ruby</a> <a data-prefetch='true' class='internal-link muted' href='/notes/packages'>#Packages</a> <a data-prefetch='true' class='internal-link muted' href='/notes/fathom-analytics'>#Fathom Analytics</a></p>
</div></div>August 15th, 20212021-08-15T07:00:00+00:002021-08-15T22:56:10+00:00https://www.joshuawood.net/notes/august-15th-2021<div class="block" id="block-yJlfSbFlR"><h2>More thoughts on <span class="block-ref">Apple’s New Child-Protection Features <a data-prefetch="true" href="/notes/august-14th-2021#block-QixIAfFMk">#</a></span></h2><div class="block" id="block-HvF7y1l8U"><blockquote>
<p><span class="block-ref">I’m glad that <a data-prefetch='true' class='internal-link' href='/notes/apple'>Apple</a> is doing <em>something</em>, and that their solution doesn’t make it easy to get around the new protections by default—like <a data-prefetch='true' class='internal-link' href='/notes/facebook'>Facebook</a>’s encryption option. <a data-prefetch='true' class='internal-link' href='/notes/ben-thompson'>Ben Thompson</a> makes a good point: maybe it would have been better not to compromise the device, and do the scanning in iCloud (which parents could choose to enable). <a data-prefetch="true" href="/notes/august-14th-2021#block-sWp-YZwBX">#</a></span></p>
</blockquote>
<div class="block" id="block-5sa-16EAw"><p>If you don’t use iCloud, then the safety vouchers are never sent anywhere. In that case—from a privacy standpoint—how is on-device fingerprinting different from fingerprinting in iCloud? It seems to be roughly equivalent. If Apple <em>does</em> enable end-to-end encryption in the future, I think their on-device approach makes a lot of sense and is <em>better</em> than fingerprinting in the cloud—which would rule out end-to-end encryption entirely.</p>
</div><div class="block" id="block-wCF1g1Gql"><p>In either case, the point of the CSAM detection feature is to detect the content if it’s <em>stored in the cloud</em>—not necessary when it’s <em>shared</em>. It doesn’t seem that Apple will detect or report CSAM in Messages, but they potentially <em>could</em> with the on-device scanning approach, and it would be the only way since Messages are <em>already</em> end-to-end encrypted.</p>
</div></div></div>August 14th, 20212021-08-14T07:00:00+00:002021-08-15T23:01:45+00:00https://www.joshuawood.net/notes/august-14th-2021<div class="block" id="block-IKz8CCFCL"><p><a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a></p>
<div class="block" id="block-cbDpf4p8w"><p><a href="https://www.wsj.com/articles/why-gold-bugs-bond-bears-and-amazon-skeptics-think-alike-11628863203?st=pp99u4gs6po6zf8&reflink=article_copyURL_share">Why Gold Bugs, Bond Bears and Amazon Skeptics Think Alike</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/investing'>#Investing</a> <a data-prefetch='true' class='internal-link muted' href='/notes/the-wall-street-journal-wsj'>#The Wall Street Journal (WSJ)</a> <a data-prefetch='true' class='internal-link muted' href='/notes/jason-zweig'>#Jason Zweig</a></p>
<div class="block" id="block-O3AbuF9Nx"><blockquote>
<p>“I’m the kind of person who takes pride in admitting when I’m wrong.”</p>
</blockquote>
</div><div class="block" id="block-dETMswG7U"><p>A good way to think in general.</p>
</div></div><div class="block" id="block-pnx3kagpa"><p><a href="https://www.wsj.com/articles/these-people-who-work-from-home-have-a-secret-they-have-two-jobs-11628866529?st=6gee97xchqdvz04&reflink=article_copyURL_share">These People Who Work From Home Have a Secret: They Have Two Jobs</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/the-wall-street-journal-wsj'>#The Wall Street Journal (WSJ)</a> <a data-prefetch='true' class='internal-link muted' href='/notes/remote-work'>#Remote Work</a></p>
<div class="block" id="block-9DoshXMnA"><p>Give people the option to have flexible work schedules with performance goals, and let them have side projects so they don’t have to lie to you.</p>
</div></div></div><div class="block" id="block-QixIAfFMk"><h2>Apple's New Child-Protection Features</h2><div class="block" id="block-tzfvgNpNK"><p>Background reading/listening:</p>
<ul><li><div class="block" id="block-DTJAnyNjG"><p><a href="https://www.nytimes.com/interactive/2019/09/28/us/child-sex-abuse.html">The Internet Is Overrun With Images of Child Sexual Abuse. What Went Wrong? (NYT)</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/privacy'>#Privacy</a> <a data-prefetch='true' class='internal-link muted' href='/notes/encryption'>#Encryption</a> <a data-prefetch='true' class='internal-link muted' href='/notes/internet'>#Internet</a> <a data-prefetch='true' class='internal-link muted' href='/notes/abuse'>#Abuse</a></p>
</div></li><li><div class="block" id="block-MwpJecI97"><p><a href="https://www.apple.com/child-safety/">Apple’s Announcement: Expanded Protections for Children</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/apple'>#Apple</a> <a data-prefetch='true' class='internal-link muted' href='/notes/privacy'>#Privacy</a> <a data-prefetch='true' class='internal-link muted' href='/notes/encryption'>#Encryption</a> <a data-prefetch='true' class='internal-link muted' href='/notes/internet'>#Internet</a> <a data-prefetch='true' class='internal-link muted' href='/notes/abuse'>#Abuse</a></p>
</div></li><li><div class="block" id="block-zd4u7Nhrv"><p><a href="https://www.wsj.com/articles/apple-child-protection-features-11628861782?st=ohpwve74a988fqa&reflink=article_copyURL_share">Apple’s Child-Protection Features and the Question of Who Controls Our Smartphones (WSJ)</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/the-wall-street-journal-wsj'>#The Wall Street Journal (WSJ)</a> <a data-prefetch='true' class='internal-link muted' href='/notes/apple'>#Apple</a> <a data-prefetch='true' class='internal-link muted' href='/notes/privacy'>#Privacy</a> <a data-prefetch='true' class='internal-link muted' href='/notes/encryption'>#Encryption</a></p>
</div></li><li><div class="block" id="block-gwHwImlAw"><p><a href="https://stratechery.com/2021/apples-mistake/">Apple’s Mistake on Stratechery</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/articles'>#Articles</a> <a data-prefetch='true' class='internal-link muted' href='/notes/apple'>#Apple</a> <a data-prefetch='true' class='internal-link muted' href='/notes/privacy'>#Privacy</a> <a data-prefetch='true' class='internal-link muted' href='/notes/encryption'>#Encryption</a> <a data-prefetch='true' class='internal-link muted' href='/notes/internet'>#Internet</a> <a data-prefetch='true' class='internal-link muted' href='/notes/abuse'>#Abuse</a></p>
</div></li><li><div class="block" id="block-GCKDWkBU1"><p><a href="https://dithering.fm">Apple’s Assumption on Dithering</a> <a data-prefetch='true' class='internal-link muted' href='/notes/links'>#Links</a> <a data-prefetch='true' class='internal-link muted' href='/notes/apple'>#Apple</a> <a data-prefetch='true' class='internal-link muted' href='/notes/privacy'>#Privacy</a> <a data-prefetch='true' class='internal-link muted' href='/notes/encryption'>#Encryption</a> <a data-prefetch='true' class='internal-link muted' href='/notes/internet'>#Internet</a> <a data-prefetch='true' class='internal-link muted' href='/notes/abuse'>#Abuse</a></p>
</div></li></ul></div><div class="block" id="block-S0SqAx14D"><p>A few key points on image detection/reporting:</p>
<ul><li><div class="block" id="block-ba43M6GVL"><p><span class="highlighter"><strong>Detection happens on your device, not in iCloud</strong></span></p>
</div></li><li><div class="block" id="block-d32ng4XJK"><p>Cryptographic hashes of each images are compared with a database of known images only</p>
</div></li><li><div class="block" id="block-oxorn17wE"><p>The <strong>metadata</strong> is uploaded with each photo, and that’s what Apple uses to report potential abuse</p>
</div></li></ul></div><div class="block" id="block-19BeyT6dX"><p>A few key points on new parental controls in Messages:</p>
<ul><li><div class="block" id="block-QuHZuIIvv"><p>Apple uses on-device machine learning to detect nudity</p>
</div></li><li><div class="block" id="block-xUr6iZJ8Z"><p>The user/child is given the option <em>not</em> to look at and/or distribute the image first</p>
</div></li><li><div class="block" id="block-iXGgoAvk6"><p>For accounts of children 12 and under, the parent can be notified if their child decides to proceed</p>
</div></li></ul></div><div class="block" id="block-2httBHUYC"><p>This is one of those incredibly murky issues that do not have clear answers. It’s a tradeoff between protecting children and protecting privacy. Ignoring either enables terrible outcomes—on the one hand by sexual predators, on the other by abusive governments.</p>
</div><div class="block" id="block-Tl98BrMq9"><p><a data-prefetch='true' class='internal-link' href='/notes/ben-thompson'>Ben Thompson</a> of <a data-prefetch='true' class='internal-link' href='/notes/stratechery'>Stratechery</a> thinks that Apple made a mistake in their approach because they violated the assumption that the user owns their device; a better tradeoff would be to scan in iCloud, similar to how Facebook scans images uploaded to their servers.</p>
</div><div class="block" id="block-FTOMEm2a0"><p>As far as I know, <a data-prefetch='true' class='internal-link' href='/notes/facebook'>Facebook</a> cannot scan images in Messenger when end-to-end encryption is enabled since the scanning happens in the cloud—not on the device.</p>
</div><div class="block" id="block-Pvvvo_Qjp"><p><a data-prefetch='true' class='internal-link' href='/notes/ben-thompson'>Ben Thompson</a> and <a data-prefetch='true' class='internal-link' href='/notes/john-gruber'>John Gruber</a> had a good conversation about Apple’s future privacy plans on a recent episode of <a data-prefetch='true' class='internal-link' href='/notes/dithering-podcast'>Dithering (Podcast)</a>. They speculated that Apple’s decision to perform more work on-device (rather than in iCloud) could be laying the groundwork for enabling end-to-end encryption in iCloud in the future. Currently, iCloud backups are <em>not</em> encrypted, making them available to requests from law enforcement.</p>
</div><div class="block" id="block-sWp-YZwBX"><p>I’m glad that <a data-prefetch='true' class='internal-link' href='/notes/apple'>Apple</a> is doing <em>something</em>, and that their solution doesn’t make it easy to get around the new protections by default—like <a data-prefetch='true' class='internal-link' href='/notes/facebook'>Facebook</a>’s encryption option. <a data-prefetch='true' class='internal-link' href='/notes/ben-thompson'>Ben Thompson</a> makes a good point: maybe it would have been better not to compromise the device, and do the scanning in iCloud (which parents could choose to enable).</p>
</div><div class="block" id="block-2Tcvilo4f"><p>There were no rules at the start of the internet, but there were also few users, and the technology itself made it difficult for criminals to hide. It’s not the same place it once was. As in many societal debates, we need to find the right balance between safety and freedom.</p>
</div><div class="block" id="block-ByhRMJh6g"><p>From the kid’s perspective, I’m sure they’ll find creative ways to circumvent any censorship/controls their parents put in place. We don’t have to make it easy, though. Give them a challenge.</p>
</div></div>August 12th, 20212021-08-12T07:00:00+00:002021-08-12T21:21:47+00:00https://www.joshuawood.net/notes/august-12th-2021<div class="block" id="block-gANG5pko-"><p>This is cool, <a data-prefetch='true' class='internal-link' href='/notes/node-js'>Node.js</a> added an experimental <code>--source-map-support</code> flag in 12.12:</p>
<div class="block" id="block-KWZiCenqc"><p><a href="https://github.com/nodejs/node/pull/29564">https://github.com/nodejs/node/pull/29564</a></p>
</div><div class="block" id="block-gbF1Icm_d"><p><a href="https://nodejs.org/dist/latest-v14.x/docs/api/cli.html#cli_enable_source_maps">https://nodejs.org/dist/latest-v14.x/docs/api/cli.html#cli_enable_source_maps</a></p>
</div><div class="block" id="block-dC_I2lzDx"><p>The stack traces were a bit wonky, though—the “->” prefix is not supported by most stack trace parsers (including Honeybadger).</p>
<div class="block" id="block-gWXny1WAz"><pre><code class="language-plain">>Error: oops, something went wrong
at AppService.getHello (/Users/josh/tmp/test-node-app/dist/main.js:100:15)
-> /Users/josh/tmp/test-node-app/dist/webpack:/test-node-app/src/app.service.ts:6:11
at AppController.getHello (/Users/josh/tmp/test-node-app/dist/main.js:68:32)
-> /Users/josh/tmp/test-node-app/dist/webpack:/test-node-app/src/app.controller.ts:10:28
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-execution-context.js:38:29
at InterceptorsConsumer.intercept (/Users/josh/tmp/test-node-app/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:11:20)
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-execution-context.js:46:60
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-proxy.js:9:23
</code></pre></div></div><div class="block" id="block--CRNJg1Hi"><p>That’s fixed in Node 14+, so the stack traces are supported everywhere.</p>
<div class="block" id="block-HbPRUIi5Q"><pre><code class="language-plain">>Error: oops, something went wrong
at AppService.getHello (webpack://test-node-app/src/app.service.ts:6:11)
at AppController.getHello (webpack://test-node-app/src/app.controller.ts:10:28)
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-execution-context.js:38:29
at InterceptorsConsumer.intercept (/Users/josh/tmp/test-node-app/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:11:20)
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-execution-context.js:46:60
at /Users/josh/tmp/test-node-app/node_modules/@nestjs/core/router/router-proxy.js:9:23
</code></pre></div></div></div><div class="block" id="block-lUTTo9r3_"><p><a data-prefetch='true' class='internal-link' href='/notes/node-js'>Node.js</a> projects in <a data-prefetch='true' class='internal-link' href='/notes/honeybadger'>Honeybadger</a> can now officially take advantage of source maps, just like Client-Side <a data-prefetch='true' class='internal-link' href='/notes/javascript'>JavaScript</a> projects can! <a href="https://www.honeybadger.io/blog/server-side-source-maps/">See my blog post on the Honeybadger Developer Blog</a></p>
</div>July 4th, 20212021-07-04T07:00:00+00:002021-07-04T21:53:14+00:00https://www.joshuawood.net/notes/july-4th-2021<div class="block" id="block-RmSviL8Bv"><p>“America is false to the past, false to the present, and solemnly binds herself to be false to the future.” —<a data-prefetch='true' class='internal-link' href='/notes/frederick-douglas'>Frederick Douglas</a> <a data-prefetch='true' class='internal-link muted' href='/notes/quotes'>#Quotes</a></p>
<div class="block" id="block-SrZAE4u4B"><p>Celebrate progress, and don’t be false. Happy 4th.</p>
</div><div class="block" id="block-wQX5L69xj"><p><a href="https://teachingamericanhistory.org/library/document/what-to-the-slave-is-the-fourth-of-july/">“What to the Slave Is the Fourth of July?”</a></p>
</div></div>June 28th, 20212021-06-28T07:00:00+00:002021-06-28T21:20:57+00:00https://www.joshuawood.net/notes/june-28th-2021<div class="block" id="block-2sVboU7ez"><p>Record PNW heatwave. High of 115 today.</p>
</div><div class="block" id="block-q1igKoAP9"><p>Redfin is aggressively trying to sell me a house. I hope it’s not working.</p>
</div><div class="block" id="block-tSKpyDBa_"><p>On the bright side, my garage gym is now a hot yoga studio.</p>
<div class="block" id="block-SGE-uQ7ik"><p>They say entrepreneurs are often irrational optimists.</p>
</div></div>June 27th, 20212021-06-27T07:00:00+00:002021-06-27T16:42:58+00:00https://www.joshuawood.net/notes/june-27th-2021<div class="block" id="block-V655jdhKy"><h2>Outliner wishlist for blogging</h2><div class="block" id="block-y5Osf4IpP"><p>Here are some things I wish my outliner could do for an optimal blogging setup.</p>
</div><div class="block" id="block-x2TDe3BFD"><h3>Custom block types</h3><div class="block" id="block-loFyapBx4"><p>Roam gives you a few ways to view sub-elements: document, bulleted list, numbered list. I wish I could customize these/create additional types. Each type would have a custom stylesheet/template for display in the outliner, and associated attribute(s) in data exports (i.e. OPML, JSON, etc.).</p>
</div><div class="block" id="block-JbWP8TDl_"><p>This feature reminds me of early content management systems (which often had a single content/page type) and their successors—such as <a href="https://expressionengine.com">Expression Engine</a>—which let you create custom content types. It opened up a lot of possibilities.</p>
</div><div class="block" id="block-TuD96uK2e"><p>The key is that I want the ease of editing content in an outliner such as Roam, but greater flexibility when displaying it. The better the content in the outliner imitates the published display format, the less I have to think about formatting.</p>
</div><div class="block" id="block-WffTZtyqp"><p>In the meantime, I wish Roam would actually include all of the display type metadata in JSON exports… (Currently it does not include the document display type.)</p>
</div></div><div class="block" id="block-cH11hMBDN"><h3>Live preview</h3><div class="block" id="block-0wPwvewow"><p>Imagine being able to see a live preview of content (sort of like markdown preview) in a right-sidebar.</p>
</div></div><div class="block" id="block-DHiESg3jv"><h3>Every block has a unique id</h3><div class="block" id="block-IoK-ukzsU"><p>Roam has block refs, and they’re super handy since each element can have a true permalink. An alternative approach is to use the timestamp of when the block was created (maybe with millisecond precision)—however you would still have to store this with each block, which isn’t really practical if using markdown as the storage format.</p>
</div></div></div>June 26th, 20212021-06-26T07:00:00+00:002021-06-26T20:30:36+00:00https://www.joshuawood.net/notes/june-26th-2021<div class="block" id="block-aSmFA2ID9"><p>Checking out <a href="https://www.polywork.com/joshuap">PolyworkHQ</a>. Added a few recent and not-so-recent work highlights so far. Follow me if ya want!</p>
</div>