<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Stephen Sisk</title>
    <description>The latest articles on Forem by Stephen Sisk (@stephensisk).</description>
    <link>https://forem.com/stephensisk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F670356%2F22d72617-c5e3-4bc2-9413-1646d19b36a2.jpg</url>
      <title>Forem: Stephen Sisk</title>
      <link>https://forem.com/stephensisk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stephensisk"/>
    <language>en</language>
    <item>
      <title>Throwaway email blocklists want to block Firefox Relay: Here's an alternative</title>
      <dc:creator>Stephen Sisk</dc:creator>
      <pubDate>Fri, 21 Jan 2022 02:58:00 +0000</pubDate>
      <link>https://forem.com/stephensisk/throwaway-email-blocklists-want-to-block-firefox-relay-heres-an-alternative-470f</link>
      <guid>https://forem.com/stephensisk/throwaway-email-blocklists-want-to-block-firefox-relay-heres-an-alternative-470f</guid>
      <description>&lt;p&gt;&lt;em&gt;TLDR: I propose a way for email masking services like Firefox Relay, ThxNoThx or iCloud Hide My Email to help out services that need to uniquely identify users, without compromising user privacy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Disclosure: I am the founder of &lt;a href="https://www.thxnothx.com"&gt;ThxNoThx&lt;/a&gt;, an alternative email masking service (obligatory marketing pitch: with advanced features like distraction free newsletter reading, one click unsubscribe from the inbox, and using addresses in your existing domain names)&lt;/p&gt;

&lt;p&gt;This post is a response to &lt;a href="https://github.com/disposable-email-domains/disposable-email-domains/pull/298"&gt;https://github.com/disposable-email-domains/disposable-email-domains/pull/298&lt;/a&gt; since they have (probably wisely :) locked down comments. They propose adding Firefox Relay domains to their blocklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Throwaway email services allow users to generate new email addresses at will. They are often used when someone doesn't want to give a real email address to a website. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/disposable-email-domains/disposable-email-domains"&gt;disposable-email-domains&lt;/a&gt; is one such list of throwaway email domains. It is used by SaaS services to prevent customers from using a throwaway email address when registering.&lt;/p&gt;

&lt;p&gt;It was recently proposed that Firefox Relay be added to the list of blocked domains. &lt;/p&gt;

&lt;p&gt;Email masking services like iCloud Hide My Email and Firefox Relay (and ThxNoThx!) are different from throwaway email services since they allow continued communication with the user, usually by forwarding emails on to the user's inbox.&lt;/p&gt;

&lt;p&gt;In my last job I did work around account management at a site targeted by cryptominers (views expressed in this post are my own), and in my experience it's trivially easy for disposable email address providers to simply create new domain names. I just tried it: search for "burner email address" -&amp;gt; click the first link -&amp;gt; look at the generated email address (reamtv.com) and... it's not in the blocklist at disposable-email-domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should the goals of a solution be?
&lt;/h2&gt;

&lt;p&gt;Services using domain blocklists need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A way to uniquely identify users&lt;/strong&gt; - for example, a user should only get one free trial. Email address is often used for this purpose, but it is not perfect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An open channel of communication with their users&lt;/strong&gt; for marketing and transactional purposes. For example they need to contact you if there's a problem with an order or because they think you'd like a new feature they've added. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users of email masking services need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt; - a random artisanal soap company on the internet does not need to have my real email address. I shouldn't have to trust they won't get hacked and leak my address or that they won't sell it to other companies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control over their inbox&lt;/strong&gt; - unsubscribe links in emails are great, but they ultimately rely on company's willingness to allow users to unsubscribe (in some places this is legally mandated, but it is an imperfect system)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe email masking services represent a good middle ground: businesses get an email address that is permanent and can reach the user when they need to, and if the user finds their marketing material helpful, they can keep their email address active.&lt;/p&gt;

&lt;p&gt;However, email masking services also make it easy for users to generate multiple addresses, meaning that email addresses will be less useful for uniquely identifying users in the future. &lt;/p&gt;

&lt;h2&gt;
  
  
  Proposed Solution
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Companies should be able to ask email masking services if the user behind an email address at an email masking service has previously registered with their company&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The company that wants to know if a user has previously registered can send a query with the following info: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A secret&lt;/strong&gt; that is known only to the company, used in each and every query from that company (eg '123abcMySaasIsAwesome') &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The email address&lt;/strong&gt; of the user that's trying to register&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A queryId&lt;/strong&gt; - this can be used if there is a failure in communication and the same query needs to be sent again. This makes the query idempotent (the masking service stores the queryId of the first request of the user + service combo, thus preventing a false positive if a request needs to be resubmitted)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The email masking service simply replies with true/false that the user behind that email address has previously registered with the company identified by the secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  An example
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A user (Mary) goes to register for a Saas service (FeelingSaasy.com), and during account creation, she submits her email address as &lt;a href="mailto:anon123@mary.thxnothx.com"&gt;anon123@mary.thxnothx.com&lt;/a&gt; (ThxNoThx users can use any email address under @{username}.thxnothx.com)&lt;/li&gt;
&lt;li&gt;FeelingSaasy sends the ThxNoThx the email address and a secret only known by FeelingSaasy in a request to ThxNoThx, asking if the user behind that email address has registered with the service behind that secret (FeelingSaasy). This would presumably be done via a simple HTTP request&lt;/li&gt;
&lt;li&gt;The email masking service would respond to the request with true/false - from that, FeelingSaasy can decide whether or not to allow the request from the user.&lt;/li&gt;
&lt;li&gt;Potentially the email masking service could inform the user of this request, as well as provide the user with the previous email address used. This might be helpful in "I forgot my login credentials" type situations as well as provide transparency to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some interesting aspects of this solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FeelingSaasy.com never knows which previous email address was used - they only know that the user behind an email address has previously registered. (Currently Firefox Relay and ThxNoThx addresses can contain the username of the user in the domain name - and thus email addresses from the same user can be identified that way - but that may change in the future.)&lt;/li&gt;
&lt;li&gt;The email masking service does not know the identity of the company - the secret should just be a random string known only to the company &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Opportunities
&lt;/h2&gt;

&lt;p&gt;I would argue that email relay services solve the problem of uniquely identifying users better than existing solution because &lt;em&gt;a user paid money to the email masking service.&lt;/em&gt; That raises the costs of switching between services or creating new accounts with the masking service.  &lt;/p&gt;

&lt;p&gt;We would notably still have a role for the blocklist to play: we need to know what domains support the unique user identification service.&lt;/p&gt;

&lt;p&gt;We all benefit if the internet has a bit more privacy than it does today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;This does represent more work for services to integrate with, however I believe it can be implemented via a single API call. &lt;/p&gt;

&lt;p&gt;This is also work for the masking service: they need to have a service that responds to this request, but it's a fairly simple lookup easily supported by regular db indexes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attacks/Problems
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A masking service decides to return bad results:&lt;/strong&gt; (eg. falsely say no one has ever previously registered): This should be easily detectable by the other side, since they could simply create an account themselves and do a check (you'd only need a few folks in the eco system doing this to ensure good results). The possible response to this behavior (if/when detected) would be to add them to the proper blocklist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A site with large # of calls to check identities at the email masking service&lt;/strong&gt;:  The service's secret would be a pretty good way to do rate limiting. If the email masking service needed to get the attention of the calling site, they could start returning 500s with a message :)&lt;/p&gt;

&lt;p&gt;DDoS attacks and "someone stole our secret" both are issues, but those are always issues? I don't think the proposed service is any more vulnerable to those attacks than any other service on the internet. &lt;/p&gt;

&lt;p&gt;I'm sure I'm missing something - please reach out as discussed below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;If you're interested in discussing this further, please contact me at {myfirstname}@sunnyporch.dev, &lt;a class="mentioned-user" href="https://dev.to/stephensisk"&gt;@stephensisk&lt;/a&gt; on twitter or by replying to this post.&lt;/p&gt;

&lt;p&gt;Some things we'd need to do to make this real:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Someone needs to provide a spec for the request/response,  and a canonical implementation (perhaps with a basic test suite to show compliance)&lt;/li&gt;
&lt;li&gt;Email masking service providers: implement this request and provide the URL to domain blocklists.&lt;/li&gt;
&lt;li&gt;Domain blocklists: provide a list of domains that support this, and the URL of the endpoint&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any service is interested in using this I'd be excited to work on this from the email masking service side.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>firefox</category>
      <category>healthydebate</category>
    </item>
    <item>
      <title>I'm building a modern spreadsheet</title>
      <dc:creator>Stephen Sisk</dc:creator>
      <pubDate>Fri, 27 Aug 2021 15:40:53 +0000</pubDate>
      <link>https://forem.com/stephensisk/i-m-building-a-modern-spreadsheet-2l66</link>
      <guid>https://forem.com/stephensisk/i-m-building-a-modern-spreadsheet-2l66</guid>
      <description>&lt;p&gt;I like spreadsheets. &lt;/p&gt;

&lt;p&gt;As a programmer, I find the simple UI and immediately propagating updates to be powerful and refreshing. Considering that it was invented &lt;em&gt;over 40 years ago&lt;/em&gt; it's truly an achievement that the core concept is relevant today. &lt;/p&gt;

&lt;p&gt;But I also look at the UI and see something that hasn't changed much from the days of VisiCalc.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled.png"&gt;

*VisiCalc, circa 1978*
&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2F%2Fimages%2FUntitled%25201.png"&gt;

*Spreadsheet, circa 2021*
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We moved away from neon blue towards grey and discovered non-monospaced fonts! 😉&lt;/p&gt;

&lt;p&gt;What should spreadsheets look like without baggage from the past? Not designed by a human primarily used to working by writing on a chalkboard or paper, but someone from the far future.... 2021!&lt;/p&gt;

&lt;h1&gt;
  
  
  The traditional spreadsheet UI is a liability
&lt;/h1&gt;

&lt;p&gt;Mistakes caused by spreadsheets have unfortunately grown alongside spreadsheets. It's hard to overstate that, given that the EU has a &lt;a href="http://www.eusprig.org/" rel="noopener noreferrer"&gt;special interest group&lt;/a&gt; devoted to discussing and reducing the risk from spreadsheets, and I think the scope of the problem warrants a look at contributing factors of those errors and ways to reduce them. &lt;/p&gt;

&lt;p&gt;The changes I outline below were originally just a way to scratch my itch as a programmer for a spreadsheet tool that combined the simplicity of spreadsheets with the powerful tools I use every day as a software engineer, but I realized that some of the changes I wanted were the result of lessons in avoiding programming errors that the software industry as a whole has had to learn.&lt;/p&gt;

&lt;p&gt;We must continually ask if the software we use every day for critical tasks can be improved - my assertion that when it comes to spreadsheets, the answer is yes. &lt;/p&gt;

&lt;h1&gt;
  
  
  Let's start with equations and basic math
&lt;/h1&gt;

&lt;p&gt;Let's look at a simple spreadsheet equation:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;B2-B1&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;What does this mean? Should we have used B3 instead of B2? Should it have been &lt;code&gt;B1-B2&lt;/code&gt; instead? These are unanswerable questions without manually checking the other cells in the spreadsheet. &lt;/p&gt;

&lt;p&gt;What if instead you could write:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;profit=income-expenses&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;🤯&lt;/p&gt;

&lt;p&gt;Variable names in a spreadsheet! &lt;em&gt;[1]&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;So how can we get this magical world where we get to use variables naturally in spreadsheets?&lt;/p&gt;

&lt;p&gt;Let's look at a simple spreadsheet:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25203.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25203.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the spreadsheet already has labels we could use for variable names, but the spreadsheet doesn't realize there's a connection, and figuring out there's a connection would be tricky and error prone.&lt;/p&gt;

&lt;p&gt;Instead, we could think about formalizing it, and let each cell have a label and a value. That makes a lot of sense! However, there's a reason existing spreadsheets haven't done that, and it's called.. &lt;em&gt;the grid&lt;/em&gt;. The grid layout is flexible and makes creating ad hoc tables easy, but anything can go anywhere, which makes it hard to guess what's a label and what's a value.&lt;/p&gt;

&lt;p&gt;So let's talk about a design that lets us bake labels and values in from the start.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25204.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25204.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we still have cells (one label/value pair), and we line them up vertically. Users can create new cells below existing ones. And we can use those labels as variable names. &lt;/p&gt;

&lt;p&gt;This lends itself more to being a document rather than a traditional grid. We can allow users to type in their labels and values and use &lt;code&gt;=&lt;/code&gt; as a natural delimiter to separate the two. This usage of  &lt;code&gt;=&lt;/code&gt; flows naturally from existing spreadsheet formulas.&lt;/p&gt;

&lt;p&gt;Let's see it in action!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2Fbasic_doc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2Fbasic_doc.gif" alt="basic_doc.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think this design works pretty well. And everything doesn't have to be a single column - a newspaper style layout, with multiple columns would allow for using the full screen just like a regular spreadsheet. Larger items like charts could span multiple columns.&lt;/p&gt;

&lt;p&gt;For mobile, the layout lends itself well to flowing and adapting to a compressed layout, resulting in something like:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25205.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25205.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So a vertical layout incorporating labels and cells gives us the power of variable naming without needing to give up on the nice layout of the grid. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further thoughts:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can easily autogenerate a name (eg. cell1, A1, etc) if the user doesn't want to enter a label.&lt;/li&gt;
&lt;li&gt;Autocomplete with variable names would make this very user friendly&lt;/li&gt;
&lt;li&gt;This UI can be made more user friendly by providing a menu/toolbox of items that can be added to the worksheet (calculations/tables/etc) - this means users don't need to memorize a list of commands.&lt;/li&gt;
&lt;li&gt;I didn't discuss user defined functions/higher order functions, but they are definitely on the road map.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;[1] I hear someone in the back yelling "Spreadsheets do support naming cells!", but... you'll need to go in and manually name the cell a second time - and if the label text changes, the variable name of the cell doesn't change. Also, I'll bet half the folks reading this didn't even realize this functionality existed, and if they do, they don't use it most of the time. I also hear that one other guy waaay in the back yelling that A1 is still a variable name.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  But what about tables?
&lt;/h1&gt;

&lt;p&gt;"The grid is perfect for tables!" I hear you saying. "It is nothing but a table".&lt;/p&gt;

&lt;p&gt;But when you want to have columns with uniform calculations it's a bit of a pain to copy the formula into each one, and of course who doesn't love formatting a spreadsheet table for the umpteenth time? &lt;em&gt;[2]&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Let's take a look at what a calculation table could look like in our new worksheet format:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25206.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25206.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a design sketch and it needs more work. But the core idea is that you simply state that you want a table by entering &lt;code&gt;TABLE&lt;/code&gt; and it pops up a simple table creator. The first and second rows define the initial value and formula for the column. You can see the usage of the &lt;code&gt;prev&lt;/code&gt; keyword to get values from the previous row.&lt;/p&gt;

&lt;p&gt;You'll note that since the app knows it's a table, it's able to nicely format the table header and properly align the contents without any actions by the user. &lt;/p&gt;

&lt;p&gt;Note that once the app knows it's a calculated table, you don't need to show the entire table - the user can expand it to see more or less of the table as they see fit, and the document will naturally flow around it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[2] Yup, I'm aware Excel has formal table support - I bet even fewer folks know about it and use it regularly than named cells. And google sheets support &lt;a href="https://www.benlcollins.com/spreadsheets/how-to-make-a-table-in-google-sheets/" rel="noopener noreferrer"&gt;is&lt;/a&gt; &lt;a href="https://hooshmand.net/tables-in-google-sheets/" rel="noopener noreferrer"&gt;abysmal&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Data Tables &amp;amp; Manipulation
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;or: I just want to use SQL instead of trying to figure out what "values" in a pivot table means&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The last section ignored a big way we use spreadsheet tables: user entered data tables (eg. "spreadsheet as a makeshift database"). I think it'd easy to create that: it'd be as easy as detecting that the user doesn't add a formula as the contents of the cell on the second row. &lt;/p&gt;

&lt;p&gt;Once you have data tables, how are you going to process that data? &lt;/p&gt;

&lt;p&gt;When I'm coding, I love using functions like Map/Reduce/Filter to manipulate and produce new tables of data (those are equivalent to SQL's SELECT, WHERE, GROUP BY, etc.. if you're more familiar with those), and I'd love to have that functionality available in spreadsheets.&lt;/p&gt;

&lt;p&gt;This is another place where the grid becomes problematic. All of those functions output &lt;em&gt;another table&lt;/em&gt;, and you need to put that output table somewhere. Thus, they force you to make a compromise on how to display your output. Are you going to stick it all inside one cell where you can't see it? "Spill" the table out across multiple cells? Hope you don't have any data around the cell doing the calculation that get overwritten! (or overwritten later if the size of the output changes). &lt;/p&gt;

&lt;p&gt;This is where our new layout really shines. We can just have one cell per operation and output a new table each time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further thoughts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We also don't have to keep user entered data and calculations in separate tables - you can just do it on a column by column basis (some columns in a table can define a calculation, others can contain user entered data).&lt;/li&gt;
&lt;li&gt;Having an easy way to add CSV files, other sources of data from the web, and other worksheets sure seems useful&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Units
&lt;/h1&gt;

&lt;p&gt;I'm just going to show an example worksheet here, because I think it's pretty self-explanatory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25207.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25207.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now the app understands that&lt;code&gt;$&lt;/code&gt; is a unit that should be carried through to other values - we didn't have to special that total_income was a dollar, it just inherited that unit from the values it read fro.&lt;/p&gt;

&lt;p&gt;The _ symbol is ignored in numbers and is useful for making numbers more readable without interfering with function calls*[3].* &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25208.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25208.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... and now that we know it's currency, we can do smart things with the decimals. The "correct" result for &lt;code&gt;7/2&lt;/code&gt; is 3.5, but we know to format it with 2 decimal places because it's currency. We didn't need to change any formatting settings - it just knows to display with 2 decimal places for currency if there's any at all.  You will also note that above in the other_cost_two example, we didn't need to tell it not to display the cents, it could pick up from context that we didn't need to display decimals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25209.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%25209.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Percents work with their own special rules, knowing that the $ unit should carry through to take_home_income, and that 15% is actually .0015 when multiplying.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252010.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252010.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... and we can support other types of units, like distances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252011.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252011.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You didn't think I'd forget SI symbols, did you?&lt;/p&gt;

&lt;p&gt;I think adding units to spreadsheets is exciting, if only for the reason that it reduces the amount of formatting that needs to be manually done by the user.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[3] Function calls + using comma separators in numbers results in chaos. What numbers are being passed to this function? &lt;code&gt;max(100,000, 2, 000)&lt;/code&gt; ? You can interpret that by using spaces, but it's a bit iffy. Using the _ symbol as a separator is a convention becoming popular in programming languages for solving this problem. _ is also culture agnostic, so europeans (number format: 2.000,00) and americans (number format: 2,000.00) can finally get along.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Scenarios
&lt;/h1&gt;

&lt;p&gt;While I like using spreadsheets for all kinds of calculations, my personal biggest use case is for investment/retirement planning. &lt;/p&gt;

&lt;p&gt;And in that world, being able to explore different scenarios is pretty important. So let's see how we can explore scenarios with worksheets.&lt;/p&gt;

&lt;p&gt;Here's an example of a plain old savings worksheet in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252012.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252012.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;savings_at_retirement&lt;/code&gt; uses a notation I'm not in love with: &lt;code&gt;tableName.column[row]&lt;/code&gt;, but I think this communicates the idea pretty clearly: You can read individual cell values out of a table. (I'll probably move to &lt;code&gt;tableName[column][row]&lt;/code&gt; since that seems much cleaner)&lt;/p&gt;

&lt;p&gt;Now, if we wanted to experiment with various savings plans, we could manually change the savings_rate, income, stock_rate_of_return, etc... But why not allow for easy scenario exploration with multiple values?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This UI is definitely a work in progress.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252013.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252013.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we introduce the &lt;code&gt;VARY&lt;/code&gt; keyword in &lt;code&gt;stock_rate_of_return&lt;/code&gt;, which allows that variable to have multiple values and causes any values downstream of it to produce multiple outputs, one for each of the values. &lt;/p&gt;

&lt;p&gt;Introducing the VARY had two downstream effects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Next/Prev controls on &lt;code&gt;savings_over_time&lt;/code&gt; allow you to switch through the various values of &lt;code&gt;stock_rate_of_return&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;You can also see that there's a nice roll up in &lt;code&gt;savings_at_retirement&lt;/code&gt; showing the end result of savings for each of the values of &lt;code&gt;stock_rate_of_return&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But why are we restricting ourselves to one variable at a time? Here I show 3 different VARYs working at once:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252014.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstephensisk.net%2Fimages%2FUntitled%252014.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll note that both &lt;code&gt;savings_over_time&lt;/code&gt; and &lt;code&gt;savings_over_retirement&lt;/code&gt; are updated to show the new values of the &lt;code&gt;VARY&lt;/code&gt;s&lt;/p&gt;

&lt;p&gt;...and of course if you change the values of VARY, everything will instantly update.&lt;/p&gt;

&lt;p&gt;I think this is a very natural but powerful way to express different scenarios, and a simple tool for explore those scenarios.&lt;/p&gt;

&lt;h1&gt;
  
  
  Feedback, please!
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Would you like to see more? &lt;a href="https://qrunch.studio" rel="noopener noreferrer"&gt;Sign up for the beta waitlist&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://buttondown.email/runthenumbers" rel="noopener noreferrer"&gt;Subscribe to my dev diary newsletter&lt;/a&gt; if you'd like to get ~weekly updates on the nitty gritty of my development work, or follow me here on DEV.TO &lt;/p&gt;

&lt;p&gt;I'd love to hear your feedback: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/stephensisk" rel="noopener noreferrer"&gt;Follow me on twitter&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Email: stephen [at] qrunch [dot] studio&lt;/p&gt;

</description>
      <category>sql</category>
      <category>tooling</category>
      <category>spreadsheet</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
