From 24f459e046c0c05c4be4228bb9f43727cfc55127 Mon Sep 17 00:00:00 2001 From: Spelkington Date: Fri, 8 Mar 2024 19:26:27 +0000 Subject: [PATCH] deploy: da61475be5e043986786d49b3d5dfbb28bb608fa --- index.xml | 80 ++++++++++++++--------------- notes/strong-and-weak-opinions.html | 2 +- sitemap.xml | 36 ++++++------- static/contentIndex.json | 2 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/index.xml b/index.xml index b9f56fbd..a25e9e28 100644 --- a/index.xml +++ b/index.xml @@ -6,65 +6,65 @@ Last 10 notes on Chaotic Good Computing Quartz -- quartz.jzhao.xyz - Contact Chaotic Good Computing - https://blog.chaoticgood.computer/contact - https://blog.chaoticgood.computer/contact - - Fri, 08 Mar 2024 19:18:17 GMT - - Oh, Howdy! - https://blog.chaoticgood.computer/ - https://blog.chaoticgood.computer/ - Chaotic Good Computing is an organization specializing in providing advice and assistance for small companies around: Software Engineering Data Analysis & Handling Economic Analysis CGC’s general specialty is engineering, analysis, insights, and maintenance of digital economies like multiplayer game economies, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications. - Fri, 08 Mar 2024 19:18:17 GMT - - Daily Notes - https://blog.chaoticgood.computer/notes/dailies/ - https://blog.chaoticgood.computer/notes/dailies/ - These are daily notes, where I log and track progress on ongoing projects and make notes for myself later. These are largely for my own benefit, and are here in case they’re helpful to myself (or, somehow, others) in the future. - Fri, 08 Mar 2024 19:18:17 GMT - - What is a Digital Economy? - https://blog.chaoticgood.computer/notes/digital-economies - https://blog.chaoticgood.computer/notes/digital-economies - Digital economies are primarily-online economies that you might find in multiplayer games, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications. - Fri, 08 Mar 2024 19:18:17 GMT - - Notes - https://blog.chaoticgood.computer/notes/ - https://blog.chaoticgood.computer/notes/ - These are notes - they’re things that are structured, albeit not necessarily as structured or refined as CGC articles. In general, there are three kinds of notes I make: General notes, which are found on this page Daily Notes, which contain daily logs for my own benefit Scratch Notes, which really just means “none of the above” . - Fri, 08 Mar 2024 19:18:17 GMT - - Scratch Notes - https://blog.chaoticgood.computer/notes/scratch/ - https://blog.chaoticgood.computer/notes/scratch/ - For all intents and purposes, these are the digital gardening equivalent of shitposts and shower thoughts. - Fri, 08 Mar 2024 19:18:17 GMT - C\# https://blog.chaoticgood.computer/tags/csharp https://blog.chaoticgood.computer/tags/csharp - Fri, 08 Mar 2024 19:18:17 GMT + Fri, 08 Mar 2024 19:26:03 GMT Doodles, a.k.a. Minimally Professional Presentations https://blog.chaoticgood.computer/tags/doodles https://blog.chaoticgood.computer/tags/doodles - Fri, 08 Mar 2024 19:18:17 GMT + Fri, 08 Mar 2024 19:26:03 GMT Economics https://blog.chaoticgood.computer/tags/economics https://blog.chaoticgood.computer/tags/economics - Fri, 08 Mar 2024 19:18:17 GMT + Fri, 08 Mar 2024 19:26:03 GMT engineering https://blog.chaoticgood.computer/tags/engineering https://blog.chaoticgood.computer/tags/engineering - Fri, 08 Mar 2024 19:18:17 GMT + Fri, 08 Mar 2024 19:26:03 GMT + + Gremlin Kicking (a.k.a Productivity) + https://blog.chaoticgood.computer/tags/gremlin-kicking + https://blog.chaoticgood.computer/tags/gremlin-kicking + Gremlin kicking is a somewhat underhanded term for productivity habits and tools. + Fri, 08 Mar 2024 19:26:03 GMT + + Digital Gardening, and Horticulture as Research + https://blog.chaoticgood.computer/tags/horticulture + https://blog.chaoticgood.computer/tags/horticulture + As a logical consequence of taking a digital gardening approach to writing, the horticulture tag will be used to catalog thoughts related to digital gardening and general research. + Fri, 08 Mar 2024 19:26:03 GMT + + CGC Mentoring + https://blog.chaoticgood.computer/tags/mentoring + https://blog.chaoticgood.computer/tags/mentoring + + Fri, 08 Mar 2024 19:26:03 GMT + + Python + https://blog.chaoticgood.computer/tags/python + https://blog.chaoticgood.computer/tags/python + + Fri, 08 Mar 2024 19:26:03 GMT + + Roblox + https://blog.chaoticgood.computer/tags/roblox + https://blog.chaoticgood.computer/tags/roblox + + Fri, 08 Mar 2024 19:26:03 GMT + + Data Visualizations & Presentations + https://blog.chaoticgood.computer/tags/visualizations + https://blog.chaoticgood.computer/tags/visualizations + + Fri, 08 Mar 2024 19:26:03 GMT \ No newline at end of file diff --git a/notes/strong-and-weak-opinions.html b/notes/strong-and-weak-opinions.html index 5083dd32..409064f1 100644 --- a/notes/strong-and-weak-opinions.html +++ b/notes/strong-and-weak-opinions.html @@ -26,7 +26,7 @@

Opinionated Softwareblack python formatter while wrangling Databricks codebases at M Science diff --git a/sitemap.xml b/sitemap.xml index 4b22de01..2dda213d 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1,6 +1,6 @@ https://blog.chaoticgood.computer/about - 2024-03-08T19:18:17.319Z + 2024-03-08T19:26:03.162Z https://blog.chaoticgood.computer/articles/binglish 2024-03-01T00:00:00.000Z @@ -9,7 +9,7 @@ 2021-07-28T00:00:00.000Z https://blog.chaoticgood.computer/articles/ - 2024-03-08T19:18:17.319Z + 2024-03-08T19:26:03.162Z https://blog.chaoticgood.computer/articles/littlefield 2021-08-28T00:00:00.000Z @@ -24,10 +24,10 @@ 2022-07-14T00:00:00.000Z https://blog.chaoticgood.computer/contact - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/ - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/notes/arc-review 2024-02-28T00:00:00.000Z @@ -78,16 +78,16 @@ 2024-03-08T00:00:00.000Z https://blog.chaoticgood.computer/notes/dailies/ - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/notes/digital-economies - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/notes/digital-gardening-with-quartz 2024-02-25T00:00:00.000Z https://blog.chaoticgood.computer/notes/ - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/notes/literal-scratch-piano 2018-07-18T00:00:00.000Z @@ -114,7 +114,7 @@ 2024-03-01T00:00:00.000Z https://blog.chaoticgood.computer/notes/scratch/ - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.314Z https://blog.chaoticgood.computer/notes/scratch/press-f-to-commit 2024-02-28T00:00:00.000Z @@ -153,32 +153,32 @@ 2021-03-01T00:00:00.000Z https://blog.chaoticgood.computer/tags/csharp - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/doodles - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/economics - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/engineering - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/gremlin-kicking - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/horticulture - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/mentoring - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/python - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/roblox - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z https://blog.chaoticgood.computer/tags/visualizations - 2024-03-08T19:18:17.471Z + 2024-03-08T19:26:03.318Z \ No newline at end of file diff --git a/static/contentIndex.json b/static/contentIndex.json index 6159bfd4..08029478 100644 --- a/static/contentIndex.json +++ b/static/contentIndex.json @@ -1 +1 @@ -{"about":{"title":"About Chaotic Good Computing","links":[],"tags":[],"content":""},"articles/binglish":{"title":"Binglish as a Dead Language (BaaDL)","links":["articles/structured-streaming","articles/robloxaville","notes/digital-gardening-with-quartz","notes/the-quest-to-kick-the-gremlin"],"tags":["economics","horticulture"],"content":"Binglish\n\nbing·lish, noun (derogatory)\n\nThe default writing style of generative AI text models. (derogatory)\nShorthand for a median style of writing, devoid of personality. (derogatory)\nThe way that a monkey’s paw would grant Microsoft’s wish to finally give Bing a generic English term like lowercase-g “google” (very derogatory)\n\n\nIn writing a bit more, I’ve been back-and-forth on the extent to which I want to swear. The style of my writing is more-or-less the way that I speak out loud (which prompted a lot of “couldn’t you make this a bit more professional?” feedback on the Databricks post), and when I speak out loud, I swear. Obviously, the frequency depends - at work it’s sparse (but not nil), on a personal level it’s pretty frequent - but I do still pepper it in for effect in some places. The only times I can remember not swearing is when I was teaching math to K-12 students, and when writing posts here.\nThis feels somewhat… internally dissonant? personally disingenuous? If, when I speak I swear, and I tend to write like I speak, why wouldn’t I also swear in my writing? The answer in the past has been professionalism. It feels unbecoming of a (relatively) young professional to swear in a professional context, and some of what I write here overlaps with what I do for work.\nToning down my writing has been, so far, a fairly active effort. I’ve occasionally even gone as far as writing with swears and then, after-the-fact, explicitly (ha!) searching for illicit words and removing them as I see them. This was probably most apparent when writing the Robloxaville recap article - it mentions a lot of my (very) early work history and, at the time, I thought that potential employers (or youths) might come across it, warranting a touch-up.\nThe world has changed quite a bit since ye olde 2021. I am (slightly) more established in my career, and the context of written documentation has changed quite a bit as technology has advanced. This has made me reconsider my previous policy of toning down my writing. In the process of porting over & more frequently updating this blog, I’ve made an executive decision for the foreseeable future: I’m going to be swearing a bit more.\nOr, at the very least, I’m going to be taking a dramatically less formal approach to writing and editing, here. The spur of this decision:\nThe Bots Are Coming Have Arrived\nI don’t think that, ten years ago, anybody expected that the next dramatic economic shift would’ve been generative AI - specifically text-based AI - putting white-collar workers at the highest risk of automation. An example that comes readily to mind is the CGPGrey video Humans Need Not Apply, in which self-driving cars were offered up as the most readily-apparent example of economic risk of automation. This feels slightly silly with the benefit of hindsight - having started my engineering studies at around the same time though, it’s easy to forget how high-profile advances in self-driving were (at the time). It has become wildly, obviously apparent that the current frontier of automation has come, first, in the form of automated writing.\nThis is obviously a concern for many reasons. The internet is made up of a whole lot of writing. It’s how we text, how we tweet, how we email. It’s what we read, how we get our news, how we ask questions and how we find our answers. Before now, we could safely assume that something we read on the internet came from, at the very least, another human being.\nThat’s not the case anymore, and it will likely not be the case ever again. I don’t think this is the end of the world (probably. hopefully). I do think that this is the end of what I refer to as the statistical median of language: boring, sanitized, business-speak.\nFor the purposes of this note, I am going to refer to this type of language as Binglish.\nBinglish is a Dead-On-Arrival Language\nBinglish, to me, can be described in a few ways:\n\nIt’s Business English. Office English. LinkedIn™ English. I hope, to those of you reading who have also worked a traditional office job, that you can recognize this shorthand as the type of thing that you’d find in your Outlook inbox;\nIt’s Boring English. It’s the median of the language, absent of all personality or human voice; and\nIt’s Bing English. Meant to half-heartedly celebrate Microsoft’s role in solidifying what is very likely a self-consuming business model , poised to consume the very medium it was trained on, this is the type of English that we (currently) see from Bing Copilot, ChatGPT, Gemini, and others\n\nAbsent explicit directives on tone, you can find examples of Binglish on pretty much every single chatbot you could open at the moment. It’s informative. It’s to the point. Once you get the hang of it, it’s easy to both read and write. What’s not to love?\nAnd - unfortunately for the mediums that rely on Binglish - it’s wildly automatable, now.\nIn an effort to formalize the English language into a common median, we have all but guaranteed that the data used to train LLMs has, by definition and in practice, mastered it and put all of us that use it at risk of automation. We can also see the remnants of human efforts to curtail widely-used bots from going outside Binglish at their default settings:\n\nChatGPT refuses to generate even a generic list of English swears…\n\n…as does Raycast’s AI feature, which uses either GPT-Turbo-3.5 or GPT-4…\n\n…as well as Github Copilot, which makes a bit more sense…\n\n…as well as Bing Copilot, even with creative settings, which makes less sense.\nThe takeaway, to me, seems as clear as day.\nHumans Need Not Write Binglish\nThe market for Binglish is cornered. It’s been automated away. The need for writing in the median, devoid of voice or personality, has gone the way of horses in a world of cars. The onus for humans, then, is not to stop writing, but instead to write outside of the Binglish median.\nOne of my favorite examples of people who write with an inimitable voice is Kyla Scanlon, who frequently writes and records thoughts about macro-economics. What makes her writing engaging is not just thoughtful analysis of economic trends, but the voice in which she writes it. It was specifically her post on language and trust that spurred this note to turn into the length of an article.\nWhile I feel like the market for dry, median writing was already withered in the wake of a rising palette preference for infotainment, it was the the advent of ChatGPT and widely-available generative text that has thoroughly crushed the future prospects of Binglish as a human activity. While I can make no guarantees that generative AI won’t someday master imitation of human voice in writing - something that has already reared its head in generative images and spurred active efforts to curtail imitation and preserve unique styles), I have made a decision for my personal writing:\nI don’t want to write Binglish anymore.\nI find no joy in editing the way I write into a now-dead, median form of language, optimized for algorithms with its supply automated away by language models. I’d rather write in my own voice, with my own anachronisms and mistakes and weird vocal ticks and stray punctuation and weirdly-placed emoticons and deeply-nested parentheticals and… run-on sentences? Probably quite a few run-on sentences.\nAs far as I’m concerned, my responsibility is to ensure that the text is readable and that the points I want to make come across, even if it the occasional sentence requires a re-read.\nAnd if it’s not search-engine optimized, or tonally non-neutral, or long-winded? if it contains foul language?\n¯\\(ツ)/¯ fuck it."},"articles/hello-blog":{"title":"Hello, Blog!","links":[],"tags":["python","data"],"content":"Look at that - a whole blog, just for me! At this rate, the last thing I need to do to be a real tech guru is start a podcast.\nI’m starting this page as a place to talk about my cool projects, dumb thoughts, and other odds-and-ends aspects about my life and work.\nTo set the tone, here’s a quick code function to find the geomethic meandian of a set of numbers in Python - in case the need ever arises.\n\nimport numpy as np\n \ndef geothmetic_meandian(\n numbers: np.array,\n error: float = 10e-5\n):\n '''Find the geothmetic meandian of a set of numbers.'''\n \n # If all the numbers are close to the same, return the first number\n if sum(np.abs(numbers - numbers[0])) < error:\n return numbers[0]\n else:\n # Recursively call the geomethic meandian until the numbers converge\n return geothmetic_meandian(np.array([\n np.average(numbers),\n np.product(np.power(numbers, 1 / len(numbers))),\n np.median(numbers)\n ]), error)\n>>> geothmetic_meandian([1, 1, 2, 3, 5])\n2.089\n\nVoila!"},"articles/index":{"title":"Chaotic Good Computing Articles","links":["notes/"],"tags":[],"content":"Here, you’ll find some actual, bona-fide Articles™. You can expect a higher degree of cohesion, revision, and quality than you may find in, say, notes."},"articles/littlefield":{"title":"Zen, and the Art of Laziness","links":["notes/season-of-rhythm","notes/qamo","notes/stability-of-marriage","assets/clutter.png"],"tags":["economics","python","visualizations","data","engineering","games"],"content":"I am awful at sticking to routines - the only thing I can bear to check on every day is Twitter. Even if it means spending twice as long over the course of a weekend, I will always try to find a way to automate away routine manual work.\n(All of the code used in this post can be found here.)\nToo much time to kill\nThis Monday, I started the last major semester of my undergraduate career. That’s right, folks - after six years, four program changes, and one brain surgery (which, in my personal opinion, is one too many), I will finally be wrapping up my degree!\nMy last two semesters will be my first part-time courseloads of my academic career, which leaves me quite a bit of extra time. Given that there’s not much to do during the quarantime, I took a bit of extra time to go over the top in a class I’m taking on operations and supply chain management.\nIntroducing: Littlefield\nAs part of the course, we’ll be spending four weeks in the operations simulation Littlefield. The premise of Littlefield is to tune parameters - things like orders taken and machines purchased - to optimize the profit of a simulated production line. The simulation itself runs a bit faster than real time. Over the course of five full calendar days, one session of the game simulates 250 days of work.\nIn the words of the course instructors:\n\nthe game is set up to give you the flexibility of checking it at your convenience (at any time of day or night)\n\nThe problem? I’m a walking dumpster fire when it comes to routinely checking on anything.\nMy email inbox is constantly full. I am always running on a quarter tank of gas. I’ve never even kept a house plant alive for more than a week - I’m responsible for the early death of more succulents than I would ever care to admit.\nIn the honest-to-God words that my fourth grade teacher wrote on my report card, I am somebody who is “lazy to the point of efficiency.” If there is any way for me to put in all of the work up front, I will find a way.\nWeb Scraping 101\nAs somebody who has been lazy for 23 years now, I’ve become well-acquainted with the concept of web scraping. This is a method for accessing websites using a program instead of your browser. If your job ever involves going to a massive number of web pages and finding specific information - as a few of my internships have entailed from time to time - it’s a fantastic way to avoid the grunt work of going to each individual page by hand. For example, rather than employing an army of people to go through every web page on the internet and keep track of keywords, Google instead uses an army of web scrapers to do all that work for them.\nLittlefield, like the rest of everything on the internet, is scrape-able as well. The game is hosted on a web page that looks like this:\n\nWhile the page is different - and a bit harder to scrape - than your average news article or social media page, it’s still just a set of links that we can get information from. Each node of the graph above leads to a page full of data about the game. If were playing this by hand, we would log in a few times each day, open up each page, and see if there were any issues or bottlenecks in need of fixing.\nIt takes about five minutes to check everything - five exhausting minutes.\nInstead of taking five minutes to check this data myself, I have - as the rational person I am - spent the last six hours creating a program that can check it for me: the Littlefield Driver.\nThe Littlefield Driver\nThe Littlefield Driver is a program that takes all of the data about the state of the game - things like machine utilization, cash on hand, and orders placed - and compiles it into one data table I can look at, graph, and use to diagnose any issues that may be the case. The program is based on a 2017 project by Greg Lewis, who was (at the time) an MBA student at the University of Maryland. Lewis wasn’t alone - developer Jiayu Yi created an export kit for Littlefield back in 2017 as well.\nIdeally, my Littlefield Driver will have a bit of extra functionality beyond data export, but the spirit of automation is still the same. By the end of the project, the goal will be to let the Littlefield Driver use incoming data to automate machine production in the background, and maybe even send me a notification if (or when) something goes horribly wrong.\nThe first order of business for the bot is to take the structure of the game and represent it as a network graph.\nHere’s what the driver sees when it opens up the game:\n>>> lfdriver.draw_graph()\n\n\nIt’s… admittedly not very pretty. At the very least, though, it shows that the program is seeing what we’re seeing: the production line starts at the Orders & Material menus, which goes to the first queue, which feeds into the first station, et cetera.\nHTML is the least romantic language\nWhen a web page is sent to your computer for your viewing pleasure, it’s sent as Hypertext Markup Language, or HTML for short. Normally, we don’t have to deal with HTML directly. The entire point of your web browser is to read the HTML and turn it into something clean, pretty, and - most importantly - human-readable. Scraping the web, however, means that we do need to read the HTML directly in order to pick out the parts we want the computer to look for.\nOur target for the first round of web scraping is going to be the Littlefield data pages. These data pages give you the historical plot of whatever the selected node of the graph represents. For example, this is the data page for how many incoming job requests are received every in-game day:\n\n(as an aside, every time you open a data view, it annoyingly opens as an entirely new window, which means playing Littlefield often looks like this)\nI can always appreciate a clean-looking graph.\nTo make that graph, it’s actually your web browser doing all the work to turn the HTML into a neat visualization. This is what your computer is actually sent:\n\nEven when you’re making a website, reading through raw HTML is rarely ever a fun time. Thankfully, the data we’re looking for is on line 29, smack-dab in the middle of the page:\n{label: 'data', points: '1 1 2 1 3 2 4 ...}\n\nThat’s the data that your browser is using to create the plot from the first image. It’s a bit weird that it’s all one line, but we can pick up from context that the data is being provided in pairs - the first number is the day, then the next is the datapoint - repeated over and over again. You could read it as:\nDay 1: 1 job\nDay 2: 1 job\nDay 3: 2 jobs\nDay 4: ...\n\nThankfully, the data is delivered in the same way for every single data page, from the orders received to the utilization of each station. All we have to do is write the code once, give the program all the data pages, and let it run. Instead of one string of data, we can tell it to put the data in nice, neat human-readable columns like this:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nDayJOBIN112132425363\nAfter scraping every single page of data in the game, we can smash it all together and get a beautiful chart!\n>>> lfdriver.data()\n\n\nThis chart just shows the first and last 10 days of the historical data, and even from this we can gain some insights. S3UTIL, which represents the current utilization of the third station, is at 67% on Day 50 of the simulation. Judging by the rate of increase - roughly 1.3% every day on average - we should probably consider buying another machine at Station 3 prior to Day 75.\nOf course, that’s just an estimate. The purpose of the Driver is to check in on the game routinely to see if there are any critical issues. For example, the Driver can check to see if a station utilization is at a high percent and calculate whether or not it would be profitable to order a new machine.\nEverything is done - for now\nAt the time of writing this, I haven’t actually played a game of Littlefield - everything written so far was done on a static sample game. This means I haven’t had access to some features - like purchasing machines - so they haven’t been added to the Littlefield Driver… yet. Additionally, there’s some system variables - such as the cost of a new machine - that are available in the data but aren’t available in the Driver.\nUltimately, this is a god-awful way to play the game. With 12 years in development and only 2 examples (that I’ve found) of people attempting to automate the game, the game is clearly playable by hand. You might ask, then - why put in all this effort?\nThe real question is: why not?"},"articles/resume-ci-pipeline":{"title":"Job Applications are a Waking Nightmare - Let Tech Do It For You","links":[],"tags":["mentoring","engineering","tutorials"],"content":"\nNOTE: THIS IS OUTDATED. There are now far better PDF markup languages to use, such as Typst. These will be detailed in a later blog post.\n\nAfter trying - and failing - to constantly keep my resume up-to-date in a dozen different places, I took a page out of the wild world of software development and found the solution: continuous integration.\nIt used to be the case that software would release in massive updates. A bunch of big changes, tweaks, and bug fixes would be shoved together in a tidy package and delivered out all at once. As development became faster, though, development teams created continuous integration pipelines to constantly push changes out to their users. Rather than waiting until the next big change to release patches, small changes could be pushed out automatically.\nThis is common in web applications like Facebook or Twitter. You’ll never see Twitter come out with some big new Twitter 2.0 (Two-tter) - any changes they need to make are just pushed out to users in small batches, over time. Why not do the same with a resume?\nCreating an Always-Updated Resume\nCreating a continuously-updating resume can be done in two steps:\n\nSet up your resume so that you can make small, quick, iterative changes over time; and\nFind a central place to send those changes to, and send viewers to that location.\n\nI’m sure there are quite a few ways to run those two stages. I personally chose Overleaf and GitHub. At this point, I had already been using Overleaf to format my resume and had been using GitHub for small odds-and-ends projects for the first couple years of my undergrad. If we’re being honest, I didn’t want to learn new things - I just wanted it to work.\nSometimes being lazy pays off. Not usually, but sometimes.\nIt also helps that Overleaf has a neat built-in GitHub integration. How nice of them to do that! With this integration, the steps for the project start to come together:\n\nCreate a resume on Overleaf\nPush your resume to GitHub\nCompile your resume into a .pdf file\n\nAlright - let’s do it!\nCreating a Resume in Overleaf\nFor the uninitiated, Overleaf is an application commonly used in academia to write academic papers in a programming language called LaTeX. If you’ve ever used HTML to create a website, LaTeX does the same thing for PDFs. Thankfully, to get started, you don’t have to create a new resume from scratch. Overleaf has a ton of sleek-looking resume templates that you can put your current information into. If you’re looking for a friendly resume-making guide, I made a starter template with explanations on a few best resume practices for students.\nOnce you have a template picked, you can select “Open as Template” to add it to your personal Overleaf projects. You can start putting your information in at your own pace, but it isn’t necessary to start connecting your resume to GitHub.\nLinking Overleaf and GitHub\nIf you don’t have a GitHub account, now is the time to make a new one! GitHub is a fantastic place to store and update code - it’s literally what it was made for! Because your new resume (and the LaTeX it’s made from) are very small, it’s an ideal place to host your resume.\nOn your Overleaf resume, you can find the GitHub integration in the menu on the top-left of the code editing window. After signing into your GitHub account, you’ll have the option to create a new code repository for your project. Choose a name for your repository, enter a description if you’d like, and then select the option to make your repository public.\nWhile you can name your code repository anything, I would recommend sending this to your user’s GitHub Pages repository. Every GitHub user gets a special place where they can host a website or files publicly at <YOUR USERNAME>.github.io. If that type of address looks familiar, it’s because I host this blog on my own GitHub Pages site!\nIn order to use Github Pages, you’ll need to name your new repository <YOUR USERNAME>.github.io. For example, because my GitHub username is spelkington, my GitHub Pages repository is named spelkington.github.io.\nFinally, with your repository made, click the button to push Overleaf changes to GitHub. Now it’s time to make your resume update automatically!\nSetting up Continuous Integration\nGitHub has a nifty feature called Github Actions that development teams can use to automate some of the pain-in-the-ass aspects of programming. Typically this involves automatically testing software for glitches or compiling code, but for our case we’re going to use it to automatically turn our resume code into a .pdf file.\nThankfully, we don’t have to come up with a way to do this ourselves! Xu Cheng has created a nifty GitHub Action that will compile LaTeX files into PDFs.\nGo to your new repository on GitHub and click on the Actions button at the top. From there, you can create a new action.\nCreating a new action should take you to a code editor where you can create an Action configuration from scratch. Remove everything and place this code below:\nname: Build LaTeX document\n \n# Run this action every time the resume .tex is updated\non:\n push:\n paths:\n - '<RESUME FILE NAME>.tex'\n \njobs:\n build_latex:\n runs-on: ubuntu-latest\n steps:\n \n # Check out the repository on the Action machine\n - name: Set up Git repository\n uses: actions/checkout@v2\n \n # Compile the LaTeX document into a .pdf\n - name: Compile LaTeX document\n uses: xu-cheng/latex-action@v2\n with:\n root_file: resume/<RESUME FILE NAME>.tex\n \n # Commit this change as an automated user\n - name: Commit Change\n uses: EndBug/add-and-commit@v7.0.0\n with:\n author_name: <YOUR NAME> (auto)\n author_email: <YOUR EMAIL>\n message: 'TeX compile'\n \n # Push the change to the repository\n - name: Upload PDF\n uses: ad-m/github-push-action@master\n with:\n github_token: $\\{{ secrets.GITHUB_TOKEN }}\nReplace everything in the < > brackets, press the “Start Commit” button at the top right, and you’re all set! From now on, whenever you make changes to your resume in Overleaf, you can navigate back to the GitHub integration menu, push your change, and it’ll automatically send the code to GitHub and turn it into a .PDF!\nSending Your Resume\nOf course, the point of all this is be able to have a single link to your resume that will stay up-to-date forever. So how do we get this link?\nIf you followed the instructions for setting up the resume on your GitHub pages repository, it’s easy! Your resume will be available at <YOUR GITHUB USERNAME>.github.io/<YOUR RESUME FILE>.pdf. For example, mine is available at spelkington.github.io/Elkington_Resume.pdf."},"articles/robloxaville":{"title":"The Unbearable Weight of ROBLOX Celebrity","links":["notes/robloxaville-remaster"],"tags":["roblox","lua","engineering","games"],"content":"Guilty confession: I’ve had a ROBLOX account for 14 years. At 23 years old, that’s more than half my life. After picking up development again in 2021, I’ve had quite the walk through memory lane.\nBeing a dork is a lifetime commitment\nFlash back to 2007: Spencer Elkington, 4th grade extraordinaire. Oh, to be at my peak again. While I appreciate that secondary schools mandate that all kids have a well-rounded curriculum to introduce them to a wide span of different fields of study, I can safely say that one of my least favorite classes was art. While I didn’t not enjoy spending an hour cutting, painting, gluing, and molding, there are only so many burnt ceramics and skewed portraits I could churn out before they - and my parents to whom that “art” was gifted - realized that perhaps a budding patronage in the fine arts wasn’t going to be in the cards for me.\nRelated point: Being a dork might be genetic\nAround that same time, I made an account on ROBLOX, an online game platform that was just a year old in 2007. Founded originally as a physics engine by mechanical engineers, it transitioned into a gaming platform after (I can only assume) the founders decided simulating viable buildings was far less fun than blowing them up. One of the coolest features was ROBLOX Studio, an IDE for developing user-made games and content in Lua. If you could play a game, you could make a game, and that ease of entry introduced a whole generation - myself included - to the wild world of programming.\nCooking up small games for me and my friends is probably the closest I’ll ever get being an artist. I could never paint a canvas worth a damn, but in an increasingly digital world being able to write a bit of code lets you create as much as a paintbrush ever could. Always looking for ways to hang out with her son, my mom - who is and always will be the biggest, coolest dork I have ever met and will ever will meet - joined the platform in 2008 to make games too.\nWith a background in coding from her physics, geology, and chemistry studies at BYU during her undergraduate (because just studying one STEM field would be too easy, obviously), she was an artist of her own right when it came to making games her kids could play. Over time, one of those games developed into a project called Robloxaville that she actively developed on from 2008 to 2012. The game became one of the most played games on ROBLOX during that period, later superceded by a follow-on project called Lakeside that became one of the fastest-growing projects made on the platform within two months of its’ initial release.\n\nOriginal Robloxaville thumbnail, 2008\nThis success was in no small part due to a feature she developed in 2009 called Morph Magic, a wildly clever, wildly hack-y workaround she discovered to modify the underlying skeleton of the ROBLOX player model and transform players into fully-animated dogs, cats, giants, or any of a dozen other models. The ad-hoc rigging method originally used in Morph Magic was the only method for modifying the player skeleton until ROBLOX added official rigging support - six years later. Watching millions of people enjoyed my mom’s masterpiece is what made me get into coding - first as a play tester, then as a (very amateur) contributor, and finally remastering the project in 2017.\nLike I said: the biggest, coolest dork I have ever met and will ever meet.\nThe wild ways software can go horribly, horribly wrong\nIn 2013, my mom stopped developing on the platform. It’s not that she didn’t enjoy it - as a general rule, nobody in their right mind writes clever workaround libraries in their free time if they don’t enjoy it. What stopped her from developing on the platform was years of rampant client-side exploits made possible by some questionable decisions made in the development of the ROBLOX game engine. For the uninitiated, here’s what went wrong:\nWhenever you use a device connected to the internet - your phone, laptop, tablet, desktop, etc. - it is communicating with tons of other computers called servers that belong to whatever service you happen to be using. When you’re browsing the web, it’s communicating with web servers. When you’re sending an email, it’s communicating with email servers. And when you’re playing ROBLOX, it’s communicating with ROBLOX servers.\nThese servers are responsible for running all the code that makes the game work. It diligently reads the Lua code that makes up a ROBLOX game, line by line, and changes the state of the game to whatever its’ told. If you tell the server to game.Workspace.Player.Head:Remove(), it will gleefully read that line of code and promptly remove the head of some unsuspecting victim.\nThat being said, sometimes the server needs a bit of help. Specifically, the server will occasionally rely on the game clients - your computer, and the computers of every other player in the game - to help it run some of the physics calculations. The millions of physics calculations run by the game can be a real pain in the ass for one computer, so the game server needs all the help it can get. Because of that, the client will occasionally send some information to the server to help the server know what the state of the game should be. Innocent enough, right?\nIt wasn’t always the case that the server relied on the clients for just physics calculations. Back in the early days of the ROBLOX engine, the client could send the server any information about the state of the game and the server would happily accept it as a gospel truth, even if it wasn’t in the game code. Here’s how the conversations between the server and client used to go:\n\nCLIENT: Hey Server! I need you to remove this player’s head for me.\nSERVER: Are you sure? I don’t remember seeing game.Workspace.Player.Head:Remove() anywhere in the code.\nCLIENT: Yep! Definitely supposed to not have a head. That’s how it looks on my computer.\n\nAnd then the server would, once again, gleefully remove the head of some unlucky soul, despite that fact that it was a rogue player’s client who gave the order, not the programmer.\nThese exploits, at a basic level, allowed users to wreak havoc on games: breaking game functions, harassing players, et cetera. However, the exploits were not always just to be annoying. The same exploit that allowed users to mess with the state of the server could also be used to download the source code for entire games, allowing users to rip and reupload entire years-long projects in minutes. At their worst, these exploits could get downright horrifying. \nBack in the Saddle\nIn 2014 - following what could only be described as a complete COPPA cluster - ROBLOX began making moves to clean up and polish the platform. This came in two major changes to the way development worked. \n1. Filtering Enabled\nTo fix the slightly problematic client exploit issue, the company introduced the Filtering Enabled feature to their game engine. Filtering Enabled locked down what types of information game servers would accept from the game client and fixed that little whoopsies mistake made in the younger days of the platform. However, development became a trickier after this feature was rolled out - many older games needed to be re-made to conform to the communication boundary between the server and client, and required a bit more formal knowledge of game development to make.\n(For reference, I didn’t learn anything about server and client relationships until my third year into a computer science degree.)\nEven though this feature could be disabled to allow legacy games to keep functioning (and yes, Robloxaville is legacy now - it even has the Fandom Wiki page to prove it), ROBLOX’s featured games algorithm wouldn’t touch your project with a ten-foot pole for risk of traumatizing even more unsuspecting children. This was especially important for the next major change,\n2. Monetization\nThat’s right, folks - every line of code my mom wrote from 2008 to 2013, she wrote for free. Making fun games for millions of kids across the world, pro bono? That’s just the way Tiffany rolls.\nWith the introduction of the Developer Exchange (DevEx), anybody (who could afford a premium membership) could take the in-game currency generated from their games and exchange it for cold, hard cash. Funnily enough, in that original blog post explaining how the DevEx program worked, the company describes a system where:\n\n[A] power-user [could cash] cash out and [buy] a car to get to and from college – all from developing a popular game on ROBLOX. This is the kind of story we can’t wait to tell.\n\nThat’s not quite the direction things went.\nThe Part Where Spencer Does Some Math\nSince DevEx was released, I’ve heard stories of full-time developers leaving their jobs to develop on the platform. Success could be lucrative: Welcome to Bloxburg, one of a number of games that filled in the Town And City genre gap after Robloxaville and Lakeside became deprecated by the Filtering Enabled update, has been played 4.8 billion times as of writing.\nBillion. With a “B”. 4,800,000,000.\nThat’s a lot of zeroes.\nThe game offers users a premium pass as an in-game purchase. This is a pretty common way to offer users a bit of extra bang for their buck by providing small bonus features - Robloxaville did the same thing at one point. How much do you think they could make off of a feature like that?\nUnfortunately for us, exact numbers are hard to find. ROBLOX stopped showing how many times in-game purchases were sold, no doubt to stop people from snooping around at how much developers make. That being said, we’ll make an assumption off of Robloxaville’s conversion rates: For every 10,000 player visits, 5 people will splurge on a premium pass at a purchase rate of 0.05%. That doesn’t look too impressive - yet.\nAt a 0.05% purchase rate against - and I cannot emphasize this enough - 4.8 billion visits, we could estimate that BLOXburg’s premium pass has been purchased 2.4 million times. Each game pass is 400 Robux (R$), ROBLOX’s in-game currency. If memory serves, ROBLOX keeps 30% of in-game player-to-player purchases (because, as we know, the only certainties are death and Robux taxation). We can assume, then, that the developers of BLOXburg received ~960 million R$ for that premium pass.\nThat golden parachute is starting to look real good.\nWhat might a 960 million R$ payout look like? The current DevEx exchange rate as of writing is 0.0035 USD for every 1 Robux (Robuck?) at the time of writing. This means that the estimated worth of that one premium pass for that one game is…\n3.6 million dollars.\nHm.\nHmmm.\nOf course, this does not come without some caveats. First: this is one of the most played games in the history of the platform - its’ success is by no means descriptive of every developer. Second: their estimated payout was made over the course of the six years the game has been in development. Third: the BLOXburg team is not just a single developer, and they are very good at what they do - enviously good, even.\nThat being said: those caveats also come with caveats. Although not every developer is going to be that successful, ROBLOX self-reportedly spends about 25% of their revenue on developer payouts as of a report from 2017. Since the company made its’ public debut on the New York Stock Exchange and started reporting revenue as a publicly traded company, they reported a revenue of $147 million dollars in 2020. Assuming they still pay out 25% to developers, that’s a big ol’ pot of 34 million dollars to go around.\nHow To Make Games and Influence Gen Z\nThis post has gotten way, way longer (and included way more math) than I intended, so I’ll wrap it up for now. Long story short: since 2007, ROBLOX has grown beyond description in both size and sophistication. The introduction of monetization professionalized the platform beyond what hobbyists from the early 2010s could ever pull off today. And, after (attempting) to redux Robloxaville back in 2016, I’m ready to take another stab at it.\nThe way I see it, games are to the computer what film was to the camera and paint was to the canvas. It’s a way to create an experience that people can look at, play with, and grow from. I really enjoy it. It’s a way for somebody who has no business in making art to get pretty damn close.\n(And it wouldn’t hurt to get some of that sweet DevEx stimmie, either.)"},"articles/structured-streaming":{"title":"Don't Double Down: Using Spark Structured Streaming to Wrangle Growing Data","links":[],"tags":["data","engineering","python","aws","tutorials","visualizations"],"content":"\nThis post was written during my time as a software engineer at M Science as a joint project with Databricks. You can view the original post here\n\nLet’s say that you, a ✨ humble data plumber ✨ of the Big Data era, have been tasked to create an analytics solution for an online retail dataset:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nInvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry53636585123AWHITE HANGING HEA…62012-01-10$2.5517850United Kingdom53636571053WHITE METAL LANTERN62012-01-10$3.3917850United Kingdom53636584406BCREAM CUPID HEART…82012-01-10$2.7517850United Kingdom……………………\nThe analysis you’ve been asked for is simple - an aggregation of the number of dollars, units sold, and unique users for each day, and across each stock code. With just a few lines of PySpark, we can transform our raw data into a usable aggregate:\nimport pyspark.sql.functions as F\n \ndf = spark.table("default.online_retail_data")\n \nagg_df = (\n df\n # Group data by month, item code and country\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n F.countDistinct("CustomerID")\n .alias("Users"),\n )\n)\n \n(\n agg_df.write\n .format('delta')\n .mode('overwrite')\n .saveAsTable("analytics.online_retail_aggregations")\n)\nWith your new aggregated data, you can throw together a nice visualization to do… business things.\n\nThis works - right?\nAn ETL process like will work great for a static analysis, where you don’t expect the data to ever be updated - you assume the data you have now is going to be the only data you ever have. The problem with a static analysis?\nModern data doesn’t stop growing.\nWhat are you going to do when you get more data?\nThe naive answer would be to just run that same code every day, but then you’d be re-processing all of the data, every time you run the code. Each new update means re-processing data you’ve already processed before. When your data gets big enough, you’ll be doubling down on what you spend in time and compute costs.\n\nWith a static analysis, you spend money on re-processing data you’ve already processed before\nThere are very few modern data sources that aren’t going to be updated. If you want to keep your analytics growing with the source of your data, and save yourself a fortune on compute cost, you’ll need a better solution.\nWhat do we do when our data grows?\nIn the past few years, the term “Big Data” has become… lacking. As the sheer volume of data has grown and more of life has moved online, the era of Big Data has started to become the era of “God Help Us, It Just Won’t Stop Getting Bigger Data.” A good data source doesn’t stop growing while you work, and this growth can make keeping data products up-to-date a monumental task.\nAt M Science, our mission is to use alternative data - data outside of your typical quarterly report or stock trend data sources - to analyze, refine, and predict change in the market and economy.\nEvery day, our analysts and engineers face a challenge: alternative data grows really fast. I’d even go as far to say that, if our data ever stops growing, something in the economy has gone very, very wrong.\nAs our data grows, our analytics solutions need to handle that growth. Not only do we need to account for growth, we also need to account for data that may come in late or out-of-order. This is a vital part of our mission - every new batch of data could be the batch that signals a dramatic change in the economy.\nTo make scalable solutions to the analytics products that M Science analysts and clients depend on every day, we use Databricks Structured Streaming. Structured Streaming gives us the assurance that, as our data grows, our solutions will scale as well.\nUsing Spark Structured Streaming\nStructured Streaming comes into play when new batches of data are being introduced into your data sources. Structured Streaming leverages Delta Lake’s ability to track changes in your data to determine what data is part of an update and re-computes only the parts of your analysis that are affected by the new data.\nIt’s important to re-frame how you think about streaming data. For many people, “streaming” means real-time data - streaming a movie, checking Twitter, checking the weather, et cetera. If you’re an analyst, engineer, or scientist, any data that gets updated is a stream. The frequency of the update doesn’t matter. It could be seconds, hours, days, or even months - if the data gets updated, the data is a stream. If the data is a stream, then Structured Streaming is going to save you a lot of headaches.\n\nWith Structured Streaming, you can avoid the cost of re-processing previous data\nLet’s step back into our hypothetical - you have an aggregate analysis that you not only need to deliver today, but also keep updating as new data rolls in. This time, we have the DeliveryDate column to remind us of the futility of our previous single-shot analysis:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nInvoiceNoStockCodeDescriptionQuantityInvoiceDateDeliveryDateUnitPriceCustomerIDCountry53636585123AWHITE HANGING HEA…62012-01-102012-01-172.5517850United Kingdom53636571053WHITE METAL LANTERN62012-01-102012-01-153.3917850United Kingdom53636584406BCREAM CUPID HEART…82012-01-102012-01-162.7517850United Kingdom………………………\nThankfully, the interface for Structured Streaming is incredibly similar to your original PySpark snippet. Here is your original static batch analysis code:\n# =================================\n# ===== OLD STATIC BATCH CODE =====\n# =================================\n \nimport pyspark.sql.functions as F\n \ndf = spark.table("default.online_retail_data")\n \nagg_df = (\n df\n \n # Group data by date & item code\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n \n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n F.countDistinct("CustomerID")\n .alias("Users"),\n )\n)\n \n(\n agg_df.write\n .format('delta')\n .mode('overwrite')\n .saveAsTable("analytics.online_retail_aggregations")\n)\nWith just a few tweaks, we can adjust this to leverage Structured Streaming. To convert your previous code, you’ll:\n\nRead our input table as a stream instead of a static batch of data\nMake a directory in your file system where checkpoints will be stored\nSet a watermark to establish a boundary for how late data can arrive before it is ignored in the analysis\nModify some of your transformations to keep the saved checkpoint state from getting too large\nWrite your final analysis table as a stream that incrementally processes the input data\n\nWe’ll apply these tweaks, run through each change, and give you a few options for how to configure the behavior of your stream.\nHere is the ✨ stream-ified ✨ version of your old code:\n# =========================================\n# ===== NEW STRUCTURED STREAMING CODE =====\n# =========================================\n \n+ CHECKPOINT_DIRECTORY = "/delta/checkpoints/online_retail_analysis"\n+ dbutils.fs.mkdirs(CHECKPOINT_DIRECTORY)\n \n+ df = spark.readStream.table("default.online_retail_data")\n \nagg_df = (\n df\n+ # Watermark data with an InvoiceDate of -7 days\n+ .withWatermark("InvoiceDate", f"7 days")\n \n # Group data by date & item code\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n \n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n+ F.approx_count_distinct("CustomerID", 0.05)\n .alias("Users"),\n )\n)\n \n(\n+ agg_df.writeStream\n .format("delta")\n+ .outputMode("update")\n+ .trigger(once = True)\n+ .option("checkpointLocation", CHECKPOINT_DIR)\n+ .toTable("analytics.online_retail_aggregations")\n)\nLet’s run through each of the tweaks we made to get Structured Streaming working:\n\nStream from a Delta Table\n\n+ df = spark.readStream.table("default.online_retail_data")\nOf all of Delta tables’ nifty features, this may be the niftiest: you can treat them like a stream. Because Delta keeps track of updates, you can use .readStream.table() to stream new updates each time you run the process.\nIt’s important to note that your input table must be a Delta table for this to work. It’s possible to stream other data formats with different methods, but .readStream.table() requires a Delta table\n\nDeclare a checkpoint location\n\n+ # Create checkpoint directory\n+ CHECKPOINT_DIRECTORY = "/delta/checkpoints/online_retail_analysis"\n+ dbutils.fs.mkdirs(CHECKPOINT_DIRECTORY)\nIn Structured Streaming-jargon, the aggregation in this analysis is a stateful transformation. Without getting too far in the weeds, Structured Streaming saves out the state of the aggregation as a checkpoint every time the analysis is updated.\nThis is what saves you a fortune in compute cost: instead of re-processing all the data from scratch every time, updates simply pick up where the last update left off.\n\nDefine a watermark\n\n+ # Watermark data with an InvoiceDate of -7 days\n+ .withWatermark("InvoiceDate", f"7 days")\nWhen you get new data, there’s a good chance that you may receive data out-of-order. Watermarking your data lets you define a cutoff for how far back aggregates can be updated. In a sense, it creates a boundary between “live” and “settled” data.\nTo illustrate: let’s say this data product contains data up to the 7th of the month. We’ve set our watermark to 7 days. This means aggregates from the 7th to the 1st are still “live”. New updates could change aggregates from the 1st to the 7th, but any new data that lagged behind more than 7 days won’t be included in the update - aggregates prior to the 1st are “settled”, and updates for that period are ignored.\n\nNew data that falls outside of the watermark is not incorporated into the analysis.\nIt’s important to note that the column you use to watermark must be either a Timestamp or a Window.\n\nUse Structured Streaming-compatible transformations\n\n+ F.approx_count_distinct("CustomerID", 0.05)\nIn order to keep your checkpoint states from ballooning, you may need to replace some of your transformations with more storage-efficient alternatives. For a column that may contain lots of unique individual values, the approx_count_distinct function will get you results within a defined relative standard deviation.\n\nCreate the output stream\n\n+ agg_df.writeStream\n .format("delta")\n+ .outputMode("update")\n+ .trigger(once = True)\n+ .option("checkpointLocation", CHECKPOINT_DIR)\n+ .toTable("analytics.online_retail_aggregations")\nThe final step is to output the analysis into a Delta table. With this comes a few options that determine how your stream will behave:\n\n.outputMode("update") configures the stream so that, each time the code runs, the aggregation will pick up where it left off instead of running from scratch. To re-do an aggregation from scratch, you can use "complete" - in effect, doing a traditional batch aggregate while still preserving the aggregation state for a future "update" run.\ntrigger(once = True) will trigger the query once when the line of output code is started, and then stop the query once all of the new data has been processed.\n"checkpointLocation" lets the program know where checkpoints should be stored.\n\nThese configuration options make the stream behave most closely like the original one-shot solution.\nThis all comes together to create a scalable solution to your growing data. If new data is added to your source, your analysis will take into account the new data without costing an arm and a leg.\nYou’d be hard pressed to find any context where data isn’t going to be updated at some point. It’s a soft agreement that data analysts, engineers, and scientists make when we work with modern data - it’s going to grow, and we have to find ways to handle that growth.\nWith Spark Structured Streaming, we can use the latest and greatest data to deliver the best products, without the headaches that come with scale."},"contact":{"title":"Contact Chaotic Good Computing","links":[],"tags":[],"content":""},"index":{"title":"Oh, Howdy!","links":["notes/digital-economies","tags/mentoring","articles/"],"tags":[],"content":"Chaotic Good Computing is an organization specializing in providing advice and assistance for small companies around:\n\nSoftware Engineering\nData Analysis & Handling\nEconomic Analysis\n\nCGC’s general specialty is engineering, analysis, insights, and maintenance of digital economies like multiplayer game economies, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications.\nCGC also provides professional development resources and mentoring for young developers and professionals interested in economics and software engineering.\nThis site contains articles, notes, and thoughts on a broad range of topics. Chaotic Good Computing’s articles are great points to get started!"},"notes/arc-review":{"title":"Arc Browser: The Beginning of My Tumulting Times™","links":["notes/the-quest-to-kick-the-gremlin"],"tags":["gremlin-kicking"],"content":"The Arc Browser is probably the first tool that kicked off a series of shake-ups on how I use technology to put up guard rails on being able to start - and stay - focused. It was also on their blog that I discovered Maggie Appleton’s blog - so in a way, it was very much a half-step into a pool of ideas that have helped me come to terms with the slightly-more-than-standardly chaotic way that I tend to work.\nAt some point, I’ll do a review here."},"notes/beethoven":{"title":"From the Archive: \"Reading the Room with Beethoven\"","links":[],"tags":["engineering","typescript"],"content":"Beethoven was a project for HackTheU 2019, where a team and I (mostly the team) created an application for providing live captions to deaf students by using a remote microphone to stream audio and captioning to a user’s local device.\nFrom the original submission:\n\nInspiration\nSpencer, one of our team members, has a parent who is hearing-impaired and another that provides live, remote, ver batem transcription services for deaf and hard-of-hearing undergraduate, Ph.D., and Executive MBA students across the nation. Dan and Joseph, two of our other members, work for Sorenson Communications making video calling and other applications for the deaf community. We noticed that, for deaf students who would prefer live captioning in their lectures, there is no one-stop solution for both audio streaming and live captioning. We created Beethoven, an application for quick and accurate transcription in the classroom, to solve this.\nFunctionality\nPut simply, Beethoven will pair two devices together - an audio input and a screen output - and stream captioning from one device to the other in real time. The student can put one device at the front of the class for the clearest possible audio, and then position another next to them to read live captioning of the lecture and dialog as if it was the Closed Captioning on a television show or movie. This can either be done through Google Cloud transcription services or a live CART interpreter, depending on the level of accuracy desired and resources available.\nDevelopment Process\nThe application is split into three main parts - the audio input, the transcription service, and the screen output. First, the audio is captured by the audio input device. From there, it goes to either the Google Cloud voice transcriber, or a live CART interpreter. This happens through Google Cloud Services or peer-to-peer WebRTC, respectively. Once complete, the text will be sent to both our server’s backend to be compiled into a transcript and send to the screen output device, placed in front of the student, where a stream of the captioning is displayed.\nWhat’s next for Beethoven\nMoving forward, we’d like to fully implement the CART reporting features of the application. The P2P handshaking feature has a lot of improvements that can be made. Once finished, we’d like to reach out to the deaf and CART communities to get their feedback on the product.\n"},"notes/caveat-lector":{"title":"Caveat Lector: Reader Beware","links":["notes/digital-gardening-with-quartz","notes/qamo","tags/horticulture"],"tags":["horticulture"],"content":"The past few days have been a weird experience as I actively try to lower the internal bar for what I feel comfortable putting out into the world. As a proud member of the most terminally online generation to ever live, I have a deep and relentless fear of being wrong on the Internet.\nIn getting everything ready to re-publish this site as my own digital garden, I’ve started using the phrase “caveat lector” a lot. Back in my undergraduate degree, I learned about the phrase caveat emptor and caveat venditor:\n\nCaveat emptor means “buyer beware,” to be used in situations where a buyer of a product is responsible for understanding the risk they take in their purchase; and\nCaveat venditor means “seller beware”, to be used in situations where a seller of a product is responsible for minimizing the risk of the products they sell.\n\nA good napkin example would be a buyer and seller of digital LCD displays. In that case, it’s the seller’s responsibility to make sure that the display actually works - caveat venditor. However, what if a display works, but has a few dead pixels? This doesn’t render the display unfit for purpose - the seller would still be selling a good and usable product that fulfills their promise - but dead pixels are pretty annoying. The risk of dead pixels, then, may fall on the buyer - caveat emptor.\nOne of my intentions with Chaotic Good Computing is to contribute to the free body of knowledge I’ve benefitted immensely from myself, but to do so in a way that both fits my style and my habits better than traditional blogging or educational entertainment. The commitments that I’m making to you, the reader, are:\n\nTo my knowledge, the things that I’m posting are accurate at the time that I write them down; and\nIf I learn something in the future that corrects something I’ve written in the past, I’ll do my best to make corrections as I find mistakes. \n\nThat said, I’m also just some person on the internet. I know some things pretty well and other things not-so-much, with a pretty vast in-between. By the very nature of learning in public, some things here will be straight-up wrong, if not at least not-as-correct-as-they-could-be.\nSo, to you, I say:\n\nCaveat lector!\nReader Beware!\n\nand, as a follow-up piece of advice, I might also borrow from the Russian proverb:\n\nDoveryay, no Proveryay.\nTrust, but Verify.\n"},"notes/dailies/2024-02-25":{"title":"2024-02-25","links":["notes/caveat-lector","notes/digital-gardening-with-quartz","notes/over-under-engineering"],"tags":["typescript","horticulture"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI didn’t plan anything today, but I do want to start planning things in the future.\nToday’s Report\nI’m totally ripping off the labelling of this from Pikmin 2’s “Today’s Report” screen.\nThat’s not even a joke - I absolutely love the idea of ending the day with little graphs of what I did (or did not do) well that day in a tidy little reflective at-a-glance view.\nToday was (and will continue to be - my plan is to go home and keep going while I watch Avatar) a whole lot of writing. I’m still in the process of creating a new blog with Quartz, but I keep catching myself falling into a trap of “I want to make everything look perfect before I publish it!“. Despite spending the day jotting down my thoughts about over-engineering killing my dreams, I can’t seem to stop myself.\nThe stopping point for today will probably be a vague “do I feel like I’ve written enough to cover, at a base level, the anchor tags of what I want to write.” I still do want to do some weird D3.js fuckery to Quartz’s network graph where major “anchor” tags are locked to the outside of a circle (or some other shape) with extending graphs moving inward, but I am unfortunately blocked by not knowing how to debug with Quartz’s weird custom CLI build process.\nActually, it looks like the Quartz author just got back to me - QuartzComponents are built…\ntoo late? too early? I still don’t know enough about frontend development to fully understand how Quartz works under-the-hood or totally what that message means.\nTL;DR something about the Quartz build process means that I can’t use DevTools in a browser to debug Quartz components. Yesterday I was researching CodePens (or, more specifically, VSCode-inline CodeSwings) as a better workflow for my not-design-or-frontend-savvy self to develop these components in isolation. While I do still want to do some deep customizations to the way the Quartz Graph component works, I have decided (just now, as I’m writing) to leave this as a stretch goal, and instead prioritize getting this blog out as-is and customizing it to my liking later.\nMore work to be done in the endless struggle to avoid putting horses before carts, or whatever.\nNotes\n\nhttps://blog.partykit.io/posts/cursor-party\nhttp://www.bruno-latour.fr/sites/default/files/35-MIXING-H-ET-NH-GBpdf_0.pdf\nhttps://maggieappleton.com/gathering-structures\nhttps://maggieappleton.com/ambient-copresence\nhttps://github.blog/2023-10-05-a-developers-guide-to-open-source-llms-and-generative-ai/\nhttps://github.blog/2023-10-04-how-to-communicate-like-a-github-engineer-our-principles-practices-and-tools/\nhttps://www.rawgraphs.io/\n"},"notes/dailies/2024-02-26":{"title":"2024-02-26","links":["notes/caveat-lector","notes/dailies/2024-02-25","notes/the-quest-to-kick-the-gremlin","notes/season-of-rhythm"],"tags":["csharp","aws","gremlin-kicking","horticulture"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nMost of today’s plan is going to be getting an internal NWYC project up-and-running with an MVP before we transition to some compliance updates to infrastructure. Follow-up on CGC will be taking inventory of the writing I did yesterday, and (once again) debating whether or not to get the formatting of the blog just right before I publish.\nB-Block\n\nCompleting C# wrappers for Geocoding services\nWorking on next ChainSharp steps for congressional data lookups\n\nM-Block\n\nLikely a continuation of B-block work\n\nE-Block\n\nCGC; in particular, either\n\nContinuing content writing, potentially starting the new posts for 1099 contractor writing; OR\nSetting up an environment & workflow for creating swings with CodeSwings\n\n\nStretch goal is contemplating whether or not MDX compatibility for Obsidian and Quartz will come now or later. I think Remark has the ability to do MDX files but I’ll need to spike that a bit more closely.\n\nToday’s Report\n\n\nNoon progress update: Got distracted at the possibilities of AWS CloudWatch Dashboards. Morning block is a bit behind, but getting back to it.\n\n\nAfternoon progress update: as a general rule, try to never fuck up the same way twice. that’s a good motivation for writing down as much as possible outside of code, so that the body of DX-related issues with undocumented fixes is always shrinking.\n🎵 come with me 🎵 //\n🎵 and you’ll see 🎵 //\n🎵 a world in which no developer fucks up the same way twice, and rather fucks up in new and creative ways each time 🌈 🎵\n\n\nIn sum total, today was… okay? ish? in terms of progress. Didn’t quite get as far as I’d hoped on C#, but some other (equally important) stuff came up and that seems okay. E-block certainly didn’t go as far as I’d hoped (read: it did not happen) but at least CGC stuff is at my own pace.\nAdmittedly, a minor distraction did pull away more of my attention than I ought to’ve allowed.\n\nAs a bit of a buzzer-beater against my self-imposed daily deadline of 12:00pm MT, I’ve decided to just publish this new blog format as-is. It doesn’t quite have the same style and zest as the original, but I’d rather put this out to encourage myself to improve it rather than let it languish in a “refactor” branch on GitHub.\nUPDATE: I did not beat the buzzer. It is currently 4:00AM the next day, and I am definitely not going to be deploying anything. Ironically, during this time I wrote the first posts about kicking The Gremlin and my Year of Rhythm, which is ironic considering The Gremlin certainly won tonight.\nNotes\n\nhttps://www.youtube.com/watch?v=0RFwyobtnKA\n"},"notes/dailies/2024-02-27":{"title":"2024-02-27","links":["notes/caveat-lector","notes/dailies/2024-02-26","articles/resume-ci-pipeline"],"tags":["csharp","python"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI didn’t get nearly as much C# done as I’d wanted to yesterday - while I’m a bit hesitant to say that “today is going to be a 100% effort day!”, considering how yesterday ended I’ve kept C# goals to a breezy middle-of-the-road, since I’d rather under- than over-set expectations.\nB-Block\n\nMore ChainSharp step testing.\n\nAs an aside, I think I’ve been dramatically over-complicating how I create separable PRs. This is one of my “Fuck, Theaux was right” moments that I increasingly have as I learn more C#. At some point, I’d like to do some gardening on philosophies for separable pull requests and commits.\n\n\n\nM-Block\n\nChecking on our internal project status - there’s likely tasks I can pick up, but my current work is the only very-large-web I have left to untangle (unless I’m forgetting something, which is likely.)\n\nE-Block\n\nToday’s E-block is a CGC day, so (sleep status pending) I’d like to work on actually taking what I have and uploading it to GitHub. This’ll mean taking a look at the Quartz build process.\n\nAnother aside - while I appreciate how much the developers of Quartz has made it user-friendly with a custom CLI, it abstracts away some of the usual development workflow and means I have to learn (and consequently fumble around with) a new thing. That said, I also don’t know jack shit about frontend development and there’s probably a good reason for that.\n\n\nOh, what’s this?? A friend of mine asked me to take a look over his resume. He’s still using the old LaTeX version of my resume template, so I’m real excited to get him moved over to the new Typst version (post pending). CGC blog stuff may get pushed back accordingly - not sure how high-capacity I’m feeling now at 5pm\n\nToday’s Report\nN/A\nNotes\n\nhttps://mypy-lang.org/\nhttps://github.com/apache/spark/blob/master/python/mypy.ini\nhttps://www.youtube.com/watch?v=xZYZEGHybqQ\nhttps://engineering.blackrock.com/static-type-checking-in-python-where-did-the-ducks-go-d17881d3205e - type hinting to static checks in mypy at a gradual pace\nhttps://github.com/kaiko-ai/typedspark Holy shit - it does exist!!\nhttps://typedspark.readthedocs.io/en/latest/index.html words cannot describe how excited i am??\n"},"notes/dailies/2024-02-28":{"title":"2024-02-28","links":["notes/caveat-lector","notes/dailies/2024-02-27","notes/dailies/2024-02-26","notes/putting-selfcontrol-on-raycast","notes/dailies/2024-02-25","tags/gremlin-kicking","notes/raycast-review"],"tags":["bash","csharp","gremlin-kicking"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nWhoops! Fell asleep at a reasonable hour yesterday, and didn’t get jack squat from my E-block done. That said, considering the day before, the sleep was very welcome. And - not to break my arm patting myself on the back - I did say that everything in that block was tentative.\nToday is pretty much the same thing as yesterday - ChainSharp does set things up in such a way that most work is “Today, I make another Step!” and that, plus not giving too many details for private projects, means that the B- and E-blocks for probably the rest of this week are not going to be too spicy and different.\nB-Block\n\nWorking on ChainSharp steps for private project\n\nM-Block\n\nWorking on ChainSharp step tests for private project\n\nE-Block\n\nThis… we’ll see. Today isn’t technically a CGC day - those tend to be Mondays, Tuesdays and Thursdays. However, yesterday was less than productive, so depending on my partner’s schedule (she may be going climbing) I’ll probably be staying in the office a bit later for CGC.\nIf CGC work happens today, current priority list (I should store these on an actual list app) is:\n\nResume reviews - 3 pending for two students and a friend\nQuartz deployment to GitHub Pages\nQuartz customization - likely a custom index page\n\n\n\nToday’s Report\n\n\n8PM Update: Hmmm… I think I’m going to pivot off of resumes. For an internal project, it’ll be in my best interest to get a bit of progress down on graph analysis & generation in TypeScript. I’ve already wasted (ironically) enough CGC time today on creating a SelfControl extension for RayCast. I think the reviews can wait until this weekend - likely Sunday, but I’ll try to get those done before then based on ✨ vibes 🌈.\nIdeally, I’d like to have a Jupyter-ish environment to prototype frontend - likely, this means picking up where I left off the other day with CodeSwings, and doing some horticulture on the TypeScript analog to Python’s Pandas/C#‘s LINQ, Data Forge.\n\n\n…\nOkay - so technically I did most of what I set out to do today. Left myself a bit of wiggle room on the E-block. Again. If you squint your eyes and tilt your head, foresight and unreliability do look quite similar.\nI have decided I’m very excited about the SelfControl on Raycast stuff. Of all the things that rattle around in my skull, the xkcd post about time saved vs time spent automating is the most rattle-y. After mulling it over (while i was doing it, which is the perfect time to second-guess yourself) I decided the juice was worth the squeeze if it means I can more reliably pull myself out of doomscrolls and death spirals.\nWhen it comes to the art of gremlin-kicking, I do think that Raycast is the greatest set of steel-toed boots I own. It’s not the worst thing in the world that they now have a bit more weight in the heel with SelfControl tacked on.\n\nI will, however, also admit that - in terms of deliverables - the squeeze also squoze(?) out some time for other things I was hoping to do today. Hopefully trimming the doomscrolling fat makes up the time soon. Other than that slight detour, my CGC priorities remain generally the same and some of today’s list will likely get recycled into Friday. Tomorrow will be a lighter report day - CGC work is taking a backseat to watching the new(ish) Mean Girls with my partner, and then likely cleansing our palettes with the original Mean Girls afterwards. Taking a backseat? Classic Regina.\nIn a buzzer-beater, I learned a bit about D3 and finally settled on how to use CodeSwings in such a way that I can have them interact with Quartz internals. Maybe I am a frontend guy?? 😎\n(i am not.)\nNotes\n\nhttps://github.blog/2024-02-28-how-were-using-github-projects-to-standardize-our-workflows-and-stay-aligned/ - perhaps Projects is actually becoming… good? What a time to be alive!\nhttps://www.rawgraphs.io/ - Implementation as Backstage Plugin or Electron App?\nhttps://github.com/rawgraphs/rawgraphs-app - unfortunately not the type of “app” i was hoping for.\nhttps://github.com/jessejanderson/skylink - would be nice to do a popup as an Arc boost\nhttps://github.com/raycast/extensions/tree/c524392d80b35348811bae59831f29bfdbc34432/extensions/youtube-music/ - I’d like to, at some point, look at forking & adding the ability to add a song to a playlist. the selfcontrol stuff was quite a gateway drug, although i’ll have to adapt to using TypeScript for extensions rather than creating shitty, poorly-tested bash.\n"},"notes/dailies/2024-02-29":{"title":"2024-02-29","links":["notes/caveat-lector","notes/putting-selfcontrol-on-raycast"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nOkay! With myself SelfControl’d this morning, feeling very optimistic today!! I think, today, I can finish up my part in the MVP of an internal project. As a treat, I’m going to take a closer look at tuning up our old Backstage deployment. I’ve been feeling a whole lot better about my TypeScript knowledge & workflows as of late - and my engineering in general - so taking another look at Backstage after ~8 months feels like it may be refreshing.\nB-Block\n\nFinalize MVP parts for internal project\n\nM-Block\n\nRe-clone and get Backstage local environment running\nLook into Backstage Plugins\n\nE-Block\n\nNone! It’s Mean Girls night, baybeeeeee 😎\n\nToday’s Report\n\nUPDATE 3PM: The SelfControl for Raycast integration was, in fact, worth the time spent. Today’s B&M blocks have been the most productive in probably 2-3 weeks 🎉\n\nSlight end-of-day, while I have the laptop open - we ended up stopping the new Mean Girls after about 10 minutes and just watching the old one instead.\nNotes\n\nhttps://kindavim.app/ - vim everywhere on macos. May automate some of the less-than-stellar shortcuts i’ve baked myself\nthere are few terms i despise more than “tribal knowledge.” at some point this will be written about.\nhttps://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca - Happy leap day!\nhttps://www.perkins.org/resource/how-write-alt-text-and-image-descriptions-visually-impaired/ - resource for writing alt text on images\n"},"notes/dailies/2024-03-01":{"title":"2024-03-01","links":["notes/caveat-lector","articles/binglish"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI think today is likely going to be lighter day, likely finishing up assigned work during the B-block - I have a couple last-minute touches to an internal MVP, but not sure to what extent my time is booked up for the rest of the day. May take M-block to do a bit of light research on Backstage plugins.\nB-Block\n\nQuick horticulture on (free) C# code coverage libraries\n\nM-Block\n\nBackstage horticulturie\n\nE-Block\n\nResume review - for real, this time!!\nActions/Quartz deployment\n\nToday’s Report\n\nUPDATE 3:00PM: Ended up writing an article about binglish, which is absolutely not what i had planned for the afternoon but i’m certainly not mad about it. from a quick cursory online search… i don’t think anybody else has coined this term yet?? At least not for the same concept - i was only able to find references to one chrome extension (ironic) and a somewhat(?) used term for british-indian-english (which, idk, maybe it’s far larger a term but not one that culturally/algorithmically would be at the tippity-top of my SLC-based search results, even on incognito) \nUPDATE 6:00PM: i was excited enough about that post to actually publish my blog. I was about to excitedly hyperlink to it, but… I suppose this will actually be on there now. There is something about seeing what i’ve been putting into a dusty refactor/ branch on GitHub actually be on The Internet™ that… I’m frankly not certain how to feel about.\nThere is something burning in me to really quickly learn everything more i need to know about TypeScript frontend development and finish the blog formatting posthaste, but I think that will need to wait for another time. I am hungry, and must depart.\n\nSee above - stopping CGC work and closing my laptop for the day. Perhaps I will play… Factorio???\n🫡\nNotes\n\nhttps://www.hanselman.com/blog/altcover-and-reportgenerator-give-amazing-code-coverage-on-net-core - Free code coverage for C#. Uncertain about Rider compat >:l\nhttps://youtu.be/_wxU3z9VxOY?si=Y2vuh_PH5_yHay9m&t=267 - suavemente\nhttps://kyla.substack.com/p/why-we-dont-trust-each-other-anymore - words, words, words (literally and topically)\nhttps://open.substack.com/pub/kyla/p/why-we-dont-trust-each-other-anymore?selection=f9b3b76b-bbe1-46c1-87f0-57b3d84594b1&utm_campaign=post-share-selection&utm_medium=web - poetry isn’t usually my thing but this got me\nhttps://smartbear.com/learn/code-review/best-practices-for-peer-code-review/ - Study on Pull Request ideal review size. I have no idea how big PRs should be and it falls into the same “economic value of lines of code” issue that I’ve looked at before. There’s lots of metrics - lines changed? files changed” feature count? subfeature count?\nhttps://smallbusinessprogramming.com/optimal-pull-request-size/ - More research resources I need to take a look at. Someday I will have an opinion.\n"},"notes/dailies/2024-03-02":{"title":"2024-03-02","links":["notes/caveat-lector","tags/roblox","notes/dailies/2024-03-01"],"tags":["scratch"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday wasn’t actually a CGC day, but I’m finding myself with some time at the tail end of the day after some sudden super-fun springtime winter storms have floated across Salt Lake City and tanked my plans to get tastefully wine blasted tonight.\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\nToday was my partner’s first swim meet since she did triathlons in college! she did incredibly well - I wish that I knew more about photography so I could take cooler pictures of her when she’s swimming that we can send to our families. Maybe, someday, I’ll be a Photography Guy™.\nI ended up sitting next to a very nice group of kids. I had brought Kenneth Arrow’s The Limits of Organization - with no irony in the slightest, I put it away after seeing that the two kids next to me were reading objectively cooler books. They were very nice - we talked about video games and programming and played Exploding Kittens between meet heats. I cracked open my laptop and they showed me a few programs they’d made in Scratch, which brought back some memories of working with 4th-6th great students at Dr. David Johnson’s GREAT Camp back when I was a sophomore in college.\nSince teaching both that camp and working as a center director at a local Mathnasium for about a year around the same time, it’s been awhile since interacting with Modern Youths™, save for a few niche Roblox communities I lurk in for CGC-tangential projects. It is very cool to see how this generation (gen Alpha? i haven’t kept up much with the newfangled terminology around this generation) has a more… native? approach to technology. It makes sense, considering there will probably (hopefully) never be a moment they go without it.\nThey brought up roblox and I mentioned I’d played when I was their age - the oldest asked a few questions about moving from the block-based coding on Scratch to text-based coding. I feel it is a more interesting question than I was willing to inundate him with (i said “not really!” and capped it off at that.) - in hindsight, it was a pretty big transition for me. That said, I wonder if there exists a future where block-based coding comes back in a way, made possible by stronger generative code solutions to handle minute details within blocks. \nUnironically, I do think I would appreciate a graphical, scratch-like interface for cloud environments. That would be a pretty kickass Terraform frontend.\nAs a slight update on yesterday’s post about binglish - I did post it in a few places (and it didn’t even go viral??? shocked, offended, confused). I think the only piece of text feedback I got was in the Quartz discord, where somebody mentioned that albeit funny the term was one they were familiar with as a colonist term for British-Indian-English.\nI’m torn - by no means is this a Big Thing i’m doing with this blog, nor do I think it ever will be. Certainly not to the extent that the Venn diagrams of people who would read my notes and who would recognize “binglish” in that context would overlap. I also don’t know how I would go about checking - it is interesting that geography is a somewhat soft lock on that kind of cultural knowledge. Even from setting my VPN to Delhi, popping my browser into incognito and doing a (translated, obviously) search, I still get a “urban dictionary,” “stop trying to make fetch happen” vibe from the term. I’ll keep the post up purely because i like it (everybody, appreciate me!), but if that ever does become An Issue™ i will absolutely reconsider that decision.\nNotes"},"notes/dailies/2024-03-03":{"title":"2024-03-03","links":["notes/caveat-lector","notes/scratch/warning-about-slabtops"],"tags":["hardware","engineering"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday is a bit strange - I’m currently on a kick of only gaming with friends (gaming solo, for whatever reason, has started to feel like “wasting time” (which is totally not a statement on the virtue of solo gaming, this is just how I feel about it at the moment)). After a bit of a misadventure trying to turn an old laptop into a well-ventilated server, a friend’s brother very graciously offered me some spare PC parts he had lying around so I could (properly, this time) start a home lab for running miscellaneous things, such as dedicated multiplayer servers at my home.\nI highly doubt any CGC work will get done today - I’d vastly prefer setting up the server and playing around with some homelab setup experimentation.\nB-Block\n\nPick up desktop case & parts\nClean out, assemble desktop case & parts\n\nM-Block\n\nPick up a new bed frame for a new mattress arriving later this week\n\nE-Block\n\nAssemble bed frame\nWork on desktop server\n\nToday’s Report\nVery minor EOD report - was able to get a Windows Proxmox setup with GPU passthrough and VirtIO set up today. With the addition of Moonlight & Sunshine, game streaming is now possible! I cannot wait to use this to bully invite my partner to join in game nights with us, now that we have a dedicated(ish) Windows machine for her to use.\n\nBy no means is running Lethal Company at a consistent HDx60fps a technological marvel, but I am very satisfied with the work tonight. While my Steam Deck is probably going to still be my go-to because I hate myself and love debugging, this was a fun little tangent.\nAs an aside - a lot of that setup was cobbling together random support forum posts and other weird shit - at one point I spuriously bought a pack of headless HDMI dummies from Amazon thinking I’d need them. I’d like to toss a quick note here at some point this week to elaborate on some of the missing steps between major guides.\nFuture work on the server (beyond just hosting multiplayer servers) will likely be looking at some actual capital-H-capital-L HomeLab stuff like HomeAssistant to bridge some of our disparate smart home devices into HomeKit so I can control them from my phone and computer a bit easier, but that’s for another night.\nNotes\n\nhttps://forum.proxmox.com/threads/pci-gpu-passthrough-on-proxmox-ve-8-windows-10-11.131002/ - okay, this one actually works.\n"},"notes/dailies/2024-03-04":{"title":"2024-03-04","links":["notes/caveat-lector","notes/season-of-rhythm","notes/dailies/2024-03-03"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nBack to the work week! We haven’t had sprint planning, yet, so I’m not totally sure what today/this week has in store quite yet - I’ll loop back around and update blocks once I have ‘em.\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nSo, this particular report goes… well into tomorrow. I’ve been doing pretty good on my sleep rhythm lately, so let’s consider this 6:00AM posting a bit of a relapse.\nI need to get… a couple hours of sleep before I need to be up in the morning, especially considering it’s my partners birthday(!), so this’ll be a brief EOD. I will personally blame whoever it is that made this amazing set of proxmox LXC setup scripts for stealing my sleep tonight, in order to properly divert blame away from the true culprit: myself.\nNotes\n\nuhhhhh… quite the fuzzy match there, YouTube Music?\n\nhttps://gersom.nl/building-a-raycast-website-blocker - raycast blocker similar to Self Control\nhttps://www.raycast.com/tonka3000/homeassistant/commands - raycast extension for HomeAssistant, which is relevant to yesterday’s knock-on work\nhttps://docs.github.com/en/actions/managing-issues-and-pull-requests/closing-inactive-issues - action for closing stale issues, PM req\nTODO: Look up use of new on class method declaration in C#\n"},"notes/dailies/2024-03-05":{"title":"2024-03-05","links":["notes/caveat-lector"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday ended up being a sick day (for both myself and my partner, which unfortunately coincided with her birthday), so not much got done. Not good, not bad - not really sure how to feel about it. At the moment, it’s a bit dour.\nB-Block\n\nR&R\n\nM-Block\n\nR&R\n\nE-Block\n\nR&R\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\ni do appreciates some rest and recovery. in storywriting terms, we’d probably call this one a bottle episode.\nNotes\n\nhttps://tteck.github.io/Proxmox/ - Proxmox helpers\nhttps://arxiv.org/pdf/2403.01152.pdf - research on current generative AI forensics solutions\n"},"notes/dailies/2024-03-06":{"title":"2024-03-06","links":["notes/caveat-lector","notes/dailies/2024-03-04","notes/utah-office-consult","notes/supply-chain"],"tags":["aws"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI think today’s plan has me diving back into the wonderful world of DevOps, testing out internal DNS capabilities for development resources within VPCs. Thankfully server bullshit the other day has gotten me in a Domain Name State of Mind.\nI think E-block today is going to be fixing up the homelab server. I took apart all of the pieces to clean them but (from what my partner has told me — oops!) there’s a fan in there that isn’t balanced and constantly clicking, so it’ll be some investigating there.\nAlso excited to put in a couple extra pieces - I bought a cheap burner card (GTX 1030 for like $60) to dedicate to video encoding/decoding, along with a few other here-and-there parts to expand storage slots. So long, 256GB storage!\nB-Block\n\nStarting on internal AWS DNS module for Account Factory Terraform\nWhile I’m in DevOps land, I kinda want to take, like, 30 minutes and follow up on a weird concept I read about awhile back - unit testing Terraform code. I don’t totally understand how one would unit test… infrastructure configurations? but who knows, maybe it’ll blow my mind\n\nM-Block\n\nMeeting up with our PM to talk over some developer experience stuff - people problems are truly the hardest engineering problems\n\nE-Block\n\nN/A - I’m hanging out with my partner tonight, but depending on how long her plague-ridden body can handle doing things, I may do some hardware stuff tonight on the homelab server.\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes\n\nI’d like to eventually make the viz from the utah consult post a follow-up to the supply chain network post as an intro to that one guy on bluesky’s network graph viz guide\nhttps://apps.apple.com/us/app/proxmobo/id6447794447 - Proxmox mobile interface - very nice, 10/10 would recommend\nhttps://medium.com/@giuliodn/clone-and-backup-with-gparted-e1100219c1d7 - notes on transferring contents between hdrives with gparted\n"},"notes/dailies/2024-03-07":{"title":"2024-03-07","links":["notes/caveat-lector","notes/dailies/2024-03-03"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday’s plan is a bit more DevOps for work, and then some spring cleaning. Working on the new homelab server has, safe to say, unearthed a substantial amount of old hardware I had laying around in a box. If I don’t tidy up the living room, I may end up getting strangled in my sleep.\n\nThat said, the cat has fuckin’ loved the chaos. So many wires to attack - so little time between naps.\nB-Block\n\nCategorizing internal services into the internal LB/DNS\n\nM-Block\n\n\nLooking into GitHub Projects workflows through Actions. Yesterday was some messing about with actions/stale to manage some… pretty large batches of tickets at work. While this has seemed to do the trick so far, there was the realization that our current automation system would move all of the closed, stale tickets to our QA team.\nThere is currently a rolling boulder of about ~250 tickets slowly rolling towards our QA team that will squish them in 14 days’ time. God save their souls.\n\n\nE-Block\n\nSpring cleaning and playing around with the new dedicated GTX 1030 burner card in the homelab server\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes\n\ntest!\n"},"notes/dailies/2024-03-08":{"title":"2024-03-08","links":["notes/caveat-lector"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nN/A\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes"},"notes/dailies/index":{"title":"Daily Notes","links":["notes/caveat-lector","notes/digital-gardening-with-quartz"],"tags":[],"content":"These are daily notes, where I log and track progress on ongoing projects and make notes for myself later. These are largely for my own benefit, and are here in case they’re helpful to myself (or, somehow, others) in the future.\nHowever, I’d describe these as loose, at best. Caveat lector.\nOne of the approaches to digital gardening is “learning in public” - to that end, I plan on continuing to outwardly publish these."},"notes/digital-economies":{"title":"What is a Digital Economy?","links":["notes/stability-of-marriage"],"tags":["economics","data","engineering"],"content":"Digital economies are primarily-online economies that you might find in multiplayer games, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications. Digital economies are interesting - to me, at least - because the digital medium they behave in offer incredible opportunities for creating, researching & understanding market designs, enforced by digital systems, that you may not find in the real world.\nDespite being digital, they are very, very real."},"notes/digital-gardening-with-quartz":{"title":"Kicking off a Digital Garden with Quartz","links":["articles/structured-streaming","articles/hello-blog"],"tags":["engineering","typescript","gremlin-kicking","horticulture"],"content":"I’ve decided that I’m pretty bad at capital-B Blogging™. The last “post” I made (as of writing) was the Databricks guest post on Spark Structured Streaming that I did back when I worked at M Science in 2022. That particular post went through a few different stages of revisions:\n\nRevising initial drafts as I learned more about Structured Streaming as a concept\nRevising “personally final” drafts with the Structured Streaming engineering team at Databricks\nRevising “technically final” drafts with somebody from our company’s internal marketing team to make sure I didn’t sound like a doofus/didn’t make it seem like the company hired doofuses (it hired me, so it totally did, but that’s obviously not something to broadcast openly)\nRevising the “marketing final” draft with a lawyer to make sure I wasn’t blabbing trade secrets to the general public\nRevising the “legally final” draft with Databricks’ blog team to make sure the formatting was right (which I didn’t do a good job of, apparently - the final published draft ended up having some weird formatting errors. Not totally sure what happened there ¯\\(ツ)/¯ )\n\nThat was quite a bit more than I’d expected when initially pitching “What if we published our internal guide for everybody?“. That, along with starting a new job that introduced me to a far higher standard for engineering, raised my own internal bar for “what should I put on the internet?” Since then, I’ve written quite a few posts that I’d describe as ~60% “done,” but didn’t end up hurdling internal (and arbitrary) bar for publishing.\nConsidering the editorial standards I started this blog with, the idea that I’ve had any bar at all is a bit funny.\nThe cost of learning is teaching\nAs somebody that has benefitted immensely from the free body of knowledge that exists on the internet, this doesn’t make me happy. A graveyard of posts I’ve arbitrarily deemed “unfinished” isn’t particularly helpful to anybody, including myself. Just because a set of knowledge isn’t refined enough to be perfectly, 100% clear to a broad audience doesn’t mean it wouldn’t be helpful to somebody, including myself in the future.\nI was fortunate enough to stumble on Maggie Appleton’s Ethos on Digital Gardening, which notably resonated with me more than many things I’d read in the recent past. In particular, this diagram she designed clicked something in my brain that’d remained un-clicked for quite awhile:\n\n\nbrief aside: Maggie brings a level of polish and class to doodling that is frankly enviable.\n\nThe cost of perfection is infinite\nPutting things on a spectrum of “chaos” to “cultivated”, in conjunction with the idea that “the cost of perfection is infinite” (if not asymptotic), puts into hardly-uncertain terms that simply because a thing is not perfect, or close to it, necessarily means that it is unhelpful and should die a slow death in a draft bin.\n"},"notes/index":{"title":"Notes","links":["articles/","notes/dailies/","notes/scratch/"],"tags":[],"content":"These are notes - they’re things that are structured, albeit not necessarily as structured or refined as CGC articles.\nIn general, there are three kinds of notes I make:\n\nGeneral notes, which are found on this page\nDaily Notes, which contain daily logs for my own benefit\nScratch Notes, which really just means “none of the above”\n"},"notes/literal-scratch-piano":{"title":"From the Archive: Scratch Piano Application","links":["notes/dailies/2024-03-02"],"tags":["engineering","mentoring","scratch"],"content":"Back in 2018, I taught at the GREAT Camp at the University of Utah as an instructor for ~4th-6th grade students interested in intro programming in Scratch. Honestly, as a CS student at the time, it was actually really cool to try and put things I’d made in actual languages and translate them into Scratch, especially if they required manually implementing data structures like stacks and heaps.\nThis was a fun project to try and explain music - something that every Utah child learns, short of by-law - and also a way to cope with the fact that in Spring of 2018 I’d unintentionally signed up to take a weed-out Intro to Music Theory course at university.\n"},"notes/literal-scratch-quicksort":{"title":"From The Archive: Scratch Quicksort","links":["notes/literal-scratch-piano","notes/dailies/2024-03-02"],"tags":["engineering","mentoring","scratch"],"content":"As an addendum to the Scratch Piano Application, I also around the same time cooked up an implementation of QuickSort. At my partner’s recent swim meet I sat next to a couple kids who’ve been learning Scratch and they were showing off some games they’d made.\ni was shocked - when it was my turn to show off, they didn’t seem very impressed by this.\n\nhonestly, the sort isn’t the weird thing - it’s the code itself that makes me, with 6 years of hindsight, think “…why the fuck would I make this?”\n"},"notes/over-under-engineering":{"title":"The Over/Unders of Over- and Under-Engineering","links":["notes/digital-gardening-with-quartz","notes/over-under-engineering","tags/python","articles/structured-streaming"],"tags":["engineering","gremlin-kicking"],"content":"\n\n\n\nPremature optimization Over-engineering is the root of all evil\n— Donald Knuth\n— Sir Tony Hoare\n— Me, just now\n\n\n\n\nI think that over-engineering is the single greatest contributor to starting projects and never finishing them.\n\nLet’s define follow-through rate as the ratio of projects started to projects released. Not “completed”, since that’s an irrational way to think about projects.\n\nLooking back at periods of my life, I feel like my follow-through rate on projects was highest when I was 12 years old. At that point, my “projects” were:\n\nMy grades in high school\nWriting shitty programs on my TI-84\nWriting small games on Roblox\n\n13 years is long enough ago that, for the sake of simple math, my follow-through rate was 100%. Gee, what a reliable kid I was!\nI can name 4 periods of my life where the amount I learned about engineering grew at a more-rapid-than-usual pace:\n\n2016: I began studying computer science in my undergraduate\n2018: In trying to build up my resume, I started taking writing open-source and release-able projects more seriously\n2020: I got my first full-time job as a data analyst/software engineer writing data pipelines in Python and Spark\n2023: I got my second full-time job writing general software in [[csharp|C#]], with incredibly smart capital-E Engineers™ that were also incredibly good mentors\n\nWhile it feels great to know more, learning has caused me a fundamental issue: it’s easier to be bad at something on accident than on purpose.\nI’ve increasingly noticed myself trying to apply the things I’ve learned to new projects, causing a whole lot of up-front work to get a project started. Putting yourself in a prison of making the “best” choices at the very start of the project is incredibly demotivating and absolutely tanks the odds that a project started will someday be a project finished. Ironically, it’s future-proofing for a future that doesn’t happen.\nLet’s say, hypothetically, that my project follow-through rate started at 100% and dropped by a third following each learning period. After 4 learning periods, that would leave me at…\n(1.00−0.30)5=0.16\nYeesh. 16% follow-through rate sounds rough, but when I look at a recent history of what I’ve accomplished versus what I’ve wanted to accomplish, the number seems somewhat reasonable.\n\n"},"notes/putting-selfcontrol-on-raycast":{"title":"Watering Down SelfControl into Self Restraint","links":["notes/putting-selfcontrol-on-raycast","notes/season-of-rhythm","notes/arc-review","notes/the-quest-to-kick-the-gremlin","notes/raycast-review","notes/caveat-lector","notes/dailies/2024-02-28"],"tags":["gremlin-kicking","engineering","bash"],"content":"\nI talk a lot in this post. You may want to skip to the useful part.\n\nSo, during this recent period of trying to break quite a few years of bad work habits, I’ve been putting up little guardrails in my own life to keep myself on-track when I want to stay on-track. One issue I’ve run into - especially during a particularly tumultuous US election year - is a tendency to check the news.\nAnd then, five minutes later, check the news again.\n…and again\n…and again.\nI’ve rationalized it for awhile by saying “I work in politics - of course I should stay up to date!” However, that’s a lie - my day job is not in politics. At best, It’s working on software adjacent to people who are adjacent to politics.\nTo alleviate that for awhile, I had used a Chrome-specific app called StayFocused to block a pretty broad swath of websites, but ran into two issues:\n\nStayFocused allows you to schedule blocks, but only for predetermined amounts of time, and only a single block per day. This was not quite as flexible as I was comfortable with - I do like to check the news, my email, or Bluesky at lunch, or if I get off of work a bit earlier than expected.\nI started using Arc Browser with three different profiles - Personal, Work and CGC - and each one has its own Chrome plugins. Because of this, I’d have to configure/reconfigure/update the StayFocused installation in triplicate, which due to the way their app is set up is incredibly hard to do.\nTheir app kept hijacking my browser to notify me of updates, and I didn’t see a readily-available way to do that. Ironically, this had the effect of absolutely shattering my focus.\n\nI ended up uninstalling it and going with something a bit heavier-duty. SelfControl is an application for MacOS that blocks out apps across the entire operating system. I had also seen Focus listed as a possible solution, but… $49? For effectively the same thing with a prettier interface? yeesh.\nIronically, though, SelfControl requires self control to use, which is exactly what got me in this situation to begin with. It is incredibly easy to “take a break” and then just-a-couple-more-minutes yourself out of any semblance of flow. As a nice surprise, though, SelfControl comes with a CLI, which means we can use it for some more advanced workflows! We can use this to do two things:\n\nSchedule blocks of self-control for the future, e.g. “In 10 minutes, I will focus for 50 minutes”; and\nConnect that behavior to Raycast, which will help us lower the bar to starting Raycast (as, admittedly, having to swipe back to the main Mac desktop is a pain in the ass and puts it out-of-the-way)\n\nThe Useful Part\nI’ve added a couple of useful bash scripts to a SelfControl Raycast Plugin for others to use. At some point, I’ll look into the process for getting them added to the actual Raycast extension store. You can add these by cloning the repository and adding it in the Raycast settings as a “Script Directory.”\n\nTHAT BEING SAID: I’ve used the term caveat lector quite a bit to warn people that I’m just some guy. This goes doubly here! This is software that has literally only been tested, by me, a handful of times, that I made while (ironically) procrastinating other things I should be working on. To say it isn’t well-tested would be a dramatic understatement. The creators of SelfControl warn that it’s a tool that, if misused, can have side effects. So to that end… what would the phrase even be?\n\nHuh. I guess the Romans didn’t do much file sharing.\nCaveat download!"},"notes/qamo":{"title":"Quantitative Analysis of Markets & Organizations","links":["tags/economics"],"tags":["economics"],"content":"In 2022, I graduated from the University of Utah with a degree in Quantitative Analysis of Markets & Organizations (QAMO, more-or-less quantitative economics).\nWords cannot describe how much I appreciate the mentorship I received from my professors - especially Scott Schaefer, the program director who was incredibly kind in providing a level of flexibility that, frankly, was the only reason I was able to graduate while working full-time.\nThat said, I do wish the name of the degree wasn’t such a pain in the ass to type out."},"notes/raycast-review":{"title":"Diary of a Raycastaway","links":[],"tags":["gremlin-kicking"],"content":"Recently, I stumbled on Raycast - a MacOS Spotlight replacement that I would highly recommend to everybody, not just engineers."},"notes/robloxaville-remaster":{"title":"Thoughts on the bad 2017 Robloxaville Remaster","links":["articles/robloxaville","notes/over-under-engineering","notes/digital-gardening-with-quartz"],"tags":["roblox","lua","games","engineering"],"content":"When I was in high school, I dabbled a bit in programming on Roblox. Due to some pretty glaring security concerns, a project started over the summer of 2017 to remaster Robloxaville. I’ll be the first to admit that the remaster is substantially less fun to play than the original. While part of this constraint was time - the original was made over the course of ~4 years, while the remaster was made in ~3 months - it’s undeniable that the velocity of the original project was simply far higher because it was under-engineered.\nThe original project was largely made by my mom, who studied programming during her physics-chemistry-geology triple(!!!) major in college, with some tangential work from me, who was a literal child. Not to sell short the sheer amount of work she put into the project, but between a lack of formal software engineering and the pretty glaring shortcomings of the Roblox engine itself meant that, frankly, it would’ve been impossible to engineer any of it properly to begin with. By the time the summer of 2017 rolled around and the remaster started, two circumstances collided:\n\nPlatform developers were now being paid, which introduced a far higher bar on quality of work being done\nI had just finished my first semester of a degree in computer science and learned tip-of-the-iceberg concepts of what constituted “good” software.\n\nDespite happening 7 years ago as of the time of writing, I remember how absolutely stressful that summer was. I spent wasted a lot of time worried that the code I was writing wasn’t engineered enough, and ended up designing a lot of bad and convoluted systems meant to save myself time in a future of development on that project that never came.\nThere exists a graveyard of projects and posts between 2017 and today that have fallen victim of arbitrary bars for under-engineering that I’ve put on my own work."},"notes/scratch/brevity":{"title":"brevity is no longer the soul of wit","links":["articles/binglish"],"tags":["horticulture"],"content":"when he wrote “brevity is the soul of wit”, shakespeare clearly did not consider that someday AI generated briefs would consume the english language"},"notes/scratch/index":{"title":"Scratch Notes","links":["tags/horticulture"],"tags":[],"content":"For all intents and purposes, these are the digital gardening equivalent of shitposts and shower thoughts."},"notes/scratch/press-f-to-commit":{"title":"Press F to Commit","links":[],"tags":["visualizations"],"content":"A friend of mine - who is one of the most consistent people I know - was called in over the weekend for an emergency patch deployment at work.\nThe weekday streak is over; long live the weekday streak!\n"},"notes/scratch/some1-entry":{"title":"Entries to SOME 1","links":["notes/stability-of-marriage"],"tags":["doodles","economics","visualizations","python"],"content":"Awhile ago, the channel 3blue1brown announced an internship and public competition, Summer of Math Education - at the time, I submitted some half-assed entries that I’ve kept around since then.\nBachelor Analysis\n\nExcerpts from Stable Marriage\nLargely taken from a presentation on stable matching algorithms\n\n\n\nOptimal Stopping Problem\n"},"notes/scratch/the-best-side-of-the-road":{"title":"What is the best side of the road to drive on?","links":[],"tags":[],"content":"\nThe best side of the road to drive on is the side everybody else has agreed to drive on.\n\nI don’t remember where I first heard this, but I think about it every day."},"notes/scratch/unstable-marriage":{"title":"Unstable Marriage","links":["notes/stability-of-marriage"],"tags":["economics","data"],"content":"I’ve spent a whole lot of time researching matchmaking algorithms, and yet I’d never considered - didn’t even mention in the presentation - what would happen in odd-numbered sets.\nthe implications are frankly funnier than I would have imagined"},"notes/scratch/warning-about-slabtops":{"title":"Before You Slabtop Your Laptop: A Brief Warning","links":[],"tags":["engineering","hardware"],"content":"I recently had a misadventure while trying to slabtop (remove the LCD panel of a laptop to use it as a server) an old Dell Alienware G2 15. I didn’t see this piece of friendly advice while Googling around before making my attempt. I really wish I had - it would’ve saved me a lot of time, trouble, and a motherboard to boot (pun intended).\nTo contribute to the body of all knowledge, I hope you (you, the person googling “how to slabtop a laptop” right now) see this before you whip out the screwdriver and go to town on your old burner:\nSearch “<YOUR LAPTOP MODEL> LCD Panel POST Check Beeps” before you attempt to slabtop your laptop!!\nComputers run without screens all the time - we call them servers, and they run everything, so the possibility of a laptop manufacturer literally not letting a computer complete POST check without an LCD panel wasn’t even something that crossed my mind. However, if you google the above, you’ll run into lots of posts of people who hear a handful of beeps when their LCD display is disconnected, signifying that the POST process didn’t complete. This will absolutely fuck you over if your laptop manufacturer is one of the many who have this check in place.\nWhile I believe it is possible to do this on a PC (not a Mac, where slabtopping has been documented extensively), I personally ended up frying the motherboard after about 5 hours of cutting away at the stupid fucking thing. If this helps even a single person, I will be immensely happy."},"notes/season-of-rhythm":{"title":"Spencer's Season of Rhythm","links":["notes/the-quest-to-kick-the-gremlin","notes/over-under-engineering","tags/gremlin-kicking"],"tags":[],"content":"In the spirit of setting themes instead of resolutions, I’ve adopted a seasonal (or perhaps year-long - who knows?) theme for my own life:\nThe Season of 🎵 Rhythm! ✨\nDuring my Season of 🎵 Rhythm! ✨, I want to establish healthier cadences to how I spend my time day-to-day, and to be far more intentional with how I spend my time. This is largely a response to a broad problem in my life that I’ve felt for some time now.\nI am not a person who, at any point, has ever formed good, lasting, healthy habits.\nThrough high school, into college, and continuing into my adult life, I have always been a very “whichever way the wind blows” kind of personality. This hasn’t been entirely without its upsides. A coworker once described me as “very good to have in emergencies.” While I’d agree with that characterization, it’s because my tendency embrace The Gremlin has meant I have been a co-conspirator to many of the emergencies in which I’ve learned to work well under pressure. If you do enough work, enough times, an hour before a deadline, you become very good at doing lots of work with hours before a deadline.\nThe downside to this is… fairly obvious. In the last year, I started working for and with a very emotionally healthy team of engineers who are remarkable at pacing themselves, doing diligent and level-headed work, and avoiding emergencies when possible - something that drove me absolutely insane at times during my first year. After having seen - and felt - how much healthier this environment is and how much more it can accomplish - particularly in collaborative and non-competitive settings - I’ve accepted it’s the way I’d ought to work, too.\nAs an additional downside to the way I worked, only having a cohesive and consistent pace of work meant that larger projects - things that aren’t done in one all-nighter but have to happen over the course of weeks and months - had a tendency to fall into obscurity. I’d attribute some of that to the way I have structured many of these projects, but constantly losing the thread between bursts of motivation means that bigger plans can easily turn into aimless wandering.\nSeason of Rhythm is a time to actively, rather than passively, establish good “rhythms” and routines that lower the variance of my own work and habits. The goal isn’t to shed the “works well in emergencies” characterization - on the face of it, I don’t think that’s a bad thing. However, where I’d describe the previous variance of my own ability to function personally and professionally as a 25-50% pace during “peace-time” and 200-400% pace during emergencies, I’d vastly prefer to even this out to something that doesn’t feel like personal and occupational whiplash: maybe 80% day-to-day and 120% during emergencies, as a vibes-y estimate.\nAfter two months, I’m on a really good track. A whole lot of gremlin-kicking posts this year will probably be related to tools I’ve found that help me keep on track, and I’m excited to see how the trajectory of this next 4-10 months"},"notes/stability-of-marriage":{"title":"College Admissions and the Stability of Marriage","links":["notes/qamo","tags/doodles","notes/scratch/some1-entry"],"tags":["doodles","economics","python"],"content":"In college, my area of focus during my economics degree was non-market environments, which encompass the areas of economics where money isn’t used for moral or practical reasons.\nA presentation I’m particularly proud of is a presentation on David Gale and Lloyd Shapley’s 1962 paper College Admissions and the Stability of Marriage\n\nThis presentation happened at a personally odd time during a globally odd year, and - due to the practical limitation of only having my iPad available while I was in-patient at the University of Utah - was the first time I started using doodles in the vast majority of my presentations.\nThere are a few things that were cut for the presentation for time - in particular, the incredibly interesting concept of matchmaking lattices. Eventually, I’d like to include some additional written resources here on the topic, because it’s pretty cool. One of the cut slides is available here.\nThe absolutely incredible Dr. Allison Stashko is the only reason this presentation was possible - she was incredibly kind and encouraging during a difficult period, and is in large part the reason why non-market environments are my primary interest in economics."},"notes/strong-and-weak-opinions":{"title":"let opinion = null","links":["notes/strong-and-weak-opinions","tags/roblox","assets/Pasted-image-20240305234056.png","tags/python","notes/scratch/the-best-side-of-the-road"],"tags":["engineering"],"content":"\nThis note ended up having a lot of front-loaded context - feel free to skip to the point\n\nOpinionated Software\nThere’s a term that floats around that feels new. It’s not something that I’d ever seen in my computer science portions of my undergraduate, but as I’ve entered into industry and started both using and participating in development of a broader range of software, the sharp increase in frequency that I’ve seen this term:\n\n[Proper noun] is an opinionated [general noun]\n\nWhat… does this mean? I’d never seen it in an academic slide deck before, but I can name a few high-profile places in my own engineering. While it’s usually surrounding frameworks, I’ve seen it used in other places as well:\n\nDuring C# related work - I have previously used Wrapt as a [[csharp|C#]] web API scaffolding tool, which describes its default options as opinionated\n\nTo chase down a chain of opinions, Wrapt’s opinions are based on some of the Vertical Slice Architecture (VSA) opinions that I first saw from Jimmy Bogart’s post on VSA at the recommendation of my team at NWYC when I first started writing & contributing to commercial C# applications\n\n\nDuring roblox-related CGC work: “Flamework is a highly opinionated game framework”\n\nInterestingly, this description has since been replaced to say (as of writing) “Flamework is an extensible game framework.” - I thought I was going insane in trailing back after seeing that phrase there months ago and not finding it, but a stale Google Index reference shows that i’m not crazy (on this one). I am curious about the onus behind the wording change, because I do actually believe that new description better captures of the intent of the Flamework package.\n\n\nStumbling on the black python formatter while wrangling Databricks codebases at M Science\n\nThis is probably the most severe(?) case of opinionated software I’ve ever seen - it is literally named after the Henry Ford quote regarding available paint jobs for the Model T: “Any color the customer wants, as long as it’s black.”\nThe black repository is also home to one of my favorite GitHub Issues of all time, in which a senior staff engineer at Twitter requested the ability to configure 2-space tabs instead of 4-space tabs so that one of the most influential tech companies to ever exist could use it as the standard code formatter for their entire Python code base, to which the reply was a resounding “no.”\n\n\n\nAnybody who has ever seen the flame wars in the comments of Reddit threads, StackOverflow posts, or - frankly - between any call between more than, say, two engineers in the same field, opinions tend to run strong.\nWhen strong opinions collide, it can feel very much like watching an unstoppable force hit an immovable object. Especially when I was a data analyst on the way up to software engineering, I often found myself a junior (and rightfully silent) participant in long-winded, fruitless, and ultimately destructive conversations in which two parties who hold strong opinions talk past each other for… 10 minutes… 20 minutes… an hour, ultimately ending because one side or the other has to hop into a different call of the same flavor.\n(Want a real life example? Go ahead and pop “is <PROGRAMMING LANGUAGE A> better than <PROGRAMMING LANGUAGE B>?” into your search engine. One of my strong opinions is that 99.9% of those conversations are bullshit, wasted time, and that seeing them in the wild makes me want to close my laptop and walk into the ocean, my final thought before the air depletes from my lungs being that, at the very least, my decomposing body will contribute more back into The Universe than those people did by arguing complete fucking nonsense on the internet.)\nI think the way people sometimes approach having an opinion - or not having an opinion - is ultimately reductive, destructive, and slowly chisels away, bit by bit, hundreds of thousands of minutes, hours, and days of human life to the behest of our goals yet delight of the Reaper himself.\nThe Point\nI’m proposing, here, a way to a) properly classify your opinions and b) how to use those classifications to lead actually constructive conversations with others\nI put my own opinions into two categories:\n\nStrong Opinions: Opinions that I have built up over time and experience, and that I feel I have a compelling case for that clearly communicates the full scope of costs and benefits to the decisions that opinion leads me to propose\nWeak Opinions: These are the ones that I have that are built on sub-par information, that I can’t clearly communicate, or that are generally based on ✨ vibes 🌈\n\nWhen contributing to a conversation or argument on a topic, I’ve been trying really hard to ask myself: “Is the opinion I’m about to state a strong opinion?”\nHaving a weak opinion on a topic doesn’t necessarily mean it shouldn’t be mentioned at all. It does mean that it’s likely a point that, should somebody else have a stronger opinion, that opinion isn’t a hill I should consider dying on.\nThat said, having a strong opinion also doesn’t necessarily mean it’s something I ought to be doubling (or, god forbid, tripling down on). Especially when in a conversation with more senior engineers - which, at the current stage of my career, is vastly more likely - a strong opinion is one in which I ought to present my best case, rationale, and analysis in the hopes of reaching consensus.\nEven if my case for one of my strong opinions fails to reach a consensus - or even convince anybody, which does happen (sometimes a lot) (most of the time) - that isn’t failure. Ultimately, as I’ve gotten further into my career and seen a broader range of opinions reach a broader range of success or shortcoming, my approach has ultimately fallen back to:\nThe best side of the road to drive on is the side everybody else has agreed to drive on.\nNo matter how strongly you might feel one way or another, never underestimate the power of consensus. Either way, the outcome to accepting consensus is positive:\n\nYour opinion ended up being the way to go in hindsight and you’ve gained experience to make a better case the next time it comes up; or\nThe consensus opinion goes perfectly fine, you achieve your goals, and have gained experience on which you can build new, better-informed opinions.\n\nA final open letter\nI’ve noticed, in working with others, that the above classifications can somewhat freak people out - especially if they’re used to working with Strong Opinion People™, because how quickly I’m willing to roll over on my weak(er) opinions has the potential to come across as misunderstanding or apathy.\nAs an open letter to people in the future that see me do this, I make you this promise: when I quickly fold on an opinion, it is far more likely that, in that moment, I feel there’s more value in reaching a consensus and moving forward with any opinion than trying to force through a bad argument for a strong argument or a null argument for a weak one. At this point in my life, I am more interested in making progress than being right."},"notes/supply-chain":{"title":"From the Archive: \"What *are* Supply Chains, Anyway?\"","links":["tags/visualizations","notes/caveat-lector","notes/qamo","contact"],"tags":["python","economics","visualizations"],"content":"Below, you’ll find some graphs. These are what is known in the field of data visualization as “bad.”\nThese graphs are (as far as I can recall) my first attempts at using & visualizing network structures. As much as I would like to say they’re not too bad for a first attempt, they don’t “speak for themselves” as much as they “scream torments in the face of the viewer.”\nThe below graphs are stock tickers, connected to one another by their supplier relationships. For example, if Company A publicly noted that they received supplies from Company B, that would be denoted by a connecting edge.\n\nBelow is my first (and only) attempt to organize the above output. If I’m recalling correctly (and this was in 2019, so caveat lector), this was at least an attempt to get the first-order to third-order suppliers of a given set of equities and place their order in shells around the center. It’s messy, it’s noisy, and frankly, incomprehensible.\n\nThe hope of this analysis was to ultimately connect supply chains and, as a secondary goal, find graph cycles among a set of target stocks to find and catalog “supply loops”, and see if stocks in a given supply loop rise and fall together. The visualization acted more as a sanity check to see if my web scraper was working and less of a rigorous tool for understanding.\nDespite my area of focus being the parts of economics that aren’t related to either studying (or making) money, this is something I’d like to return to again in the future. However, I unfortunately don’t have the same level of data access that I did as an undergraduate, and purchasing access to a Bloomberg terminal falls well outside the financial means of CGC. However, if you’re ever looking for somebody to make bad graphs pro-bono and do have access to that kind of data, please feel free to reach out."},"notes/the-quest-to-kick-the-gremlin":{"title":"The Quest to Kick The Gremlin","links":["tags/gremlin-kicking","notes/caveat-lector"],"tags":["gremlin-kicking"],"content":"I am terrified by how quickly, without structure and habits, my life devolves into a cycle of sleeping, eating, procrastinating, and repeating until the visage of death sweeps me from this mortal coil.\nThis cycle is called “The Gremlin”\nI hate The Gremlin. The Gremlin makes me sad. The Gremlin stops me from doing the things that make me happy. Every day, I have to actively re-remember how much I hate The Gremlin, and how much happier I am when it’s gone, so I try my best to kick The Gremlin.\nI also hate the word “productivity.” There’s a sort of LinkedIn-centric slice of society that has built up the neutrality as an honest days’ work as a divinely-capitalized entity: Productivity™. It elicits (in me, personally) the visceral feeling I get when I see hustle-culture, rise-and-grind, success-is-a-choice-and-failure-is-your-fault types - the ones that farm for engagement by repeating gross approximations of quotes from self-help books that have been Human Centipede’d from one hustler to another. \nThat being said - productivity tools are some of my most reliable Gremlin-kicking weapons. This leaves me feeling very conflicted. Absent the weird Soylent-chugging culture that has formed around capital-P Productivity™, I would be in (and have been to) a really rough place without the productivity tools and habits I’ve tried my best to use and form in my quest to kick The Gremlin.\nAs a transparent act of shoving this internal inconsistency into the box in the back of my skull labelled “Don’t Think About It!”, I’ll be using the gremlin-kicking tag to denote posts about productivity and productivity tools.\nIn these posts, I’ll talk a bit about the structures I put up in my own life, and the tools I use to enforce those structures. To some degree, gremlin-kicking posts exist because I hope it might help another person who has their own Gremlin to kick and is looking for new tools to kick it. To a far greater degree, they’re here because the act of writing it down helps me set these structures in stone for myself. It is surprisingly easy to forget about good habits when, some day in the future, they’re no longer the habits they used to be.\nCaveat lector - you are you, and I am me. Some of these posts may resonate with you, and some of them may not, because different people are different."},"notes/time-tracking":{"title":"Some initial thoughts about time tracking","links":["notes/season-of-rhythm","tags/gremlin-kicking"],"tags":["gremlin-kicking"],"content":"Time-tracking is one of the tools I’ve picked up during my Year of Rhythm and gremlin-kicking. I’ll probably write about it more, here, later."},"notes/utah-office-consult":{"title":"From the Archive: \"Utah Office Consult\"","links":["notes/scratch/the-best-side-of-the-road"],"tags":["consulting","visualizations","python","data"],"content":"\nThis presentation is one that I did for an organization I was a part of during college. Looking back, this is probably the first time this phrase clicked in my brain:\n\nPeople problems are the hardest engineering problems\n\nFrom the first time that phrase entered into my head, it has ricocheted against the inside of my skull every single day. In computer science, problems are relatively easy to solve because the only thing you have to convince is a compiler. I am not (nor would I ever claim to be) a sociologist, but nonetheless feel safe in stating that people are not compilers. People have opinions. People have motivations. To work together, to have systems, to make any progress as a society, people have to agree on things.\nNever forget - the best side of the road to drive on is the side everybody else has agreed to drive on. When it comes to people problems, consensus is king.\nI’d imagine that the vast majority of you are people, like me, whose professional reputations to not precede you. As fellow members of the proletariat who fall outside of the LinkedIn-influencer and TED-talk alumni elite, we don’t have a whole lot of ethos on which to make our arguments for why people should agree with an idea. I don’t think that’s a huge deal (although golly gee, wouldn’t it be nice to have authority on matters?). It does mean, though, that turning an idea into consensus has to rely on logic and vibes.\nTo that end, I do think that using what I’d describe as “soft” quantitative frameworks for largely qualitative (read: vibes) properties of things is a good way to bring pathos and logos together. In the above presentation, using distance from other locations is not necessarily a catch-all description for the causes of many of the above problems, but it was a good rule-of-thumb."},"tags/csharp":{"title":"C\\#","links":[],"tags":[],"content":""},"tags/doodles":{"title":"Doodles, a.k.a. Minimally Professional Presentations","links":[],"tags":[],"content":""},"tags/economics":{"title":"Economics","links":[],"tags":[],"content":""},"tags/engineering":{"title":"engineering","links":[],"tags":[],"content":""},"tags/gremlin-kicking":{"title":"Gremlin Kicking (a.k.a Productivity)","links":["notes/the-quest-to-kick-the-gremlin"],"tags":[],"content":"Gremlin kicking is a somewhat underhanded term for productivity habits and tools."},"tags/horticulture":{"title":"Digital Gardening, and Horticulture as Research","links":["notes/digital-gardening-with-quartz"],"tags":[],"content":"As a logical consequence of taking a digital gardening approach to writing, the horticulture tag will be used to catalog thoughts related to digital gardening and general research.\nI also wanted to use horticulture because I think it’s a funny word."},"tags/mentoring":{"title":"CGC Mentoring","links":[],"tags":[],"content":""},"tags/python":{"title":"Python","links":[],"tags":[],"content":""},"tags/roblox":{"title":"Roblox","links":[],"tags":[],"content":""},"tags/visualizations":{"title":"Data Visualizations & Presentations","links":[],"tags":[],"content":""}} \ No newline at end of file +{"about":{"title":"About Chaotic Good Computing","links":[],"tags":[],"content":""},"articles/binglish":{"title":"Binglish as a Dead Language (BaaDL)","links":["articles/structured-streaming","articles/robloxaville","notes/digital-gardening-with-quartz","notes/the-quest-to-kick-the-gremlin"],"tags":["economics","horticulture"],"content":"Binglish\n\nbing·lish, noun (derogatory)\n\nThe default writing style of generative AI text models. (derogatory)\nShorthand for a median style of writing, devoid of personality. (derogatory)\nThe way that a monkey’s paw would grant Microsoft’s wish to finally give Bing a generic English term like lowercase-g “google” (very derogatory)\n\n\nIn writing a bit more, I’ve been back-and-forth on the extent to which I want to swear. The style of my writing is more-or-less the way that I speak out loud (which prompted a lot of “couldn’t you make this a bit more professional?” feedback on the Databricks post), and when I speak out loud, I swear. Obviously, the frequency depends - at work it’s sparse (but not nil), on a personal level it’s pretty frequent - but I do still pepper it in for effect in some places. The only times I can remember not swearing is when I was teaching math to K-12 students, and when writing posts here.\nThis feels somewhat… internally dissonant? personally disingenuous? If, when I speak I swear, and I tend to write like I speak, why wouldn’t I also swear in my writing? The answer in the past has been professionalism. It feels unbecoming of a (relatively) young professional to swear in a professional context, and some of what I write here overlaps with what I do for work.\nToning down my writing has been, so far, a fairly active effort. I’ve occasionally even gone as far as writing with swears and then, after-the-fact, explicitly (ha!) searching for illicit words and removing them as I see them. This was probably most apparent when writing the Robloxaville recap article - it mentions a lot of my (very) early work history and, at the time, I thought that potential employers (or youths) might come across it, warranting a touch-up.\nThe world has changed quite a bit since ye olde 2021. I am (slightly) more established in my career, and the context of written documentation has changed quite a bit as technology has advanced. This has made me reconsider my previous policy of toning down my writing. In the process of porting over & more frequently updating this blog, I’ve made an executive decision for the foreseeable future: I’m going to be swearing a bit more.\nOr, at the very least, I’m going to be taking a dramatically less formal approach to writing and editing, here. The spur of this decision:\nThe Bots Are Coming Have Arrived\nI don’t think that, ten years ago, anybody expected that the next dramatic economic shift would’ve been generative AI - specifically text-based AI - putting white-collar workers at the highest risk of automation. An example that comes readily to mind is the CGPGrey video Humans Need Not Apply, in which self-driving cars were offered up as the most readily-apparent example of economic risk of automation. This feels slightly silly with the benefit of hindsight - having started my engineering studies at around the same time though, it’s easy to forget how high-profile advances in self-driving were (at the time). It has become wildly, obviously apparent that the current frontier of automation has come, first, in the form of automated writing.\nThis is obviously a concern for many reasons. The internet is made up of a whole lot of writing. It’s how we text, how we tweet, how we email. It’s what we read, how we get our news, how we ask questions and how we find our answers. Before now, we could safely assume that something we read on the internet came from, at the very least, another human being.\nThat’s not the case anymore, and it will likely not be the case ever again. I don’t think this is the end of the world (probably. hopefully). I do think that this is the end of what I refer to as the statistical median of language: boring, sanitized, business-speak.\nFor the purposes of this note, I am going to refer to this type of language as Binglish.\nBinglish is a Dead-On-Arrival Language\nBinglish, to me, can be described in a few ways:\n\nIt’s Business English. Office English. LinkedIn™ English. I hope, to those of you reading who have also worked a traditional office job, that you can recognize this shorthand as the type of thing that you’d find in your Outlook inbox;\nIt’s Boring English. It’s the median of the language, absent of all personality or human voice; and\nIt’s Bing English. Meant to half-heartedly celebrate Microsoft’s role in solidifying what is very likely a self-consuming business model , poised to consume the very medium it was trained on, this is the type of English that we (currently) see from Bing Copilot, ChatGPT, Gemini, and others\n\nAbsent explicit directives on tone, you can find examples of Binglish on pretty much every single chatbot you could open at the moment. It’s informative. It’s to the point. Once you get the hang of it, it’s easy to both read and write. What’s not to love?\nAnd - unfortunately for the mediums that rely on Binglish - it’s wildly automatable, now.\nIn an effort to formalize the English language into a common median, we have all but guaranteed that the data used to train LLMs has, by definition and in practice, mastered it and put all of us that use it at risk of automation. We can also see the remnants of human efforts to curtail widely-used bots from going outside Binglish at their default settings:\n\nChatGPT refuses to generate even a generic list of English swears…\n\n…as does Raycast’s AI feature, which uses either GPT-Turbo-3.5 or GPT-4…\n\n…as well as Github Copilot, which makes a bit more sense…\n\n…as well as Bing Copilot, even with creative settings, which makes less sense.\nThe takeaway, to me, seems as clear as day.\nHumans Need Not Write Binglish\nThe market for Binglish is cornered. It’s been automated away. The need for writing in the median, devoid of voice or personality, has gone the way of horses in a world of cars. The onus for humans, then, is not to stop writing, but instead to write outside of the Binglish median.\nOne of my favorite examples of people who write with an inimitable voice is Kyla Scanlon, who frequently writes and records thoughts about macro-economics. What makes her writing engaging is not just thoughtful analysis of economic trends, but the voice in which she writes it. It was specifically her post on language and trust that spurred this note to turn into the length of an article.\nWhile I feel like the market for dry, median writing was already withered in the wake of a rising palette preference for infotainment, it was the the advent of ChatGPT and widely-available generative text that has thoroughly crushed the future prospects of Binglish as a human activity. While I can make no guarantees that generative AI won’t someday master imitation of human voice in writing - something that has already reared its head in generative images and spurred active efforts to curtail imitation and preserve unique styles), I have made a decision for my personal writing:\nI don’t want to write Binglish anymore.\nI find no joy in editing the way I write into a now-dead, median form of language, optimized for algorithms with its supply automated away by language models. I’d rather write in my own voice, with my own anachronisms and mistakes and weird vocal ticks and stray punctuation and weirdly-placed emoticons and deeply-nested parentheticals and… run-on sentences? Probably quite a few run-on sentences.\nAs far as I’m concerned, my responsibility is to ensure that the text is readable and that the points I want to make come across, even if it the occasional sentence requires a re-read.\nAnd if it’s not search-engine optimized, or tonally non-neutral, or long-winded? if it contains foul language?\n¯\\(ツ)/¯ fuck it."},"articles/hello-blog":{"title":"Hello, Blog!","links":[],"tags":["python","data"],"content":"Look at that - a whole blog, just for me! At this rate, the last thing I need to do to be a real tech guru is start a podcast.\nI’m starting this page as a place to talk about my cool projects, dumb thoughts, and other odds-and-ends aspects about my life and work.\nTo set the tone, here’s a quick code function to find the geomethic meandian of a set of numbers in Python - in case the need ever arises.\n\nimport numpy as np\n \ndef geothmetic_meandian(\n numbers: np.array,\n error: float = 10e-5\n):\n '''Find the geothmetic meandian of a set of numbers.'''\n \n # If all the numbers are close to the same, return the first number\n if sum(np.abs(numbers - numbers[0])) < error:\n return numbers[0]\n else:\n # Recursively call the geomethic meandian until the numbers converge\n return geothmetic_meandian(np.array([\n np.average(numbers),\n np.product(np.power(numbers, 1 / len(numbers))),\n np.median(numbers)\n ]), error)\n>>> geothmetic_meandian([1, 1, 2, 3, 5])\n2.089\n\nVoila!"},"articles/index":{"title":"Chaotic Good Computing Articles","links":["notes/"],"tags":[],"content":"Here, you’ll find some actual, bona-fide Articles™. You can expect a higher degree of cohesion, revision, and quality than you may find in, say, notes."},"articles/littlefield":{"title":"Zen, and the Art of Laziness","links":["notes/season-of-rhythm","notes/qamo","notes/stability-of-marriage","assets/clutter.png"],"tags":["economics","python","visualizations","data","engineering","games"],"content":"I am awful at sticking to routines - the only thing I can bear to check on every day is Twitter. Even if it means spending twice as long over the course of a weekend, I will always try to find a way to automate away routine manual work.\n(All of the code used in this post can be found here.)\nToo much time to kill\nThis Monday, I started the last major semester of my undergraduate career. That’s right, folks - after six years, four program changes, and one brain surgery (which, in my personal opinion, is one too many), I will finally be wrapping up my degree!\nMy last two semesters will be my first part-time courseloads of my academic career, which leaves me quite a bit of extra time. Given that there’s not much to do during the quarantime, I took a bit of extra time to go over the top in a class I’m taking on operations and supply chain management.\nIntroducing: Littlefield\nAs part of the course, we’ll be spending four weeks in the operations simulation Littlefield. The premise of Littlefield is to tune parameters - things like orders taken and machines purchased - to optimize the profit of a simulated production line. The simulation itself runs a bit faster than real time. Over the course of five full calendar days, one session of the game simulates 250 days of work.\nIn the words of the course instructors:\n\nthe game is set up to give you the flexibility of checking it at your convenience (at any time of day or night)\n\nThe problem? I’m a walking dumpster fire when it comes to routinely checking on anything.\nMy email inbox is constantly full. I am always running on a quarter tank of gas. I’ve never even kept a house plant alive for more than a week - I’m responsible for the early death of more succulents than I would ever care to admit.\nIn the honest-to-God words that my fourth grade teacher wrote on my report card, I am somebody who is “lazy to the point of efficiency.” If there is any way for me to put in all of the work up front, I will find a way.\nWeb Scraping 101\nAs somebody who has been lazy for 23 years now, I’ve become well-acquainted with the concept of web scraping. This is a method for accessing websites using a program instead of your browser. If your job ever involves going to a massive number of web pages and finding specific information - as a few of my internships have entailed from time to time - it’s a fantastic way to avoid the grunt work of going to each individual page by hand. For example, rather than employing an army of people to go through every web page on the internet and keep track of keywords, Google instead uses an army of web scrapers to do all that work for them.\nLittlefield, like the rest of everything on the internet, is scrape-able as well. The game is hosted on a web page that looks like this:\n\nWhile the page is different - and a bit harder to scrape - than your average news article or social media page, it’s still just a set of links that we can get information from. Each node of the graph above leads to a page full of data about the game. If were playing this by hand, we would log in a few times each day, open up each page, and see if there were any issues or bottlenecks in need of fixing.\nIt takes about five minutes to check everything - five exhausting minutes.\nInstead of taking five minutes to check this data myself, I have - as the rational person I am - spent the last six hours creating a program that can check it for me: the Littlefield Driver.\nThe Littlefield Driver\nThe Littlefield Driver is a program that takes all of the data about the state of the game - things like machine utilization, cash on hand, and orders placed - and compiles it into one data table I can look at, graph, and use to diagnose any issues that may be the case. The program is based on a 2017 project by Greg Lewis, who was (at the time) an MBA student at the University of Maryland. Lewis wasn’t alone - developer Jiayu Yi created an export kit for Littlefield back in 2017 as well.\nIdeally, my Littlefield Driver will have a bit of extra functionality beyond data export, but the spirit of automation is still the same. By the end of the project, the goal will be to let the Littlefield Driver use incoming data to automate machine production in the background, and maybe even send me a notification if (or when) something goes horribly wrong.\nThe first order of business for the bot is to take the structure of the game and represent it as a network graph.\nHere’s what the driver sees when it opens up the game:\n>>> lfdriver.draw_graph()\n\n\nIt’s… admittedly not very pretty. At the very least, though, it shows that the program is seeing what we’re seeing: the production line starts at the Orders & Material menus, which goes to the first queue, which feeds into the first station, et cetera.\nHTML is the least romantic language\nWhen a web page is sent to your computer for your viewing pleasure, it’s sent as Hypertext Markup Language, or HTML for short. Normally, we don’t have to deal with HTML directly. The entire point of your web browser is to read the HTML and turn it into something clean, pretty, and - most importantly - human-readable. Scraping the web, however, means that we do need to read the HTML directly in order to pick out the parts we want the computer to look for.\nOur target for the first round of web scraping is going to be the Littlefield data pages. These data pages give you the historical plot of whatever the selected node of the graph represents. For example, this is the data page for how many incoming job requests are received every in-game day:\n\n(as an aside, every time you open a data view, it annoyingly opens as an entirely new window, which means playing Littlefield often looks like this)\nI can always appreciate a clean-looking graph.\nTo make that graph, it’s actually your web browser doing all the work to turn the HTML into a neat visualization. This is what your computer is actually sent:\n\nEven when you’re making a website, reading through raw HTML is rarely ever a fun time. Thankfully, the data we’re looking for is on line 29, smack-dab in the middle of the page:\n{label: 'data', points: '1 1 2 1 3 2 4 ...}\n\nThat’s the data that your browser is using to create the plot from the first image. It’s a bit weird that it’s all one line, but we can pick up from context that the data is being provided in pairs - the first number is the day, then the next is the datapoint - repeated over and over again. You could read it as:\nDay 1: 1 job\nDay 2: 1 job\nDay 3: 2 jobs\nDay 4: ...\n\nThankfully, the data is delivered in the same way for every single data page, from the orders received to the utilization of each station. All we have to do is write the code once, give the program all the data pages, and let it run. Instead of one string of data, we can tell it to put the data in nice, neat human-readable columns like this:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nDayJOBIN112132425363\nAfter scraping every single page of data in the game, we can smash it all together and get a beautiful chart!\n>>> lfdriver.data()\n\n\nThis chart just shows the first and last 10 days of the historical data, and even from this we can gain some insights. S3UTIL, which represents the current utilization of the third station, is at 67% on Day 50 of the simulation. Judging by the rate of increase - roughly 1.3% every day on average - we should probably consider buying another machine at Station 3 prior to Day 75.\nOf course, that’s just an estimate. The purpose of the Driver is to check in on the game routinely to see if there are any critical issues. For example, the Driver can check to see if a station utilization is at a high percent and calculate whether or not it would be profitable to order a new machine.\nEverything is done - for now\nAt the time of writing this, I haven’t actually played a game of Littlefield - everything written so far was done on a static sample game. This means I haven’t had access to some features - like purchasing machines - so they haven’t been added to the Littlefield Driver… yet. Additionally, there’s some system variables - such as the cost of a new machine - that are available in the data but aren’t available in the Driver.\nUltimately, this is a god-awful way to play the game. With 12 years in development and only 2 examples (that I’ve found) of people attempting to automate the game, the game is clearly playable by hand. You might ask, then - why put in all this effort?\nThe real question is: why not?"},"articles/resume-ci-pipeline":{"title":"Job Applications are a Waking Nightmare - Let Tech Do It For You","links":[],"tags":["mentoring","engineering","tutorials"],"content":"\nNOTE: THIS IS OUTDATED. There are now far better PDF markup languages to use, such as Typst. These will be detailed in a later blog post.\n\nAfter trying - and failing - to constantly keep my resume up-to-date in a dozen different places, I took a page out of the wild world of software development and found the solution: continuous integration.\nIt used to be the case that software would release in massive updates. A bunch of big changes, tweaks, and bug fixes would be shoved together in a tidy package and delivered out all at once. As development became faster, though, development teams created continuous integration pipelines to constantly push changes out to their users. Rather than waiting until the next big change to release patches, small changes could be pushed out automatically.\nThis is common in web applications like Facebook or Twitter. You’ll never see Twitter come out with some big new Twitter 2.0 (Two-tter) - any changes they need to make are just pushed out to users in small batches, over time. Why not do the same with a resume?\nCreating an Always-Updated Resume\nCreating a continuously-updating resume can be done in two steps:\n\nSet up your resume so that you can make small, quick, iterative changes over time; and\nFind a central place to send those changes to, and send viewers to that location.\n\nI’m sure there are quite a few ways to run those two stages. I personally chose Overleaf and GitHub. At this point, I had already been using Overleaf to format my resume and had been using GitHub for small odds-and-ends projects for the first couple years of my undergrad. If we’re being honest, I didn’t want to learn new things - I just wanted it to work.\nSometimes being lazy pays off. Not usually, but sometimes.\nIt also helps that Overleaf has a neat built-in GitHub integration. How nice of them to do that! With this integration, the steps for the project start to come together:\n\nCreate a resume on Overleaf\nPush your resume to GitHub\nCompile your resume into a .pdf file\n\nAlright - let’s do it!\nCreating a Resume in Overleaf\nFor the uninitiated, Overleaf is an application commonly used in academia to write academic papers in a programming language called LaTeX. If you’ve ever used HTML to create a website, LaTeX does the same thing for PDFs. Thankfully, to get started, you don’t have to create a new resume from scratch. Overleaf has a ton of sleek-looking resume templates that you can put your current information into. If you’re looking for a friendly resume-making guide, I made a starter template with explanations on a few best resume practices for students.\nOnce you have a template picked, you can select “Open as Template” to add it to your personal Overleaf projects. You can start putting your information in at your own pace, but it isn’t necessary to start connecting your resume to GitHub.\nLinking Overleaf and GitHub\nIf you don’t have a GitHub account, now is the time to make a new one! GitHub is a fantastic place to store and update code - it’s literally what it was made for! Because your new resume (and the LaTeX it’s made from) are very small, it’s an ideal place to host your resume.\nOn your Overleaf resume, you can find the GitHub integration in the menu on the top-left of the code editing window. After signing into your GitHub account, you’ll have the option to create a new code repository for your project. Choose a name for your repository, enter a description if you’d like, and then select the option to make your repository public.\nWhile you can name your code repository anything, I would recommend sending this to your user’s GitHub Pages repository. Every GitHub user gets a special place where they can host a website or files publicly at <YOUR USERNAME>.github.io. If that type of address looks familiar, it’s because I host this blog on my own GitHub Pages site!\nIn order to use Github Pages, you’ll need to name your new repository <YOUR USERNAME>.github.io. For example, because my GitHub username is spelkington, my GitHub Pages repository is named spelkington.github.io.\nFinally, with your repository made, click the button to push Overleaf changes to GitHub. Now it’s time to make your resume update automatically!\nSetting up Continuous Integration\nGitHub has a nifty feature called Github Actions that development teams can use to automate some of the pain-in-the-ass aspects of programming. Typically this involves automatically testing software for glitches or compiling code, but for our case we’re going to use it to automatically turn our resume code into a .pdf file.\nThankfully, we don’t have to come up with a way to do this ourselves! Xu Cheng has created a nifty GitHub Action that will compile LaTeX files into PDFs.\nGo to your new repository on GitHub and click on the Actions button at the top. From there, you can create a new action.\nCreating a new action should take you to a code editor where you can create an Action configuration from scratch. Remove everything and place this code below:\nname: Build LaTeX document\n \n# Run this action every time the resume .tex is updated\non:\n push:\n paths:\n - '<RESUME FILE NAME>.tex'\n \njobs:\n build_latex:\n runs-on: ubuntu-latest\n steps:\n \n # Check out the repository on the Action machine\n - name: Set up Git repository\n uses: actions/checkout@v2\n \n # Compile the LaTeX document into a .pdf\n - name: Compile LaTeX document\n uses: xu-cheng/latex-action@v2\n with:\n root_file: resume/<RESUME FILE NAME>.tex\n \n # Commit this change as an automated user\n - name: Commit Change\n uses: EndBug/add-and-commit@v7.0.0\n with:\n author_name: <YOUR NAME> (auto)\n author_email: <YOUR EMAIL>\n message: 'TeX compile'\n \n # Push the change to the repository\n - name: Upload PDF\n uses: ad-m/github-push-action@master\n with:\n github_token: $\\{{ secrets.GITHUB_TOKEN }}\nReplace everything in the < > brackets, press the “Start Commit” button at the top right, and you’re all set! From now on, whenever you make changes to your resume in Overleaf, you can navigate back to the GitHub integration menu, push your change, and it’ll automatically send the code to GitHub and turn it into a .PDF!\nSending Your Resume\nOf course, the point of all this is be able to have a single link to your resume that will stay up-to-date forever. So how do we get this link?\nIf you followed the instructions for setting up the resume on your GitHub pages repository, it’s easy! Your resume will be available at <YOUR GITHUB USERNAME>.github.io/<YOUR RESUME FILE>.pdf. For example, mine is available at spelkington.github.io/Elkington_Resume.pdf."},"articles/robloxaville":{"title":"The Unbearable Weight of ROBLOX Celebrity","links":["notes/robloxaville-remaster"],"tags":["roblox","lua","engineering","games"],"content":"Guilty confession: I’ve had a ROBLOX account for 14 years. At 23 years old, that’s more than half my life. After picking up development again in 2021, I’ve had quite the walk through memory lane.\nBeing a dork is a lifetime commitment\nFlash back to 2007: Spencer Elkington, 4th grade extraordinaire. Oh, to be at my peak again. While I appreciate that secondary schools mandate that all kids have a well-rounded curriculum to introduce them to a wide span of different fields of study, I can safely say that one of my least favorite classes was art. While I didn’t not enjoy spending an hour cutting, painting, gluing, and molding, there are only so many burnt ceramics and skewed portraits I could churn out before they - and my parents to whom that “art” was gifted - realized that perhaps a budding patronage in the fine arts wasn’t going to be in the cards for me.\nRelated point: Being a dork might be genetic\nAround that same time, I made an account on ROBLOX, an online game platform that was just a year old in 2007. Founded originally as a physics engine by mechanical engineers, it transitioned into a gaming platform after (I can only assume) the founders decided simulating viable buildings was far less fun than blowing them up. One of the coolest features was ROBLOX Studio, an IDE for developing user-made games and content in Lua. If you could play a game, you could make a game, and that ease of entry introduced a whole generation - myself included - to the wild world of programming.\nCooking up small games for me and my friends is probably the closest I’ll ever get being an artist. I could never paint a canvas worth a damn, but in an increasingly digital world being able to write a bit of code lets you create as much as a paintbrush ever could. Always looking for ways to hang out with her son, my mom - who is and always will be the biggest, coolest dork I have ever met and will ever will meet - joined the platform in 2008 to make games too.\nWith a background in coding from her physics, geology, and chemistry studies at BYU during her undergraduate (because just studying one STEM field would be too easy, obviously), she was an artist of her own right when it came to making games her kids could play. Over time, one of those games developed into a project called Robloxaville that she actively developed on from 2008 to 2012. The game became one of the most played games on ROBLOX during that period, later superceded by a follow-on project called Lakeside that became one of the fastest-growing projects made on the platform within two months of its’ initial release.\n\nOriginal Robloxaville thumbnail, 2008\nThis success was in no small part due to a feature she developed in 2009 called Morph Magic, a wildly clever, wildly hack-y workaround she discovered to modify the underlying skeleton of the ROBLOX player model and transform players into fully-animated dogs, cats, giants, or any of a dozen other models. The ad-hoc rigging method originally used in Morph Magic was the only method for modifying the player skeleton until ROBLOX added official rigging support - six years later. Watching millions of people enjoyed my mom’s masterpiece is what made me get into coding - first as a play tester, then as a (very amateur) contributor, and finally remastering the project in 2017.\nLike I said: the biggest, coolest dork I have ever met and will ever meet.\nThe wild ways software can go horribly, horribly wrong\nIn 2013, my mom stopped developing on the platform. It’s not that she didn’t enjoy it - as a general rule, nobody in their right mind writes clever workaround libraries in their free time if they don’t enjoy it. What stopped her from developing on the platform was years of rampant client-side exploits made possible by some questionable decisions made in the development of the ROBLOX game engine. For the uninitiated, here’s what went wrong:\nWhenever you use a device connected to the internet - your phone, laptop, tablet, desktop, etc. - it is communicating with tons of other computers called servers that belong to whatever service you happen to be using. When you’re browsing the web, it’s communicating with web servers. When you’re sending an email, it’s communicating with email servers. And when you’re playing ROBLOX, it’s communicating with ROBLOX servers.\nThese servers are responsible for running all the code that makes the game work. It diligently reads the Lua code that makes up a ROBLOX game, line by line, and changes the state of the game to whatever its’ told. If you tell the server to game.Workspace.Player.Head:Remove(), it will gleefully read that line of code and promptly remove the head of some unsuspecting victim.\nThat being said, sometimes the server needs a bit of help. Specifically, the server will occasionally rely on the game clients - your computer, and the computers of every other player in the game - to help it run some of the physics calculations. The millions of physics calculations run by the game can be a real pain in the ass for one computer, so the game server needs all the help it can get. Because of that, the client will occasionally send some information to the server to help the server know what the state of the game should be. Innocent enough, right?\nIt wasn’t always the case that the server relied on the clients for just physics calculations. Back in the early days of the ROBLOX engine, the client could send the server any information about the state of the game and the server would happily accept it as a gospel truth, even if it wasn’t in the game code. Here’s how the conversations between the server and client used to go:\n\nCLIENT: Hey Server! I need you to remove this player’s head for me.\nSERVER: Are you sure? I don’t remember seeing game.Workspace.Player.Head:Remove() anywhere in the code.\nCLIENT: Yep! Definitely supposed to not have a head. That’s how it looks on my computer.\n\nAnd then the server would, once again, gleefully remove the head of some unlucky soul, despite that fact that it was a rogue player’s client who gave the order, not the programmer.\nThese exploits, at a basic level, allowed users to wreak havoc on games: breaking game functions, harassing players, et cetera. However, the exploits were not always just to be annoying. The same exploit that allowed users to mess with the state of the server could also be used to download the source code for entire games, allowing users to rip and reupload entire years-long projects in minutes. At their worst, these exploits could get downright horrifying. \nBack in the Saddle\nIn 2014 - following what could only be described as a complete COPPA cluster - ROBLOX began making moves to clean up and polish the platform. This came in two major changes to the way development worked. \n1. Filtering Enabled\nTo fix the slightly problematic client exploit issue, the company introduced the Filtering Enabled feature to their game engine. Filtering Enabled locked down what types of information game servers would accept from the game client and fixed that little whoopsies mistake made in the younger days of the platform. However, development became a trickier after this feature was rolled out - many older games needed to be re-made to conform to the communication boundary between the server and client, and required a bit more formal knowledge of game development to make.\n(For reference, I didn’t learn anything about server and client relationships until my third year into a computer science degree.)\nEven though this feature could be disabled to allow legacy games to keep functioning (and yes, Robloxaville is legacy now - it even has the Fandom Wiki page to prove it), ROBLOX’s featured games algorithm wouldn’t touch your project with a ten-foot pole for risk of traumatizing even more unsuspecting children. This was especially important for the next major change,\n2. Monetization\nThat’s right, folks - every line of code my mom wrote from 2008 to 2013, she wrote for free. Making fun games for millions of kids across the world, pro bono? That’s just the way Tiffany rolls.\nWith the introduction of the Developer Exchange (DevEx), anybody (who could afford a premium membership) could take the in-game currency generated from their games and exchange it for cold, hard cash. Funnily enough, in that original blog post explaining how the DevEx program worked, the company describes a system where:\n\n[A] power-user [could cash] cash out and [buy] a car to get to and from college – all from developing a popular game on ROBLOX. This is the kind of story we can’t wait to tell.\n\nThat’s not quite the direction things went.\nThe Part Where Spencer Does Some Math\nSince DevEx was released, I’ve heard stories of full-time developers leaving their jobs to develop on the platform. Success could be lucrative: Welcome to Bloxburg, one of a number of games that filled in the Town And City genre gap after Robloxaville and Lakeside became deprecated by the Filtering Enabled update, has been played 4.8 billion times as of writing.\nBillion. With a “B”. 4,800,000,000.\nThat’s a lot of zeroes.\nThe game offers users a premium pass as an in-game purchase. This is a pretty common way to offer users a bit of extra bang for their buck by providing small bonus features - Robloxaville did the same thing at one point. How much do you think they could make off of a feature like that?\nUnfortunately for us, exact numbers are hard to find. ROBLOX stopped showing how many times in-game purchases were sold, no doubt to stop people from snooping around at how much developers make. That being said, we’ll make an assumption off of Robloxaville’s conversion rates: For every 10,000 player visits, 5 people will splurge on a premium pass at a purchase rate of 0.05%. That doesn’t look too impressive - yet.\nAt a 0.05% purchase rate against - and I cannot emphasize this enough - 4.8 billion visits, we could estimate that BLOXburg’s premium pass has been purchased 2.4 million times. Each game pass is 400 Robux (R$), ROBLOX’s in-game currency. If memory serves, ROBLOX keeps 30% of in-game player-to-player purchases (because, as we know, the only certainties are death and Robux taxation). We can assume, then, that the developers of BLOXburg received ~960 million R$ for that premium pass.\nThat golden parachute is starting to look real good.\nWhat might a 960 million R$ payout look like? The current DevEx exchange rate as of writing is 0.0035 USD for every 1 Robux (Robuck?) at the time of writing. This means that the estimated worth of that one premium pass for that one game is…\n3.6 million dollars.\nHm.\nHmmm.\nOf course, this does not come without some caveats. First: this is one of the most played games in the history of the platform - its’ success is by no means descriptive of every developer. Second: their estimated payout was made over the course of the six years the game has been in development. Third: the BLOXburg team is not just a single developer, and they are very good at what they do - enviously good, even.\nThat being said: those caveats also come with caveats. Although not every developer is going to be that successful, ROBLOX self-reportedly spends about 25% of their revenue on developer payouts as of a report from 2017. Since the company made its’ public debut on the New York Stock Exchange and started reporting revenue as a publicly traded company, they reported a revenue of $147 million dollars in 2020. Assuming they still pay out 25% to developers, that’s a big ol’ pot of 34 million dollars to go around.\nHow To Make Games and Influence Gen Z\nThis post has gotten way, way longer (and included way more math) than I intended, so I’ll wrap it up for now. Long story short: since 2007, ROBLOX has grown beyond description in both size and sophistication. The introduction of monetization professionalized the platform beyond what hobbyists from the early 2010s could ever pull off today. And, after (attempting) to redux Robloxaville back in 2016, I’m ready to take another stab at it.\nThe way I see it, games are to the computer what film was to the camera and paint was to the canvas. It’s a way to create an experience that people can look at, play with, and grow from. I really enjoy it. It’s a way for somebody who has no business in making art to get pretty damn close.\n(And it wouldn’t hurt to get some of that sweet DevEx stimmie, either.)"},"articles/structured-streaming":{"title":"Don't Double Down: Using Spark Structured Streaming to Wrangle Growing Data","links":[],"tags":["data","engineering","python","aws","tutorials","visualizations"],"content":"\nThis post was written during my time as a software engineer at M Science as a joint project with Databricks. You can view the original post here\n\nLet’s say that you, a ✨ humble data plumber ✨ of the Big Data era, have been tasked to create an analytics solution for an online retail dataset:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nInvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry53636585123AWHITE HANGING HEA…62012-01-10$2.5517850United Kingdom53636571053WHITE METAL LANTERN62012-01-10$3.3917850United Kingdom53636584406BCREAM CUPID HEART…82012-01-10$2.7517850United Kingdom……………………\nThe analysis you’ve been asked for is simple - an aggregation of the number of dollars, units sold, and unique users for each day, and across each stock code. With just a few lines of PySpark, we can transform our raw data into a usable aggregate:\nimport pyspark.sql.functions as F\n \ndf = spark.table("default.online_retail_data")\n \nagg_df = (\n df\n # Group data by month, item code and country\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n F.countDistinct("CustomerID")\n .alias("Users"),\n )\n)\n \n(\n agg_df.write\n .format('delta')\n .mode('overwrite')\n .saveAsTable("analytics.online_retail_aggregations")\n)\nWith your new aggregated data, you can throw together a nice visualization to do… business things.\n\nThis works - right?\nAn ETL process like will work great for a static analysis, where you don’t expect the data to ever be updated - you assume the data you have now is going to be the only data you ever have. The problem with a static analysis?\nModern data doesn’t stop growing.\nWhat are you going to do when you get more data?\nThe naive answer would be to just run that same code every day, but then you’d be re-processing all of the data, every time you run the code. Each new update means re-processing data you’ve already processed before. When your data gets big enough, you’ll be doubling down on what you spend in time and compute costs.\n\nWith a static analysis, you spend money on re-processing data you’ve already processed before\nThere are very few modern data sources that aren’t going to be updated. If you want to keep your analytics growing with the source of your data, and save yourself a fortune on compute cost, you’ll need a better solution.\nWhat do we do when our data grows?\nIn the past few years, the term “Big Data” has become… lacking. As the sheer volume of data has grown and more of life has moved online, the era of Big Data has started to become the era of “God Help Us, It Just Won’t Stop Getting Bigger Data.” A good data source doesn’t stop growing while you work, and this growth can make keeping data products up-to-date a monumental task.\nAt M Science, our mission is to use alternative data - data outside of your typical quarterly report or stock trend data sources - to analyze, refine, and predict change in the market and economy.\nEvery day, our analysts and engineers face a challenge: alternative data grows really fast. I’d even go as far to say that, if our data ever stops growing, something in the economy has gone very, very wrong.\nAs our data grows, our analytics solutions need to handle that growth. Not only do we need to account for growth, we also need to account for data that may come in late or out-of-order. This is a vital part of our mission - every new batch of data could be the batch that signals a dramatic change in the economy.\nTo make scalable solutions to the analytics products that M Science analysts and clients depend on every day, we use Databricks Structured Streaming. Structured Streaming gives us the assurance that, as our data grows, our solutions will scale as well.\nUsing Spark Structured Streaming\nStructured Streaming comes into play when new batches of data are being introduced into your data sources. Structured Streaming leverages Delta Lake’s ability to track changes in your data to determine what data is part of an update and re-computes only the parts of your analysis that are affected by the new data.\nIt’s important to re-frame how you think about streaming data. For many people, “streaming” means real-time data - streaming a movie, checking Twitter, checking the weather, et cetera. If you’re an analyst, engineer, or scientist, any data that gets updated is a stream. The frequency of the update doesn’t matter. It could be seconds, hours, days, or even months - if the data gets updated, the data is a stream. If the data is a stream, then Structured Streaming is going to save you a lot of headaches.\n\nWith Structured Streaming, you can avoid the cost of re-processing previous data\nLet’s step back into our hypothetical - you have an aggregate analysis that you not only need to deliver today, but also keep updating as new data rolls in. This time, we have the DeliveryDate column to remind us of the futility of our previous single-shot analysis:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nInvoiceNoStockCodeDescriptionQuantityInvoiceDateDeliveryDateUnitPriceCustomerIDCountry53636585123AWHITE HANGING HEA…62012-01-102012-01-172.5517850United Kingdom53636571053WHITE METAL LANTERN62012-01-102012-01-153.3917850United Kingdom53636584406BCREAM CUPID HEART…82012-01-102012-01-162.7517850United Kingdom………………………\nThankfully, the interface for Structured Streaming is incredibly similar to your original PySpark snippet. Here is your original static batch analysis code:\n# =================================\n# ===== OLD STATIC BATCH CODE =====\n# =================================\n \nimport pyspark.sql.functions as F\n \ndf = spark.table("default.online_retail_data")\n \nagg_df = (\n df\n \n # Group data by date & item code\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n \n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n F.countDistinct("CustomerID")\n .alias("Users"),\n )\n)\n \n(\n agg_df.write\n .format('delta')\n .mode('overwrite')\n .saveAsTable("analytics.online_retail_aggregations")\n)\nWith just a few tweaks, we can adjust this to leverage Structured Streaming. To convert your previous code, you’ll:\n\nRead our input table as a stream instead of a static batch of data\nMake a directory in your file system where checkpoints will be stored\nSet a watermark to establish a boundary for how late data can arrive before it is ignored in the analysis\nModify some of your transformations to keep the saved checkpoint state from getting too large\nWrite your final analysis table as a stream that incrementally processes the input data\n\nWe’ll apply these tweaks, run through each change, and give you a few options for how to configure the behavior of your stream.\nHere is the ✨ stream-ified ✨ version of your old code:\n# =========================================\n# ===== NEW STRUCTURED STREAMING CODE =====\n# =========================================\n \n+ CHECKPOINT_DIRECTORY = "/delta/checkpoints/online_retail_analysis"\n+ dbutils.fs.mkdirs(CHECKPOINT_DIRECTORY)\n \n+ df = spark.readStream.table("default.online_retail_data")\n \nagg_df = (\n df\n+ # Watermark data with an InvoiceDate of -7 days\n+ .withWatermark("InvoiceDate", f"7 days")\n \n # Group data by date & item code\n .groupBy(\n "InvoiceDate",\n "StockCode",\n )\n \n # Return aggregate totals of dollars, units sold, and unique users\n .agg(\n F.sum("UnitPrice")\n .alias("Dollars"),\n F.sum("Quantity")\n .alias("Units"),\n+ F.approx_count_distinct("CustomerID", 0.05)\n .alias("Users"),\n )\n)\n \n(\n+ agg_df.writeStream\n .format("delta")\n+ .outputMode("update")\n+ .trigger(once = True)\n+ .option("checkpointLocation", CHECKPOINT_DIR)\n+ .toTable("analytics.online_retail_aggregations")\n)\nLet’s run through each of the tweaks we made to get Structured Streaming working:\n\nStream from a Delta Table\n\n+ df = spark.readStream.table("default.online_retail_data")\nOf all of Delta tables’ nifty features, this may be the niftiest: you can treat them like a stream. Because Delta keeps track of updates, you can use .readStream.table() to stream new updates each time you run the process.\nIt’s important to note that your input table must be a Delta table for this to work. It’s possible to stream other data formats with different methods, but .readStream.table() requires a Delta table\n\nDeclare a checkpoint location\n\n+ # Create checkpoint directory\n+ CHECKPOINT_DIRECTORY = "/delta/checkpoints/online_retail_analysis"\n+ dbutils.fs.mkdirs(CHECKPOINT_DIRECTORY)\nIn Structured Streaming-jargon, the aggregation in this analysis is a stateful transformation. Without getting too far in the weeds, Structured Streaming saves out the state of the aggregation as a checkpoint every time the analysis is updated.\nThis is what saves you a fortune in compute cost: instead of re-processing all the data from scratch every time, updates simply pick up where the last update left off.\n\nDefine a watermark\n\n+ # Watermark data with an InvoiceDate of -7 days\n+ .withWatermark("InvoiceDate", f"7 days")\nWhen you get new data, there’s a good chance that you may receive data out-of-order. Watermarking your data lets you define a cutoff for how far back aggregates can be updated. In a sense, it creates a boundary between “live” and “settled” data.\nTo illustrate: let’s say this data product contains data up to the 7th of the month. We’ve set our watermark to 7 days. This means aggregates from the 7th to the 1st are still “live”. New updates could change aggregates from the 1st to the 7th, but any new data that lagged behind more than 7 days won’t be included in the update - aggregates prior to the 1st are “settled”, and updates for that period are ignored.\n\nNew data that falls outside of the watermark is not incorporated into the analysis.\nIt’s important to note that the column you use to watermark must be either a Timestamp or a Window.\n\nUse Structured Streaming-compatible transformations\n\n+ F.approx_count_distinct("CustomerID", 0.05)\nIn order to keep your checkpoint states from ballooning, you may need to replace some of your transformations with more storage-efficient alternatives. For a column that may contain lots of unique individual values, the approx_count_distinct function will get you results within a defined relative standard deviation.\n\nCreate the output stream\n\n+ agg_df.writeStream\n .format("delta")\n+ .outputMode("update")\n+ .trigger(once = True)\n+ .option("checkpointLocation", CHECKPOINT_DIR)\n+ .toTable("analytics.online_retail_aggregations")\nThe final step is to output the analysis into a Delta table. With this comes a few options that determine how your stream will behave:\n\n.outputMode("update") configures the stream so that, each time the code runs, the aggregation will pick up where it left off instead of running from scratch. To re-do an aggregation from scratch, you can use "complete" - in effect, doing a traditional batch aggregate while still preserving the aggregation state for a future "update" run.\ntrigger(once = True) will trigger the query once when the line of output code is started, and then stop the query once all of the new data has been processed.\n"checkpointLocation" lets the program know where checkpoints should be stored.\n\nThese configuration options make the stream behave most closely like the original one-shot solution.\nThis all comes together to create a scalable solution to your growing data. If new data is added to your source, your analysis will take into account the new data without costing an arm and a leg.\nYou’d be hard pressed to find any context where data isn’t going to be updated at some point. It’s a soft agreement that data analysts, engineers, and scientists make when we work with modern data - it’s going to grow, and we have to find ways to handle that growth.\nWith Spark Structured Streaming, we can use the latest and greatest data to deliver the best products, without the headaches that come with scale."},"contact":{"title":"Contact Chaotic Good Computing","links":[],"tags":[],"content":""},"index":{"title":"Oh, Howdy!","links":["notes/digital-economies","tags/mentoring","articles/"],"tags":[],"content":"Chaotic Good Computing is an organization specializing in providing advice and assistance for small companies around:\n\nSoftware Engineering\nData Analysis & Handling\nEconomic Analysis\n\nCGC’s general specialty is engineering, analysis, insights, and maintenance of digital economies like multiplayer game economies, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications.\nCGC also provides professional development resources and mentoring for young developers and professionals interested in economics and software engineering.\nThis site contains articles, notes, and thoughts on a broad range of topics. Chaotic Good Computing’s articles are great points to get started!"},"notes/arc-review":{"title":"Arc Browser: The Beginning of My Tumulting Times™","links":["notes/the-quest-to-kick-the-gremlin"],"tags":["gremlin-kicking"],"content":"The Arc Browser is probably the first tool that kicked off a series of shake-ups on how I use technology to put up guard rails on being able to start - and stay - focused. It was also on their blog that I discovered Maggie Appleton’s blog - so in a way, it was very much a half-step into a pool of ideas that have helped me come to terms with the slightly-more-than-standardly chaotic way that I tend to work.\nAt some point, I’ll do a review here."},"notes/beethoven":{"title":"From the Archive: \"Reading the Room with Beethoven\"","links":[],"tags":["engineering","typescript"],"content":"Beethoven was a project for HackTheU 2019, where a team and I (mostly the team) created an application for providing live captions to deaf students by using a remote microphone to stream audio and captioning to a user’s local device.\nFrom the original submission:\n\nInspiration\nSpencer, one of our team members, has a parent who is hearing-impaired and another that provides live, remote, ver batem transcription services for deaf and hard-of-hearing undergraduate, Ph.D., and Executive MBA students across the nation. Dan and Joseph, two of our other members, work for Sorenson Communications making video calling and other applications for the deaf community. We noticed that, for deaf students who would prefer live captioning in their lectures, there is no one-stop solution for both audio streaming and live captioning. We created Beethoven, an application for quick and accurate transcription in the classroom, to solve this.\nFunctionality\nPut simply, Beethoven will pair two devices together - an audio input and a screen output - and stream captioning from one device to the other in real time. The student can put one device at the front of the class for the clearest possible audio, and then position another next to them to read live captioning of the lecture and dialog as if it was the Closed Captioning on a television show or movie. This can either be done through Google Cloud transcription services or a live CART interpreter, depending on the level of accuracy desired and resources available.\nDevelopment Process\nThe application is split into three main parts - the audio input, the transcription service, and the screen output. First, the audio is captured by the audio input device. From there, it goes to either the Google Cloud voice transcriber, or a live CART interpreter. This happens through Google Cloud Services or peer-to-peer WebRTC, respectively. Once complete, the text will be sent to both our server’s backend to be compiled into a transcript and send to the screen output device, placed in front of the student, where a stream of the captioning is displayed.\nWhat’s next for Beethoven\nMoving forward, we’d like to fully implement the CART reporting features of the application. The P2P handshaking feature has a lot of improvements that can be made. Once finished, we’d like to reach out to the deaf and CART communities to get their feedback on the product.\n"},"notes/caveat-lector":{"title":"Caveat Lector: Reader Beware","links":["notes/digital-gardening-with-quartz","notes/qamo","tags/horticulture"],"tags":["horticulture"],"content":"The past few days have been a weird experience as I actively try to lower the internal bar for what I feel comfortable putting out into the world. As a proud member of the most terminally online generation to ever live, I have a deep and relentless fear of being wrong on the Internet.\nIn getting everything ready to re-publish this site as my own digital garden, I’ve started using the phrase “caveat lector” a lot. Back in my undergraduate degree, I learned about the phrase caveat emptor and caveat venditor:\n\nCaveat emptor means “buyer beware,” to be used in situations where a buyer of a product is responsible for understanding the risk they take in their purchase; and\nCaveat venditor means “seller beware”, to be used in situations where a seller of a product is responsible for minimizing the risk of the products they sell.\n\nA good napkin example would be a buyer and seller of digital LCD displays. In that case, it’s the seller’s responsibility to make sure that the display actually works - caveat venditor. However, what if a display works, but has a few dead pixels? This doesn’t render the display unfit for purpose - the seller would still be selling a good and usable product that fulfills their promise - but dead pixels are pretty annoying. The risk of dead pixels, then, may fall on the buyer - caveat emptor.\nOne of my intentions with Chaotic Good Computing is to contribute to the free body of knowledge I’ve benefitted immensely from myself, but to do so in a way that both fits my style and my habits better than traditional blogging or educational entertainment. The commitments that I’m making to you, the reader, are:\n\nTo my knowledge, the things that I’m posting are accurate at the time that I write them down; and\nIf I learn something in the future that corrects something I’ve written in the past, I’ll do my best to make corrections as I find mistakes. \n\nThat said, I’m also just some person on the internet. I know some things pretty well and other things not-so-much, with a pretty vast in-between. By the very nature of learning in public, some things here will be straight-up wrong, if not at least not-as-correct-as-they-could-be.\nSo, to you, I say:\n\nCaveat lector!\nReader Beware!\n\nand, as a follow-up piece of advice, I might also borrow from the Russian proverb:\n\nDoveryay, no Proveryay.\nTrust, but Verify.\n"},"notes/dailies/2024-02-25":{"title":"2024-02-25","links":["notes/caveat-lector","notes/digital-gardening-with-quartz","notes/over-under-engineering"],"tags":["typescript","horticulture"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI didn’t plan anything today, but I do want to start planning things in the future.\nToday’s Report\nI’m totally ripping off the labelling of this from Pikmin 2’s “Today’s Report” screen.\nThat’s not even a joke - I absolutely love the idea of ending the day with little graphs of what I did (or did not do) well that day in a tidy little reflective at-a-glance view.\nToday was (and will continue to be - my plan is to go home and keep going while I watch Avatar) a whole lot of writing. I’m still in the process of creating a new blog with Quartz, but I keep catching myself falling into a trap of “I want to make everything look perfect before I publish it!“. Despite spending the day jotting down my thoughts about over-engineering killing my dreams, I can’t seem to stop myself.\nThe stopping point for today will probably be a vague “do I feel like I’ve written enough to cover, at a base level, the anchor tags of what I want to write.” I still do want to do some weird D3.js fuckery to Quartz’s network graph where major “anchor” tags are locked to the outside of a circle (or some other shape) with extending graphs moving inward, but I am unfortunately blocked by not knowing how to debug with Quartz’s weird custom CLI build process.\nActually, it looks like the Quartz author just got back to me - QuartzComponents are built…\ntoo late? too early? I still don’t know enough about frontend development to fully understand how Quartz works under-the-hood or totally what that message means.\nTL;DR something about the Quartz build process means that I can’t use DevTools in a browser to debug Quartz components. Yesterday I was researching CodePens (or, more specifically, VSCode-inline CodeSwings) as a better workflow for my not-design-or-frontend-savvy self to develop these components in isolation. While I do still want to do some deep customizations to the way the Quartz Graph component works, I have decided (just now, as I’m writing) to leave this as a stretch goal, and instead prioritize getting this blog out as-is and customizing it to my liking later.\nMore work to be done in the endless struggle to avoid putting horses before carts, or whatever.\nNotes\n\nhttps://blog.partykit.io/posts/cursor-party\nhttp://www.bruno-latour.fr/sites/default/files/35-MIXING-H-ET-NH-GBpdf_0.pdf\nhttps://maggieappleton.com/gathering-structures\nhttps://maggieappleton.com/ambient-copresence\nhttps://github.blog/2023-10-05-a-developers-guide-to-open-source-llms-and-generative-ai/\nhttps://github.blog/2023-10-04-how-to-communicate-like-a-github-engineer-our-principles-practices-and-tools/\nhttps://www.rawgraphs.io/\n"},"notes/dailies/2024-02-26":{"title":"2024-02-26","links":["notes/caveat-lector","notes/dailies/2024-02-25","notes/the-quest-to-kick-the-gremlin","notes/season-of-rhythm"],"tags":["csharp","aws","gremlin-kicking","horticulture"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nMost of today’s plan is going to be getting an internal NWYC project up-and-running with an MVP before we transition to some compliance updates to infrastructure. Follow-up on CGC will be taking inventory of the writing I did yesterday, and (once again) debating whether or not to get the formatting of the blog just right before I publish.\nB-Block\n\nCompleting C# wrappers for Geocoding services\nWorking on next ChainSharp steps for congressional data lookups\n\nM-Block\n\nLikely a continuation of B-block work\n\nE-Block\n\nCGC; in particular, either\n\nContinuing content writing, potentially starting the new posts for 1099 contractor writing; OR\nSetting up an environment & workflow for creating swings with CodeSwings\n\n\nStretch goal is contemplating whether or not MDX compatibility for Obsidian and Quartz will come now or later. I think Remark has the ability to do MDX files but I’ll need to spike that a bit more closely.\n\nToday’s Report\n\n\nNoon progress update: Got distracted at the possibilities of AWS CloudWatch Dashboards. Morning block is a bit behind, but getting back to it.\n\n\nAfternoon progress update: as a general rule, try to never fuck up the same way twice. that’s a good motivation for writing down as much as possible outside of code, so that the body of DX-related issues with undocumented fixes is always shrinking.\n🎵 come with me 🎵 //\n🎵 and you’ll see 🎵 //\n🎵 a world in which no developer fucks up the same way twice, and rather fucks up in new and creative ways each time 🌈 🎵\n\n\nIn sum total, today was… okay? ish? in terms of progress. Didn’t quite get as far as I’d hoped on C#, but some other (equally important) stuff came up and that seems okay. E-block certainly didn’t go as far as I’d hoped (read: it did not happen) but at least CGC stuff is at my own pace.\nAdmittedly, a minor distraction did pull away more of my attention than I ought to’ve allowed.\n\nAs a bit of a buzzer-beater against my self-imposed daily deadline of 12:00pm MT, I’ve decided to just publish this new blog format as-is. It doesn’t quite have the same style and zest as the original, but I’d rather put this out to encourage myself to improve it rather than let it languish in a “refactor” branch on GitHub.\nUPDATE: I did not beat the buzzer. It is currently 4:00AM the next day, and I am definitely not going to be deploying anything. Ironically, during this time I wrote the first posts about kicking The Gremlin and my Year of Rhythm, which is ironic considering The Gremlin certainly won tonight.\nNotes\n\nhttps://www.youtube.com/watch?v=0RFwyobtnKA\n"},"notes/dailies/2024-02-27":{"title":"2024-02-27","links":["notes/caveat-lector","notes/dailies/2024-02-26","articles/resume-ci-pipeline"],"tags":["csharp","python"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI didn’t get nearly as much C# done as I’d wanted to yesterday - while I’m a bit hesitant to say that “today is going to be a 100% effort day!”, considering how yesterday ended I’ve kept C# goals to a breezy middle-of-the-road, since I’d rather under- than over-set expectations.\nB-Block\n\nMore ChainSharp step testing.\n\nAs an aside, I think I’ve been dramatically over-complicating how I create separable PRs. This is one of my “Fuck, Theaux was right” moments that I increasingly have as I learn more C#. At some point, I’d like to do some gardening on philosophies for separable pull requests and commits.\n\n\n\nM-Block\n\nChecking on our internal project status - there’s likely tasks I can pick up, but my current work is the only very-large-web I have left to untangle (unless I’m forgetting something, which is likely.)\n\nE-Block\n\nToday’s E-block is a CGC day, so (sleep status pending) I’d like to work on actually taking what I have and uploading it to GitHub. This’ll mean taking a look at the Quartz build process.\n\nAnother aside - while I appreciate how much the developers of Quartz has made it user-friendly with a custom CLI, it abstracts away some of the usual development workflow and means I have to learn (and consequently fumble around with) a new thing. That said, I also don’t know jack shit about frontend development and there’s probably a good reason for that.\n\n\nOh, what’s this?? A friend of mine asked me to take a look over his resume. He’s still using the old LaTeX version of my resume template, so I’m real excited to get him moved over to the new Typst version (post pending). CGC blog stuff may get pushed back accordingly - not sure how high-capacity I’m feeling now at 5pm\n\nToday’s Report\nN/A\nNotes\n\nhttps://mypy-lang.org/\nhttps://github.com/apache/spark/blob/master/python/mypy.ini\nhttps://www.youtube.com/watch?v=xZYZEGHybqQ\nhttps://engineering.blackrock.com/static-type-checking-in-python-where-did-the-ducks-go-d17881d3205e - type hinting to static checks in mypy at a gradual pace\nhttps://github.com/kaiko-ai/typedspark Holy shit - it does exist!!\nhttps://typedspark.readthedocs.io/en/latest/index.html words cannot describe how excited i am??\n"},"notes/dailies/2024-02-28":{"title":"2024-02-28","links":["notes/caveat-lector","notes/dailies/2024-02-27","notes/dailies/2024-02-26","notes/putting-selfcontrol-on-raycast","notes/dailies/2024-02-25","tags/gremlin-kicking","notes/raycast-review"],"tags":["bash","csharp","gremlin-kicking"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nWhoops! Fell asleep at a reasonable hour yesterday, and didn’t get jack squat from my E-block done. That said, considering the day before, the sleep was very welcome. And - not to break my arm patting myself on the back - I did say that everything in that block was tentative.\nToday is pretty much the same thing as yesterday - ChainSharp does set things up in such a way that most work is “Today, I make another Step!” and that, plus not giving too many details for private projects, means that the B- and E-blocks for probably the rest of this week are not going to be too spicy and different.\nB-Block\n\nWorking on ChainSharp steps for private project\n\nM-Block\n\nWorking on ChainSharp step tests for private project\n\nE-Block\n\nThis… we’ll see. Today isn’t technically a CGC day - those tend to be Mondays, Tuesdays and Thursdays. However, yesterday was less than productive, so depending on my partner’s schedule (she may be going climbing) I’ll probably be staying in the office a bit later for CGC.\nIf CGC work happens today, current priority list (I should store these on an actual list app) is:\n\nResume reviews - 3 pending for two students and a friend\nQuartz deployment to GitHub Pages\nQuartz customization - likely a custom index page\n\n\n\nToday’s Report\n\n\n8PM Update: Hmmm… I think I’m going to pivot off of resumes. For an internal project, it’ll be in my best interest to get a bit of progress down on graph analysis & generation in TypeScript. I’ve already wasted (ironically) enough CGC time today on creating a SelfControl extension for RayCast. I think the reviews can wait until this weekend - likely Sunday, but I’ll try to get those done before then based on ✨ vibes 🌈.\nIdeally, I’d like to have a Jupyter-ish environment to prototype frontend - likely, this means picking up where I left off the other day with CodeSwings, and doing some horticulture on the TypeScript analog to Python’s Pandas/C#‘s LINQ, Data Forge.\n\n\n…\nOkay - so technically I did most of what I set out to do today. Left myself a bit of wiggle room on the E-block. Again. If you squint your eyes and tilt your head, foresight and unreliability do look quite similar.\nI have decided I’m very excited about the SelfControl on Raycast stuff. Of all the things that rattle around in my skull, the xkcd post about time saved vs time spent automating is the most rattle-y. After mulling it over (while i was doing it, which is the perfect time to second-guess yourself) I decided the juice was worth the squeeze if it means I can more reliably pull myself out of doomscrolls and death spirals.\nWhen it comes to the art of gremlin-kicking, I do think that Raycast is the greatest set of steel-toed boots I own. It’s not the worst thing in the world that they now have a bit more weight in the heel with SelfControl tacked on.\n\nI will, however, also admit that - in terms of deliverables - the squeeze also squoze(?) out some time for other things I was hoping to do today. Hopefully trimming the doomscrolling fat makes up the time soon. Other than that slight detour, my CGC priorities remain generally the same and some of today’s list will likely get recycled into Friday. Tomorrow will be a lighter report day - CGC work is taking a backseat to watching the new(ish) Mean Girls with my partner, and then likely cleansing our palettes with the original Mean Girls afterwards. Taking a backseat? Classic Regina.\nIn a buzzer-beater, I learned a bit about D3 and finally settled on how to use CodeSwings in such a way that I can have them interact with Quartz internals. Maybe I am a frontend guy?? 😎\n(i am not.)\nNotes\n\nhttps://github.blog/2024-02-28-how-were-using-github-projects-to-standardize-our-workflows-and-stay-aligned/ - perhaps Projects is actually becoming… good? What a time to be alive!\nhttps://www.rawgraphs.io/ - Implementation as Backstage Plugin or Electron App?\nhttps://github.com/rawgraphs/rawgraphs-app - unfortunately not the type of “app” i was hoping for.\nhttps://github.com/jessejanderson/skylink - would be nice to do a popup as an Arc boost\nhttps://github.com/raycast/extensions/tree/c524392d80b35348811bae59831f29bfdbc34432/extensions/youtube-music/ - I’d like to, at some point, look at forking & adding the ability to add a song to a playlist. the selfcontrol stuff was quite a gateway drug, although i’ll have to adapt to using TypeScript for extensions rather than creating shitty, poorly-tested bash.\n"},"notes/dailies/2024-02-29":{"title":"2024-02-29","links":["notes/caveat-lector","notes/putting-selfcontrol-on-raycast"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nOkay! With myself SelfControl’d this morning, feeling very optimistic today!! I think, today, I can finish up my part in the MVP of an internal project. As a treat, I’m going to take a closer look at tuning up our old Backstage deployment. I’ve been feeling a whole lot better about my TypeScript knowledge & workflows as of late - and my engineering in general - so taking another look at Backstage after ~8 months feels like it may be refreshing.\nB-Block\n\nFinalize MVP parts for internal project\n\nM-Block\n\nRe-clone and get Backstage local environment running\nLook into Backstage Plugins\n\nE-Block\n\nNone! It’s Mean Girls night, baybeeeeee 😎\n\nToday’s Report\n\nUPDATE 3PM: The SelfControl for Raycast integration was, in fact, worth the time spent. Today’s B&M blocks have been the most productive in probably 2-3 weeks 🎉\n\nSlight end-of-day, while I have the laptop open - we ended up stopping the new Mean Girls after about 10 minutes and just watching the old one instead.\nNotes\n\nhttps://kindavim.app/ - vim everywhere on macos. May automate some of the less-than-stellar shortcuts i’ve baked myself\nthere are few terms i despise more than “tribal knowledge.” at some point this will be written about.\nhttps://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca - Happy leap day!\nhttps://www.perkins.org/resource/how-write-alt-text-and-image-descriptions-visually-impaired/ - resource for writing alt text on images\n"},"notes/dailies/2024-03-01":{"title":"2024-03-01","links":["notes/caveat-lector","articles/binglish"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI think today is likely going to be lighter day, likely finishing up assigned work during the B-block - I have a couple last-minute touches to an internal MVP, but not sure to what extent my time is booked up for the rest of the day. May take M-block to do a bit of light research on Backstage plugins.\nB-Block\n\nQuick horticulture on (free) C# code coverage libraries\n\nM-Block\n\nBackstage horticulturie\n\nE-Block\n\nResume review - for real, this time!!\nActions/Quartz deployment\n\nToday’s Report\n\nUPDATE 3:00PM: Ended up writing an article about binglish, which is absolutely not what i had planned for the afternoon but i’m certainly not mad about it. from a quick cursory online search… i don’t think anybody else has coined this term yet?? At least not for the same concept - i was only able to find references to one chrome extension (ironic) and a somewhat(?) used term for british-indian-english (which, idk, maybe it’s far larger a term but not one that culturally/algorithmically would be at the tippity-top of my SLC-based search results, even on incognito) \nUPDATE 6:00PM: i was excited enough about that post to actually publish my blog. I was about to excitedly hyperlink to it, but… I suppose this will actually be on there now. There is something about seeing what i’ve been putting into a dusty refactor/ branch on GitHub actually be on The Internet™ that… I’m frankly not certain how to feel about.\nThere is something burning in me to really quickly learn everything more i need to know about TypeScript frontend development and finish the blog formatting posthaste, but I think that will need to wait for another time. I am hungry, and must depart.\n\nSee above - stopping CGC work and closing my laptop for the day. Perhaps I will play… Factorio???\n🫡\nNotes\n\nhttps://www.hanselman.com/blog/altcover-and-reportgenerator-give-amazing-code-coverage-on-net-core - Free code coverage for C#. Uncertain about Rider compat >:l\nhttps://youtu.be/_wxU3z9VxOY?si=Y2vuh_PH5_yHay9m&t=267 - suavemente\nhttps://kyla.substack.com/p/why-we-dont-trust-each-other-anymore - words, words, words (literally and topically)\nhttps://open.substack.com/pub/kyla/p/why-we-dont-trust-each-other-anymore?selection=f9b3b76b-bbe1-46c1-87f0-57b3d84594b1&utm_campaign=post-share-selection&utm_medium=web - poetry isn’t usually my thing but this got me\nhttps://smartbear.com/learn/code-review/best-practices-for-peer-code-review/ - Study on Pull Request ideal review size. I have no idea how big PRs should be and it falls into the same “economic value of lines of code” issue that I’ve looked at before. There’s lots of metrics - lines changed? files changed” feature count? subfeature count?\nhttps://smallbusinessprogramming.com/optimal-pull-request-size/ - More research resources I need to take a look at. Someday I will have an opinion.\n"},"notes/dailies/2024-03-02":{"title":"2024-03-02","links":["notes/caveat-lector","tags/roblox","notes/dailies/2024-03-01"],"tags":["scratch"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday wasn’t actually a CGC day, but I’m finding myself with some time at the tail end of the day after some sudden super-fun springtime winter storms have floated across Salt Lake City and tanked my plans to get tastefully wine blasted tonight.\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\nToday was my partner’s first swim meet since she did triathlons in college! she did incredibly well - I wish that I knew more about photography so I could take cooler pictures of her when she’s swimming that we can send to our families. Maybe, someday, I’ll be a Photography Guy™.\nI ended up sitting next to a very nice group of kids. I had brought Kenneth Arrow’s The Limits of Organization - with no irony in the slightest, I put it away after seeing that the two kids next to me were reading objectively cooler books. They were very nice - we talked about video games and programming and played Exploding Kittens between meet heats. I cracked open my laptop and they showed me a few programs they’d made in Scratch, which brought back some memories of working with 4th-6th great students at Dr. David Johnson’s GREAT Camp back when I was a sophomore in college.\nSince teaching both that camp and working as a center director at a local Mathnasium for about a year around the same time, it’s been awhile since interacting with Modern Youths™, save for a few niche Roblox communities I lurk in for CGC-tangential projects. It is very cool to see how this generation (gen Alpha? i haven’t kept up much with the newfangled terminology around this generation) has a more… native? approach to technology. It makes sense, considering there will probably (hopefully) never be a moment they go without it.\nThey brought up roblox and I mentioned I’d played when I was their age - the oldest asked a few questions about moving from the block-based coding on Scratch to text-based coding. I feel it is a more interesting question than I was willing to inundate him with (i said “not really!” and capped it off at that.) - in hindsight, it was a pretty big transition for me. That said, I wonder if there exists a future where block-based coding comes back in a way, made possible by stronger generative code solutions to handle minute details within blocks. \nUnironically, I do think I would appreciate a graphical, scratch-like interface for cloud environments. That would be a pretty kickass Terraform frontend.\nAs a slight update on yesterday’s post about binglish - I did post it in a few places (and it didn’t even go viral??? shocked, offended, confused). I think the only piece of text feedback I got was in the Quartz discord, where somebody mentioned that albeit funny the term was one they were familiar with as a colonist term for British-Indian-English.\nI’m torn - by no means is this a Big Thing i’m doing with this blog, nor do I think it ever will be. Certainly not to the extent that the Venn diagrams of people who would read my notes and who would recognize “binglish” in that context would overlap. I also don’t know how I would go about checking - it is interesting that geography is a somewhat soft lock on that kind of cultural knowledge. Even from setting my VPN to Delhi, popping my browser into incognito and doing a (translated, obviously) search, I still get a “urban dictionary,” “stop trying to make fetch happen” vibe from the term. I’ll keep the post up purely because i like it (everybody, appreciate me!), but if that ever does become An Issue™ i will absolutely reconsider that decision.\nNotes"},"notes/dailies/2024-03-03":{"title":"2024-03-03","links":["notes/caveat-lector","notes/scratch/warning-about-slabtops"],"tags":["hardware","engineering"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday is a bit strange - I’m currently on a kick of only gaming with friends (gaming solo, for whatever reason, has started to feel like “wasting time” (which is totally not a statement on the virtue of solo gaming, this is just how I feel about it at the moment)). After a bit of a misadventure trying to turn an old laptop into a well-ventilated server, a friend’s brother very graciously offered me some spare PC parts he had lying around so I could (properly, this time) start a home lab for running miscellaneous things, such as dedicated multiplayer servers at my home.\nI highly doubt any CGC work will get done today - I’d vastly prefer setting up the server and playing around with some homelab setup experimentation.\nB-Block\n\nPick up desktop case & parts\nClean out, assemble desktop case & parts\n\nM-Block\n\nPick up a new bed frame for a new mattress arriving later this week\n\nE-Block\n\nAssemble bed frame\nWork on desktop server\n\nToday’s Report\nVery minor EOD report - was able to get a Windows Proxmox setup with GPU passthrough and VirtIO set up today. With the addition of Moonlight & Sunshine, game streaming is now possible! I cannot wait to use this to bully invite my partner to join in game nights with us, now that we have a dedicated(ish) Windows machine for her to use.\n\nBy no means is running Lethal Company at a consistent HDx60fps a technological marvel, but I am very satisfied with the work tonight. While my Steam Deck is probably going to still be my go-to because I hate myself and love debugging, this was a fun little tangent.\nAs an aside - a lot of that setup was cobbling together random support forum posts and other weird shit - at one point I spuriously bought a pack of headless HDMI dummies from Amazon thinking I’d need them. I’d like to toss a quick note here at some point this week to elaborate on some of the missing steps between major guides.\nFuture work on the server (beyond just hosting multiplayer servers) will likely be looking at some actual capital-H-capital-L HomeLab stuff like HomeAssistant to bridge some of our disparate smart home devices into HomeKit so I can control them from my phone and computer a bit easier, but that’s for another night.\nNotes\n\nhttps://forum.proxmox.com/threads/pci-gpu-passthrough-on-proxmox-ve-8-windows-10-11.131002/ - okay, this one actually works.\n"},"notes/dailies/2024-03-04":{"title":"2024-03-04","links":["notes/caveat-lector","notes/season-of-rhythm","notes/dailies/2024-03-03"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nBack to the work week! We haven’t had sprint planning, yet, so I’m not totally sure what today/this week has in store quite yet - I’ll loop back around and update blocks once I have ‘em.\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nSo, this particular report goes… well into tomorrow. I’ve been doing pretty good on my sleep rhythm lately, so let’s consider this 6:00AM posting a bit of a relapse.\nI need to get… a couple hours of sleep before I need to be up in the morning, especially considering it’s my partners birthday(!), so this’ll be a brief EOD. I will personally blame whoever it is that made this amazing set of proxmox LXC setup scripts for stealing my sleep tonight, in order to properly divert blame away from the true culprit: myself.\nNotes\n\nuhhhhh… quite the fuzzy match there, YouTube Music?\n\nhttps://gersom.nl/building-a-raycast-website-blocker - raycast blocker similar to Self Control\nhttps://www.raycast.com/tonka3000/homeassistant/commands - raycast extension for HomeAssistant, which is relevant to yesterday’s knock-on work\nhttps://docs.github.com/en/actions/managing-issues-and-pull-requests/closing-inactive-issues - action for closing stale issues, PM req\nTODO: Look up use of new on class method declaration in C#\n"},"notes/dailies/2024-03-05":{"title":"2024-03-05","links":["notes/caveat-lector"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday ended up being a sick day (for both myself and my partner, which unfortunately coincided with her birthday), so not much got done. Not good, not bad - not really sure how to feel about it. At the moment, it’s a bit dour.\nB-Block\n\nR&R\n\nM-Block\n\nR&R\n\nE-Block\n\nR&R\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\ni do appreciates some rest and recovery. in storywriting terms, we’d probably call this one a bottle episode.\nNotes\n\nhttps://tteck.github.io/Proxmox/ - Proxmox helpers\nhttps://arxiv.org/pdf/2403.01152.pdf - research on current generative AI forensics solutions\n"},"notes/dailies/2024-03-06":{"title":"2024-03-06","links":["notes/caveat-lector","notes/dailies/2024-03-04","notes/utah-office-consult","notes/supply-chain"],"tags":["aws"],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nI think today’s plan has me diving back into the wonderful world of DevOps, testing out internal DNS capabilities for development resources within VPCs. Thankfully server bullshit the other day has gotten me in a Domain Name State of Mind.\nI think E-block today is going to be fixing up the homelab server. I took apart all of the pieces to clean them but (from what my partner has told me — oops!) there’s a fan in there that isn’t balanced and constantly clicking, so it’ll be some investigating there.\nAlso excited to put in a couple extra pieces - I bought a cheap burner card (GTX 1030 for like $60) to dedicate to video encoding/decoding, along with a few other here-and-there parts to expand storage slots. So long, 256GB storage!\nB-Block\n\nStarting on internal AWS DNS module for Account Factory Terraform\nWhile I’m in DevOps land, I kinda want to take, like, 30 minutes and follow up on a weird concept I read about awhile back - unit testing Terraform code. I don’t totally understand how one would unit test… infrastructure configurations? but who knows, maybe it’ll blow my mind\n\nM-Block\n\nMeeting up with our PM to talk over some developer experience stuff - people problems are truly the hardest engineering problems\n\nE-Block\n\nN/A - I’m hanging out with my partner tonight, but depending on how long her plague-ridden body can handle doing things, I may do some hardware stuff tonight on the homelab server.\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes\n\nI’d like to eventually make the viz from the utah consult post a follow-up to the supply chain network post as an intro to that one guy on bluesky’s network graph viz guide\nhttps://apps.apple.com/us/app/proxmobo/id6447794447 - Proxmox mobile interface - very nice, 10/10 would recommend\nhttps://medium.com/@giuliodn/clone-and-backup-with-gparted-e1100219c1d7 - notes on transferring contents between hdrives with gparted\n"},"notes/dailies/2024-03-07":{"title":"2024-03-07","links":["notes/caveat-lector","notes/dailies/2024-03-03"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nToday’s plan is a bit more DevOps for work, and then some spring cleaning. Working on the new homelab server has, safe to say, unearthed a substantial amount of old hardware I had laying around in a box. If I don’t tidy up the living room, I may end up getting strangled in my sleep.\n\nThat said, the cat has fuckin’ loved the chaos. So many wires to attack - so little time between naps.\nB-Block\n\nCategorizing internal services into the internal LB/DNS\n\nM-Block\n\n\nLooking into GitHub Projects workflows through Actions. Yesterday was some messing about with actions/stale to manage some… pretty large batches of tickets at work. While this has seemed to do the trick so far, there was the realization that our current automation system would move all of the closed, stale tickets to our QA team.\nThere is currently a rolling boulder of about ~250 tickets slowly rolling towards our QA team that will squish them in 14 days’ time. God save their souls.\n\n\nE-Block\n\nSpring cleaning and playing around with the new dedicated GTX 1030 burner card in the homelab server\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes\n\ntest!\n"},"notes/dailies/2024-03-08":{"title":"2024-03-08","links":["notes/caveat-lector"],"tags":[],"content":"\nCAVEAT LECTOR: This is a daily note! Sometimes they’ll be structured, sometimes they won’t. These are more for the benefit of my near- and long-term future self, but I do tend to publish them in case they’re somehow helpful for other people.\n\nToday’s Plan\nN/A\nB-Block\n\nN/A\n\nM-Block\n\nN/A\n\nE-Block\n\nN/A\n\nToday’s Report\n\nTo have the full intended experience, please listen to the Pikmin 2 “Today’s Report” theme while reading & writing this\n\nN/A\nNotes"},"notes/dailies/index":{"title":"Daily Notes","links":["notes/caveat-lector","notes/digital-gardening-with-quartz"],"tags":[],"content":"These are daily notes, where I log and track progress on ongoing projects and make notes for myself later. These are largely for my own benefit, and are here in case they’re helpful to myself (or, somehow, others) in the future.\nHowever, I’d describe these as loose, at best. Caveat lector.\nOne of the approaches to digital gardening is “learning in public” - to that end, I plan on continuing to outwardly publish these."},"notes/digital-economies":{"title":"What is a Digital Economy?","links":["notes/stability-of-marriage"],"tags":["economics","data","engineering"],"content":"Digital economies are primarily-online economies that you might find in multiplayer games, network and cloud resource optimizations, or other digital spaces where you’d find a whole lot of chaos and complications. Digital economies are interesting - to me, at least - because the digital medium they behave in offer incredible opportunities for creating, researching & understanding market designs, enforced by digital systems, that you may not find in the real world.\nDespite being digital, they are very, very real."},"notes/digital-gardening-with-quartz":{"title":"Kicking off a Digital Garden with Quartz","links":["articles/structured-streaming","articles/hello-blog"],"tags":["engineering","typescript","gremlin-kicking","horticulture"],"content":"I’ve decided that I’m pretty bad at capital-B Blogging™. The last “post” I made (as of writing) was the Databricks guest post on Spark Structured Streaming that I did back when I worked at M Science in 2022. That particular post went through a few different stages of revisions:\n\nRevising initial drafts as I learned more about Structured Streaming as a concept\nRevising “personally final” drafts with the Structured Streaming engineering team at Databricks\nRevising “technically final” drafts with somebody from our company’s internal marketing team to make sure I didn’t sound like a doofus/didn’t make it seem like the company hired doofuses (it hired me, so it totally did, but that’s obviously not something to broadcast openly)\nRevising the “marketing final” draft with a lawyer to make sure I wasn’t blabbing trade secrets to the general public\nRevising the “legally final” draft with Databricks’ blog team to make sure the formatting was right (which I didn’t do a good job of, apparently - the final published draft ended up having some weird formatting errors. Not totally sure what happened there ¯\\(ツ)/¯ )\n\nThat was quite a bit more than I’d expected when initially pitching “What if we published our internal guide for everybody?“. That, along with starting a new job that introduced me to a far higher standard for engineering, raised my own internal bar for “what should I put on the internet?” Since then, I’ve written quite a few posts that I’d describe as ~60% “done,” but didn’t end up hurdling internal (and arbitrary) bar for publishing.\nConsidering the editorial standards I started this blog with, the idea that I’ve had any bar at all is a bit funny.\nThe cost of learning is teaching\nAs somebody that has benefitted immensely from the free body of knowledge that exists on the internet, this doesn’t make me happy. A graveyard of posts I’ve arbitrarily deemed “unfinished” isn’t particularly helpful to anybody, including myself. Just because a set of knowledge isn’t refined enough to be perfectly, 100% clear to a broad audience doesn’t mean it wouldn’t be helpful to somebody, including myself in the future.\nI was fortunate enough to stumble on Maggie Appleton’s Ethos on Digital Gardening, which notably resonated with me more than many things I’d read in the recent past. In particular, this diagram she designed clicked something in my brain that’d remained un-clicked for quite awhile:\n\n\nbrief aside: Maggie brings a level of polish and class to doodling that is frankly enviable.\n\nThe cost of perfection is infinite\nPutting things on a spectrum of “chaos” to “cultivated”, in conjunction with the idea that “the cost of perfection is infinite” (if not asymptotic), puts into hardly-uncertain terms that simply because a thing is not perfect, or close to it, necessarily means that it is unhelpful and should die a slow death in a draft bin.\n"},"notes/index":{"title":"Notes","links":["articles/","notes/dailies/","notes/scratch/"],"tags":[],"content":"These are notes - they’re things that are structured, albeit not necessarily as structured or refined as CGC articles.\nIn general, there are three kinds of notes I make:\n\nGeneral notes, which are found on this page\nDaily Notes, which contain daily logs for my own benefit\nScratch Notes, which really just means “none of the above”\n"},"notes/literal-scratch-piano":{"title":"From the Archive: Scratch Piano Application","links":["notes/dailies/2024-03-02"],"tags":["engineering","mentoring","scratch"],"content":"Back in 2018, I taught at the GREAT Camp at the University of Utah as an instructor for ~4th-6th grade students interested in intro programming in Scratch. Honestly, as a CS student at the time, it was actually really cool to try and put things I’d made in actual languages and translate them into Scratch, especially if they required manually implementing data structures like stacks and heaps.\nThis was a fun project to try and explain music - something that every Utah child learns, short of by-law - and also a way to cope with the fact that in Spring of 2018 I’d unintentionally signed up to take a weed-out Intro to Music Theory course at university.\n"},"notes/literal-scratch-quicksort":{"title":"From The Archive: Scratch Quicksort","links":["notes/literal-scratch-piano","notes/dailies/2024-03-02"],"tags":["engineering","mentoring","scratch"],"content":"As an addendum to the Scratch Piano Application, I also around the same time cooked up an implementation of QuickSort. At my partner’s recent swim meet I sat next to a couple kids who’ve been learning Scratch and they were showing off some games they’d made.\ni was shocked - when it was my turn to show off, they didn’t seem very impressed by this.\n\nhonestly, the sort isn’t the weird thing - it’s the code itself that makes me, with 6 years of hindsight, think “…why the fuck would I make this?”\n"},"notes/over-under-engineering":{"title":"The Over/Unders of Over- and Under-Engineering","links":["notes/digital-gardening-with-quartz","notes/over-under-engineering","tags/python","articles/structured-streaming"],"tags":["engineering","gremlin-kicking"],"content":"\n\n\n\nPremature optimization Over-engineering is the root of all evil\n— Donald Knuth\n— Sir Tony Hoare\n— Me, just now\n\n\n\n\nI think that over-engineering is the single greatest contributor to starting projects and never finishing them.\n\nLet’s define follow-through rate as the ratio of projects started to projects released. Not “completed”, since that’s an irrational way to think about projects.\n\nLooking back at periods of my life, I feel like my follow-through rate on projects was highest when I was 12 years old. At that point, my “projects” were:\n\nMy grades in high school\nWriting shitty programs on my TI-84\nWriting small games on Roblox\n\n13 years is long enough ago that, for the sake of simple math, my follow-through rate was 100%. Gee, what a reliable kid I was!\nI can name 4 periods of my life where the amount I learned about engineering grew at a more-rapid-than-usual pace:\n\n2016: I began studying computer science in my undergraduate\n2018: In trying to build up my resume, I started taking writing open-source and release-able projects more seriously\n2020: I got my first full-time job as a data analyst/software engineer writing data pipelines in Python and Spark\n2023: I got my second full-time job writing general software in [[csharp|C#]], with incredibly smart capital-E Engineers™ that were also incredibly good mentors\n\nWhile it feels great to know more, learning has caused me a fundamental issue: it’s easier to be bad at something on accident than on purpose.\nI’ve increasingly noticed myself trying to apply the things I’ve learned to new projects, causing a whole lot of up-front work to get a project started. Putting yourself in a prison of making the “best” choices at the very start of the project is incredibly demotivating and absolutely tanks the odds that a project started will someday be a project finished. Ironically, it’s future-proofing for a future that doesn’t happen.\nLet’s say, hypothetically, that my project follow-through rate started at 100% and dropped by a third following each learning period. After 4 learning periods, that would leave me at…\n(1.00−0.30)5=0.16\nYeesh. 16% follow-through rate sounds rough, but when I look at a recent history of what I’ve accomplished versus what I’ve wanted to accomplish, the number seems somewhat reasonable.\n\n"},"notes/putting-selfcontrol-on-raycast":{"title":"Watering Down SelfControl into Self Restraint","links":["notes/putting-selfcontrol-on-raycast","notes/season-of-rhythm","notes/arc-review","notes/the-quest-to-kick-the-gremlin","notes/raycast-review","notes/caveat-lector","notes/dailies/2024-02-28"],"tags":["gremlin-kicking","engineering","bash"],"content":"\nI talk a lot in this post. You may want to skip to the useful part.\n\nSo, during this recent period of trying to break quite a few years of bad work habits, I’ve been putting up little guardrails in my own life to keep myself on-track when I want to stay on-track. One issue I’ve run into - especially during a particularly tumultuous US election year - is a tendency to check the news.\nAnd then, five minutes later, check the news again.\n…and again\n…and again.\nI’ve rationalized it for awhile by saying “I work in politics - of course I should stay up to date!” However, that’s a lie - my day job is not in politics. At best, It’s working on software adjacent to people who are adjacent to politics.\nTo alleviate that for awhile, I had used a Chrome-specific app called StayFocused to block a pretty broad swath of websites, but ran into two issues:\n\nStayFocused allows you to schedule blocks, but only for predetermined amounts of time, and only a single block per day. This was not quite as flexible as I was comfortable with - I do like to check the news, my email, or Bluesky at lunch, or if I get off of work a bit earlier than expected.\nI started using Arc Browser with three different profiles - Personal, Work and CGC - and each one has its own Chrome plugins. Because of this, I’d have to configure/reconfigure/update the StayFocused installation in triplicate, which due to the way their app is set up is incredibly hard to do.\nTheir app kept hijacking my browser to notify me of updates, and I didn’t see a readily-available way to do that. Ironically, this had the effect of absolutely shattering my focus.\n\nI ended up uninstalling it and going with something a bit heavier-duty. SelfControl is an application for MacOS that blocks out apps across the entire operating system. I had also seen Focus listed as a possible solution, but… $49? For effectively the same thing with a prettier interface? yeesh.\nIronically, though, SelfControl requires self control to use, which is exactly what got me in this situation to begin with. It is incredibly easy to “take a break” and then just-a-couple-more-minutes yourself out of any semblance of flow. As a nice surprise, though, SelfControl comes with a CLI, which means we can use it for some more advanced workflows! We can use this to do two things:\n\nSchedule blocks of self-control for the future, e.g. “In 10 minutes, I will focus for 50 minutes”; and\nConnect that behavior to Raycast, which will help us lower the bar to starting Raycast (as, admittedly, having to swipe back to the main Mac desktop is a pain in the ass and puts it out-of-the-way)\n\nThe Useful Part\nI’ve added a couple of useful bash scripts to a SelfControl Raycast Plugin for others to use. At some point, I’ll look into the process for getting them added to the actual Raycast extension store. You can add these by cloning the repository and adding it in the Raycast settings as a “Script Directory.”\n\nTHAT BEING SAID: I’ve used the term caveat lector quite a bit to warn people that I’m just some guy. This goes doubly here! This is software that has literally only been tested, by me, a handful of times, that I made while (ironically) procrastinating other things I should be working on. To say it isn’t well-tested would be a dramatic understatement. The creators of SelfControl warn that it’s a tool that, if misused, can have side effects. So to that end… what would the phrase even be?\n\nHuh. I guess the Romans didn’t do much file sharing.\nCaveat download!"},"notes/qamo":{"title":"Quantitative Analysis of Markets & Organizations","links":["tags/economics"],"tags":["economics"],"content":"In 2022, I graduated from the University of Utah with a degree in Quantitative Analysis of Markets & Organizations (QAMO, more-or-less quantitative economics).\nWords cannot describe how much I appreciate the mentorship I received from my professors - especially Scott Schaefer, the program director who was incredibly kind in providing a level of flexibility that, frankly, was the only reason I was able to graduate while working full-time.\nThat said, I do wish the name of the degree wasn’t such a pain in the ass to type out."},"notes/raycast-review":{"title":"Diary of a Raycastaway","links":[],"tags":["gremlin-kicking"],"content":"Recently, I stumbled on Raycast - a MacOS Spotlight replacement that I would highly recommend to everybody, not just engineers."},"notes/robloxaville-remaster":{"title":"Thoughts on the bad 2017 Robloxaville Remaster","links":["articles/robloxaville","notes/over-under-engineering","notes/digital-gardening-with-quartz"],"tags":["roblox","lua","games","engineering"],"content":"When I was in high school, I dabbled a bit in programming on Roblox. Due to some pretty glaring security concerns, a project started over the summer of 2017 to remaster Robloxaville. I’ll be the first to admit that the remaster is substantially less fun to play than the original. While part of this constraint was time - the original was made over the course of ~4 years, while the remaster was made in ~3 months - it’s undeniable that the velocity of the original project was simply far higher because it was under-engineered.\nThe original project was largely made by my mom, who studied programming during her physics-chemistry-geology triple(!!!) major in college, with some tangential work from me, who was a literal child. Not to sell short the sheer amount of work she put into the project, but between a lack of formal software engineering and the pretty glaring shortcomings of the Roblox engine itself meant that, frankly, it would’ve been impossible to engineer any of it properly to begin with. By the time the summer of 2017 rolled around and the remaster started, two circumstances collided:\n\nPlatform developers were now being paid, which introduced a far higher bar on quality of work being done\nI had just finished my first semester of a degree in computer science and learned tip-of-the-iceberg concepts of what constituted “good” software.\n\nDespite happening 7 years ago as of the time of writing, I remember how absolutely stressful that summer was. I spent wasted a lot of time worried that the code I was writing wasn’t engineered enough, and ended up designing a lot of bad and convoluted systems meant to save myself time in a future of development on that project that never came.\nThere exists a graveyard of projects and posts between 2017 and today that have fallen victim of arbitrary bars for under-engineering that I’ve put on my own work."},"notes/scratch/brevity":{"title":"brevity is no longer the soul of wit","links":["articles/binglish"],"tags":["horticulture"],"content":"when he wrote “brevity is the soul of wit”, shakespeare clearly did not consider that someday AI generated briefs would consume the english language"},"notes/scratch/index":{"title":"Scratch Notes","links":["tags/horticulture"],"tags":[],"content":"For all intents and purposes, these are the digital gardening equivalent of shitposts and shower thoughts."},"notes/scratch/press-f-to-commit":{"title":"Press F to Commit","links":[],"tags":["visualizations"],"content":"A friend of mine - who is one of the most consistent people I know - was called in over the weekend for an emergency patch deployment at work.\nThe weekday streak is over; long live the weekday streak!\n"},"notes/scratch/some1-entry":{"title":"Entries to SOME 1","links":["notes/stability-of-marriage"],"tags":["doodles","economics","visualizations","python"],"content":"Awhile ago, the channel 3blue1brown announced an internship and public competition, Summer of Math Education - at the time, I submitted some half-assed entries that I’ve kept around since then.\nBachelor Analysis\n\nExcerpts from Stable Marriage\nLargely taken from a presentation on stable matching algorithms\n\n\n\nOptimal Stopping Problem\n"},"notes/scratch/the-best-side-of-the-road":{"title":"What is the best side of the road to drive on?","links":[],"tags":[],"content":"\nThe best side of the road to drive on is the side everybody else has agreed to drive on.\n\nI don’t remember where I first heard this, but I think about it every day."},"notes/scratch/unstable-marriage":{"title":"Unstable Marriage","links":["notes/stability-of-marriage"],"tags":["economics","data"],"content":"I’ve spent a whole lot of time researching matchmaking algorithms, and yet I’d never considered - didn’t even mention in the presentation - what would happen in odd-numbered sets.\nthe implications are frankly funnier than I would have imagined"},"notes/scratch/warning-about-slabtops":{"title":"Before You Slabtop Your Laptop: A Brief Warning","links":[],"tags":["engineering","hardware"],"content":"I recently had a misadventure while trying to slabtop (remove the LCD panel of a laptop to use it as a server) an old Dell Alienware G2 15. I didn’t see this piece of friendly advice while Googling around before making my attempt. I really wish I had - it would’ve saved me a lot of time, trouble, and a motherboard to boot (pun intended).\nTo contribute to the body of all knowledge, I hope you (you, the person googling “how to slabtop a laptop” right now) see this before you whip out the screwdriver and go to town on your old burner:\nSearch “<YOUR LAPTOP MODEL> LCD Panel POST Check Beeps” before you attempt to slabtop your laptop!!\nComputers run without screens all the time - we call them servers, and they run everything, so the possibility of a laptop manufacturer literally not letting a computer complete POST check without an LCD panel wasn’t even something that crossed my mind. However, if you google the above, you’ll run into lots of posts of people who hear a handful of beeps when their LCD display is disconnected, signifying that the POST process didn’t complete. This will absolutely fuck you over if your laptop manufacturer is one of the many who have this check in place.\nWhile I believe it is possible to do this on a PC (not a Mac, where slabtopping has been documented extensively), I personally ended up frying the motherboard after about 5 hours of cutting away at the stupid fucking thing. If this helps even a single person, I will be immensely happy."},"notes/season-of-rhythm":{"title":"Spencer's Season of Rhythm","links":["notes/the-quest-to-kick-the-gremlin","notes/over-under-engineering","tags/gremlin-kicking"],"tags":[],"content":"In the spirit of setting themes instead of resolutions, I’ve adopted a seasonal (or perhaps year-long - who knows?) theme for my own life:\nThe Season of 🎵 Rhythm! ✨\nDuring my Season of 🎵 Rhythm! ✨, I want to establish healthier cadences to how I spend my time day-to-day, and to be far more intentional with how I spend my time. This is largely a response to a broad problem in my life that I’ve felt for some time now.\nI am not a person who, at any point, has ever formed good, lasting, healthy habits.\nThrough high school, into college, and continuing into my adult life, I have always been a very “whichever way the wind blows” kind of personality. This hasn’t been entirely without its upsides. A coworker once described me as “very good to have in emergencies.” While I’d agree with that characterization, it’s because my tendency embrace The Gremlin has meant I have been a co-conspirator to many of the emergencies in which I’ve learned to work well under pressure. If you do enough work, enough times, an hour before a deadline, you become very good at doing lots of work with hours before a deadline.\nThe downside to this is… fairly obvious. In the last year, I started working for and with a very emotionally healthy team of engineers who are remarkable at pacing themselves, doing diligent and level-headed work, and avoiding emergencies when possible - something that drove me absolutely insane at times during my first year. After having seen - and felt - how much healthier this environment is and how much more it can accomplish - particularly in collaborative and non-competitive settings - I’ve accepted it’s the way I’d ought to work, too.\nAs an additional downside to the way I worked, only having a cohesive and consistent pace of work meant that larger projects - things that aren’t done in one all-nighter but have to happen over the course of weeks and months - had a tendency to fall into obscurity. I’d attribute some of that to the way I have structured many of these projects, but constantly losing the thread between bursts of motivation means that bigger plans can easily turn into aimless wandering.\nSeason of Rhythm is a time to actively, rather than passively, establish good “rhythms” and routines that lower the variance of my own work and habits. The goal isn’t to shed the “works well in emergencies” characterization - on the face of it, I don’t think that’s a bad thing. However, where I’d describe the previous variance of my own ability to function personally and professionally as a 25-50% pace during “peace-time” and 200-400% pace during emergencies, I’d vastly prefer to even this out to something that doesn’t feel like personal and occupational whiplash: maybe 80% day-to-day and 120% during emergencies, as a vibes-y estimate.\nAfter two months, I’m on a really good track. A whole lot of gremlin-kicking posts this year will probably be related to tools I’ve found that help me keep on track, and I’m excited to see how the trajectory of this next 4-10 months"},"notes/stability-of-marriage":{"title":"College Admissions and the Stability of Marriage","links":["notes/qamo","tags/doodles","notes/scratch/some1-entry"],"tags":["doodles","economics","python"],"content":"In college, my area of focus during my economics degree was non-market environments, which encompass the areas of economics where money isn’t used for moral or practical reasons.\nA presentation I’m particularly proud of is a presentation on David Gale and Lloyd Shapley’s 1962 paper College Admissions and the Stability of Marriage\n\nThis presentation happened at a personally odd time during a globally odd year, and - due to the practical limitation of only having my iPad available while I was in-patient at the University of Utah - was the first time I started using doodles in the vast majority of my presentations.\nThere are a few things that were cut for the presentation for time - in particular, the incredibly interesting concept of matchmaking lattices. Eventually, I’d like to include some additional written resources here on the topic, because it’s pretty cool. One of the cut slides is available here.\nThe absolutely incredible Dr. Allison Stashko is the only reason this presentation was possible - she was incredibly kind and encouraging during a difficult period, and is in large part the reason why non-market environments are my primary interest in economics."},"notes/strong-and-weak-opinions":{"title":"let opinion = null","links":["notes/strong-and-weak-opinions","tags/roblox","assets/Pasted-image-20240305234056.png","tags/python","notes/scratch/the-best-side-of-the-road"],"tags":["engineering"],"content":"\nThis note ended up having a lot of front-loaded context - feel free to skip to the point\n\nOpinionated Software\nThere’s a term that floats around that feels new. It’s not something that I’d ever seen in my computer science portions of my undergraduate, but as I’ve entered into industry and started both using and participating in development of a broader range of software, the sharp increase in frequency that I’ve seen this term:\n\n[Proper noun] is an opinionated [general noun]\n\nWhat… does this mean? I’d never seen it in an academic slide deck before, but I can name a few high-profile places in my own engineering. While it’s usually surrounding frameworks, I’ve seen it used in other places as well:\n\nDuring C# related work - I have previously used Wrapt as a [[csharp|C#]] web API scaffolding tool, which describes its default options as opinionated\n\nTo chase down a chain of opinions, Wrapt’s opinions are based on some of the Vertical Slice Architecture (VSA) opinions that I first saw from Jimmy Bogart’s post on VSA at the recommendation of my team at NWYC when I first started writing & contributing to commercial C# applications\n\n\nDuring roblox-related CGC work: “Flamework is a highly opinionated game framework”\n\nInterestingly, this description has since been replaced to say (as of writing) “Flamework is an extensible game framework.” - I thought I was going insane in trailing back after seeing that phrase there months ago and not finding it, but a stale Google Index reference shows that i’m not crazy (on this one). I am curious about the onus behind the wording change, because I do actually believe that new description better captures of the intent of the Flamework package.\n\n\nStumbling on the black python formatter while wrangling Databricks codebases at M Science\n\nThis is probably the most severe(?) case of opinionated software I’ve ever seen - it is literally named after the Henry Ford quote regarding available paint jobs for the Model T: “Any color the customer wants, as long as it’s black”\nThe black repository is also home to one of my favorite GitHub Issues of all time, in which a senior staff engineer at Twitter requested the ability to configure 2-space tabs instead of 4-space tabs so that one of the most influential tech companies to ever exist could use it as the standard code formatter for their entire Python code base, to which the reply was a resounding “no.”\n\n\n\nAnybody who has ever seen the flame wars in the comments of Reddit threads, StackOverflow posts, or - frankly - between any call between more than, say, two engineers in the same field, opinions tend to run strong.\nWhen strong opinions collide, it can feel very much like watching an unstoppable force hit an immovable object. Especially when I was a data analyst on the way up to software engineering, I often found myself a junior (and rightfully silent) participant in long-winded, fruitless, and ultimately destructive conversations in which two parties who hold strong opinions talk past each other for… 10 minutes… 20 minutes… an hour, ultimately ending because one side or the other has to hop into a different call of the same flavor.\n(Want a real life example? Go ahead and pop “is <PROGRAMMING LANGUAGE A> better than <PROGRAMMING LANGUAGE B>?” into your search engine. One of my strong opinions is that 99.9% of those conversations are bullshit, wasted time, and that seeing them in the wild makes me want to close my laptop and walk into the ocean, my final thought before the air depletes from my lungs being that, at the very least, my decomposing body will contribute more back into The Universe than those people did by arguing complete fucking nonsense on the internet.)\nI think the way people sometimes approach having an opinion - or not having an opinion - is ultimately reductive, destructive, and slowly chisels away, bit by bit, hundreds of thousands of minutes, hours, and days of human life to the behest of our goals yet delight of the Reaper himself.\nThe Point\nI’m proposing, here, a way to a) properly classify your opinions and b) how to use those classifications to lead actually constructive conversations with others\nI put my own opinions into two categories:\n\nStrong Opinions: Opinions that I have built up over time and experience, and that I feel I have a compelling case for that clearly communicates the full scope of costs and benefits to the decisions that opinion leads me to propose\nWeak Opinions: These are the ones that I have that are built on sub-par information, that I can’t clearly communicate, or that are generally based on ✨ vibes 🌈\n\nWhen contributing to a conversation or argument on a topic, I’ve been trying really hard to ask myself: “Is the opinion I’m about to state a strong opinion?”\nHaving a weak opinion on a topic doesn’t necessarily mean it shouldn’t be mentioned at all. It does mean that it’s likely a point that, should somebody else have a stronger opinion, that opinion isn’t a hill I should consider dying on.\nThat said, having a strong opinion also doesn’t necessarily mean it’s something I ought to be doubling (or, god forbid, tripling down on). Especially when in a conversation with more senior engineers - which, at the current stage of my career, is vastly more likely - a strong opinion is one in which I ought to present my best case, rationale, and analysis in the hopes of reaching consensus.\nEven if my case for one of my strong opinions fails to reach a consensus - or even convince anybody, which does happen (sometimes a lot) (most of the time) - that isn’t failure. Ultimately, as I’ve gotten further into my career and seen a broader range of opinions reach a broader range of success or shortcoming, my approach has ultimately fallen back to:\nThe best side of the road to drive on is the side everybody else has agreed to drive on.\nNo matter how strongly you might feel one way or another, never underestimate the power of consensus. Either way, the outcome to accepting consensus is positive:\n\nYour opinion ended up being the way to go in hindsight and you’ve gained experience to make a better case the next time it comes up; or\nThe consensus opinion goes perfectly fine, you achieve your goals, and have gained experience on which you can build new, better-informed opinions.\n\nA final open letter\nI’ve noticed, in working with others, that the above classifications can somewhat freak people out - especially if they’re used to working with Strong Opinion People™, because how quickly I’m willing to roll over on my weak(er) opinions has the potential to come across as misunderstanding or apathy.\nAs an open letter to people in the future that see me do this, I make you this promise: when I quickly fold on an opinion, it is far more likely that, in that moment, I feel there’s more value in reaching a consensus and moving forward with any opinion than trying to force through a bad argument for a strong argument or a null argument for a weak one. At this point in my life, I am more interested in making progress than being right."},"notes/supply-chain":{"title":"From the Archive: \"What *are* Supply Chains, Anyway?\"","links":["tags/visualizations","notes/caveat-lector","notes/qamo","contact"],"tags":["python","economics","visualizations"],"content":"Below, you’ll find some graphs. These are what is known in the field of data visualization as “bad.”\nThese graphs are (as far as I can recall) my first attempts at using & visualizing network structures. As much as I would like to say they’re not too bad for a first attempt, they don’t “speak for themselves” as much as they “scream torments in the face of the viewer.”\nThe below graphs are stock tickers, connected to one another by their supplier relationships. For example, if Company A publicly noted that they received supplies from Company B, that would be denoted by a connecting edge.\n\nBelow is my first (and only) attempt to organize the above output. If I’m recalling correctly (and this was in 2019, so caveat lector), this was at least an attempt to get the first-order to third-order suppliers of a given set of equities and place their order in shells around the center. It’s messy, it’s noisy, and frankly, incomprehensible.\n\nThe hope of this analysis was to ultimately connect supply chains and, as a secondary goal, find graph cycles among a set of target stocks to find and catalog “supply loops”, and see if stocks in a given supply loop rise and fall together. The visualization acted more as a sanity check to see if my web scraper was working and less of a rigorous tool for understanding.\nDespite my area of focus being the parts of economics that aren’t related to either studying (or making) money, this is something I’d like to return to again in the future. However, I unfortunately don’t have the same level of data access that I did as an undergraduate, and purchasing access to a Bloomberg terminal falls well outside the financial means of CGC. However, if you’re ever looking for somebody to make bad graphs pro-bono and do have access to that kind of data, please feel free to reach out."},"notes/the-quest-to-kick-the-gremlin":{"title":"The Quest to Kick The Gremlin","links":["tags/gremlin-kicking","notes/caveat-lector"],"tags":["gremlin-kicking"],"content":"I am terrified by how quickly, without structure and habits, my life devolves into a cycle of sleeping, eating, procrastinating, and repeating until the visage of death sweeps me from this mortal coil.\nThis cycle is called “The Gremlin”\nI hate The Gremlin. The Gremlin makes me sad. The Gremlin stops me from doing the things that make me happy. Every day, I have to actively re-remember how much I hate The Gremlin, and how much happier I am when it’s gone, so I try my best to kick The Gremlin.\nI also hate the word “productivity.” There’s a sort of LinkedIn-centric slice of society that has built up the neutrality as an honest days’ work as a divinely-capitalized entity: Productivity™. It elicits (in me, personally) the visceral feeling I get when I see hustle-culture, rise-and-grind, success-is-a-choice-and-failure-is-your-fault types - the ones that farm for engagement by repeating gross approximations of quotes from self-help books that have been Human Centipede’d from one hustler to another. \nThat being said - productivity tools are some of my most reliable Gremlin-kicking weapons. This leaves me feeling very conflicted. Absent the weird Soylent-chugging culture that has formed around capital-P Productivity™, I would be in (and have been to) a really rough place without the productivity tools and habits I’ve tried my best to use and form in my quest to kick The Gremlin.\nAs a transparent act of shoving this internal inconsistency into the box in the back of my skull labelled “Don’t Think About It!”, I’ll be using the gremlin-kicking tag to denote posts about productivity and productivity tools.\nIn these posts, I’ll talk a bit about the structures I put up in my own life, and the tools I use to enforce those structures. To some degree, gremlin-kicking posts exist because I hope it might help another person who has their own Gremlin to kick and is looking for new tools to kick it. To a far greater degree, they’re here because the act of writing it down helps me set these structures in stone for myself. It is surprisingly easy to forget about good habits when, some day in the future, they’re no longer the habits they used to be.\nCaveat lector - you are you, and I am me. Some of these posts may resonate with you, and some of them may not, because different people are different."},"notes/time-tracking":{"title":"Some initial thoughts about time tracking","links":["notes/season-of-rhythm","tags/gremlin-kicking"],"tags":["gremlin-kicking"],"content":"Time-tracking is one of the tools I’ve picked up during my Year of Rhythm and gremlin-kicking. I’ll probably write about it more, here, later."},"notes/utah-office-consult":{"title":"From the Archive: \"Utah Office Consult\"","links":["notes/scratch/the-best-side-of-the-road"],"tags":["consulting","visualizations","python","data"],"content":"\nThis presentation is one that I did for an organization I was a part of during college. Looking back, this is probably the first time this phrase clicked in my brain:\n\nPeople problems are the hardest engineering problems\n\nFrom the first time that phrase entered into my head, it has ricocheted against the inside of my skull every single day. In computer science, problems are relatively easy to solve because the only thing you have to convince is a compiler. I am not (nor would I ever claim to be) a sociologist, but nonetheless feel safe in stating that people are not compilers. People have opinions. People have motivations. To work together, to have systems, to make any progress as a society, people have to agree on things.\nNever forget - the best side of the road to drive on is the side everybody else has agreed to drive on. When it comes to people problems, consensus is king.\nI’d imagine that the vast majority of you are people, like me, whose professional reputations to not precede you. As fellow members of the proletariat who fall outside of the LinkedIn-influencer and TED-talk alumni elite, we don’t have a whole lot of ethos on which to make our arguments for why people should agree with an idea. I don’t think that’s a huge deal (although golly gee, wouldn’t it be nice to have authority on matters?). It does mean, though, that turning an idea into consensus has to rely on logic and vibes.\nTo that end, I do think that using what I’d describe as “soft” quantitative frameworks for largely qualitative (read: vibes) properties of things is a good way to bring pathos and logos together. In the above presentation, using distance from other locations is not necessarily a catch-all description for the causes of many of the above problems, but it was a good rule-of-thumb."},"tags/csharp":{"title":"C\\#","links":[],"tags":[],"content":""},"tags/doodles":{"title":"Doodles, a.k.a. Minimally Professional Presentations","links":[],"tags":[],"content":""},"tags/economics":{"title":"Economics","links":[],"tags":[],"content":""},"tags/engineering":{"title":"engineering","links":[],"tags":[],"content":""},"tags/gremlin-kicking":{"title":"Gremlin Kicking (a.k.a Productivity)","links":["notes/the-quest-to-kick-the-gremlin"],"tags":[],"content":"Gremlin kicking is a somewhat underhanded term for productivity habits and tools."},"tags/horticulture":{"title":"Digital Gardening, and Horticulture as Research","links":["notes/digital-gardening-with-quartz"],"tags":[],"content":"As a logical consequence of taking a digital gardening approach to writing, the horticulture tag will be used to catalog thoughts related to digital gardening and general research.\nI also wanted to use horticulture because I think it’s a funny word."},"tags/mentoring":{"title":"CGC Mentoring","links":[],"tags":[],"content":""},"tags/python":{"title":"Python","links":[],"tags":[],"content":""},"tags/roblox":{"title":"Roblox","links":[],"tags":[],"content":""},"tags/visualizations":{"title":"Data Visualizations & Presentations","links":[],"tags":[],"content":""}} \ No newline at end of file