Thursday, December 31, 2020

farewell to flash

Sorry that Flash is going away. I never programmed much in it but there was a whole indie game making culture in it. Flash Game History is a bit of an homage.

The archivists are at work, though, with new options to run Flash stuff...

Wednesday, December 30, 2020

html ul/li unordered lists with plus or minus icons via CSS

My main blog turned 20 today! Semi-related I published a list of highs and lows from my academic years. 

I wanted to display those as unordered lists but replacing the bullets with pluses or minuses. There's a CSS pseudoselector that works well for that, using the emoji for big plus/big minus:

.plusminus li.plus::marker {
    content: "➕";
}
.plusminus li.minus::marker {
    content: '➖';
}
.plusminus li.plusminus::marker {
    content: '➕➖';
}
.plusminus li.plusplus::marker {
    content: '➕➕';
}
.plusminus li.minusminus::marker {
    content: '➖➖';
}

I guess to do a proper job of it you should throw in an aria-label...


UPDATE: this does not work on Safari! It supports ::marker but not the content property I guess? So I switched back to this earlier idea:

ul.plusminus  {
    list-style:none;
    position: relative;
}
ul.plusminus li::before {
    position: absolute;
    left:0;
}
ul.plusminus li.plus::before {
    content: "➕";
}
ul.plusminus li.minus::before {
    content: '➖';
}
ul.plusminus li.plusminus::before {
    content: '➕➖';
}
ul.plusminus li.plusplus::before {
    content: '➕➕';
}
.plusminus li.minusminus::before {
    content: '➖➖';
}


saints row iv freezing bug on nintendo switch

Played through Saints Row IV on Switch, kind of a comfort food game for me. I played it years ago on Xbox 360, and while I mostly play my Switch on my TV (that's otherwise that's a small screen for middle-aged eyes) it's amazing to have that little open world microcosm right in your hands. And this game captures superpowers like Flash-like running and soaring like no other.

There was a frustrating bug - near the end there was a mission called "Hello Teacup"/"The Girl Who Hates the 50s", but the Switch would freeze/lockup after its completion- the first time after the rewards screen for it, and then after that on the loading screen right after warping out. 

Googling for suggestions, I tried stuff like moving the game to system memory (vs SD card) and airplane mode and what not but what worked was going back and redoing one of the DLC missions... after that I could restart the Rescue Kenzie mission, complete it, and get on with the game. 

Just mentioning it here in case Google picks up on it and maybe it helps someone. 

Tuesday, December 29, 2020

20 macs for 2020

Six Colors finished its run of 20 Macs for 2020.

I'm a relatively new convert to Mac, like 2012 or so - gradually it has become the standard for web devs around Boston (I think we're all wanna be Designers, plus its Unix core is really nice) - but was always fascinated by the line, and the history of it was cool to think about.

the other dark web

Admittedly this is kind of a link to a link, but Daring Fireball's musings on Facebook’s Unknowable Megascale got me thinking - Gruber points out how Facebook is just unknowable in a way traditional media or blogs or message boards (even reprehensible 'chans) aren't. 

There's something fundamentally subjective, then, about Facebook, which makes the algorithm's engagement-maximizing manipulation that much harder to get a handle on, and to estimate the damage of. At first, I thought the same subjectivity applied to other custom-"wall"-based sites, such as Twitter and Tumblr - it's a different experience for each person - but those streams aren't nearly as heavy handed in the algorithmic manipulation as FB, and Twitter is fundamentally public by default. (My experience with Twitter might be idiosyncratic, though - I know people long for "just tweets of people I follow, in chronological order" which I actually get putting everyone I follow (and actually want to read, not just a courtesy follow) on a "list", and only reading that.) 

Like I wrote in The Stream vs The Froth (and later, the chrono, the wall, the stream, the froth) I am bummed out that my main blog - 20 years old this week - lost its message board audience, and that if I have any hope for conversation on what I write, I have to crosspost to FB, or sometimes one of the private Slack or WhatsApp groups I enjoy.) But FB has gotten to be so bad at that. FB worked its way into our hearts in part because it was based on people you know in real life, but now to keep pulling so many people it's just the most random group doomscrolling-bait stuff... like, I like the content in the Atari group, but I certainly don't value its random content more than stuff from people I know! 

Monday, December 21, 2020

better than codepen?

 I haven't used it much but jsitor looks like a great little code sandbox...

nagbot 3000

At an old job, we had a nice kind of team culture going for the developers. 

Our manager Scott asked us to do weekly status reports at end of day on Thursdays. I thought it would be easy to forget that, so I set an iPhone alarm to remind me, and then figuring the rest of the team was in the same boat, I decided to get in the habit of nudging people. To do so, I invented a persona for our group Skype chatroom called "Nagbot 3000". In theory I could have made up an automated script to do the reminder, but A. that would be work and B. It was kind of fun trying to think of variants to keep things lively.

Nagbot 3000 was generally appreciated by my coworkers. Here are some excerpts I saved at some point...

[Aug 2 2007 16:31:21] NAGBOT 3000 SEZ: status reports for sbruce.

[Aug 16 2007 16:30:20] NAGBOT 3000 SEZ: status tonight!

[Aug 23 2007 16:30:31] NAGBOT 3000 SEZ: STATUS

[Aug 30 2007 16:54:51] NAGBOT 3000 SEZ: STATUS

[Sep 6 2007 17:12:06] NAGBOT SEZ; geez, i guess there's status though everyone seems hipdeep in demo prep...

[Sep 20 2007 16:30:31] NagBot sez: DO YER STATUS
[Sep 20 2007 16:30:48] NagBot sez: *beep*

[Sep 27 2007 15:02:45] NAGBOT 3000 SEZ: status

[Oct 4 2007 16:31:28] NAGBOT 300 SEZ: DO STATUS

[Oct 11 2007 16:17:57] NAGBOT SEZ: STATUS

[Oct 18 2007 16:52:39] NAGBOT 3000 SEZ: DO STATUS

[Oct 25 2007 16:31:02] NAGBOT 3500 (now with politeness module) SEZ: DO YOUR STATUS REPORT PLEASE

[Nov 1 2007 16:30:25] NAGBOT 3000 [NOW WITH POLITENESS MODULE] SEZ: KINDLY DO YOUR STATUS REPORT, THANK YOU

[Nov 8 2007 16:30:48] NAGBOT 3000 (W/ POLITENESS MODULE UPGRADE) SEZ: IF YOU WOULD BE SO KIND, PLEASE DO YOUR STATUS.

[Nov 15 2007 16:47:22] NAGBOT 3000 SEZ: DO STATUS

[Nov 29 2007 16:33:46] *************NAGBOT 3000 SEZ: DO STATUS**************************

[Dec 6 2007 16:30:31] NAGBOT 3000 SEZ: DO STATUS. PLZ.

[Dec 20 2007 16:30:14] NAGBOT SEZ DO STATUS

[Jan 3 2008 16:31:47] NAGBOT 3000 W/ NEW "X-TRA SASS" CIRCUIT SEZ: try to scrape together some kind of decent status report for this weird, holiday-stricken no-man's-land limbo of a week

[Jan 10 2008 16:37:17] NAGBOT 3000 (Freeware Basic Edition) SEZ: do sta.

[Jan 17 2008 16:32:11] NAGBOT 3000 (with music upgrade) SEZ (to the tune of Howdy Doody theme):
IT'S DO YOUR STATUS TIME,
IT'S DO YOUR STATUS TIME,
SCOTT WANTS TO KNOW WHAT YOU DID DO,
SO TELL HIM AND BE TRUE

[Jan 24 2008 16:40:47] NAGBOT 3000 SEZ: IT IS ABOUT TIME TO DO YOUR STATUS REPORT.

[Jan 31 2008 16:31:11] NAGBOT 3000 SEZ: SEND IN YOUR STATUS PLEASE.

[Feb 7 2008 16:30:34] NAGBOT 3000 SEZ: STATUS STATUS RAH RAH RAH

[Feb 14 2008 16:44:56] NAGBOT SEZ: DO STATUS, CHA CHA CHA

[Feb 21 2008 16:35:07] NAGBOT 3000 (RHYMING UPDATE) SEZ:
The Time Has Come
The Walrus Said
To Write Things Done and Not:
Plus Obstacles, And Take All That Stuff
And Send It O'er Scott

[Feb 28 2008 16:31:22] NAGBOT 3000 (NOW WITH NEW BELLIGERENCE MODULE) SEZ: HEY YOU YA I'M TALKIN' TO YOU YOU GONNA GET YOUR DUMB STATUS INTO SBRUCE OR WHAT

[Mar 6 2008 16:36:01] NAGBOT 3000 (NOW W/ POWERPOINT MODULE) SEZ:
----------------------------
Status Reports
* Due Thursday E.o.D.
* Send to Scott
* Report 3 things:
-what you did this past week
-what you plan to do next week
-obstacles in your way
----------------------------

[Mar 13 2008 16:31:05] NAGBOT 3000 (JAPANESE EDITION) SEZ: 自分のステータスレポートをご覧ください。

[Apr 10 2008 16:30:56] NAGBOT 3000 (Mr. T Special Edition) SEZ: I PITY TH'FOOL WHO DON'T CUT OUT ALL THAT JIBBAJABBA AND DO A STATUS REPORT!

[Apr 17 2008 16:45:20] NAGBOT 3000 (with a little help from NagNAGBOTBot) SEZ: DO YOUR STATUS REPORT

[Apr 24 2008 16:28:01] NAGBOT 3000 (late 80s hiphop edition) SEZ: LOOKIN' AT MY GUCCI IT'S ABOUT THAT TIME

[May 1 2008 17:00:51] SLIGHTLY DELAYED NAGBOT 3000 SEZ: do your status!

[May 8 2008 16:30:30] NAGBOT 3000 (special Matrix Bullet-Time FX Edition) SEZ: dddddddddooooooooooooooooooo yyyyoooooooooooooooooouuuuurrrrrrrrrr sssssssttaaaaattuuuuuuuuuuuusssssssssssss rrreeeeeeeeepppooooooooooooooorrrrrrttt

[May 15 2008 17:23:45] NAGBOT 3000 SEZ (SUPER SECRET ENCRYPTION MODULE ENGAGED): qb lbhe fgnghf naq pbatenghyngvbaf ba xabjvat ebg-guvegrra!

[May 22 2008 16:33:20] NAGBOT 3000 (limerick edition) SEZ:
there once was a guy from rockport
whose career was nearly cut short
his work went unheeded
cause all that he needed
was to do his status report!

Wednesday, December 16, 2020

regexcellent

 I've mentioned it before but I do love my tool regexcellent - parts of my current project are making good use of my old school regex skills to scrape some html by hand. (relevant info from some thing like

SOMEKEY    <a href="SOMEURL"><img src="SOMEIMGURL" width="XX" height="YY" ></a>

with some other stuff.

The match was 

^(.*)\t\<a href\=\"(.*?)\"(.*)src\=\"(.*?)\"(.*)width\=\"(.*?)\" height\=\"(.*?)\"(.*?)$

and the replace was 

'$1':{ url:'$2', src:'$4', width:'$6', height:'$7'  },

Which produces something close enough to JSON that I can wrap it and pop it in JS and then do more formal manipulation...

I think way back when I used do this as macros in editors, lots of ctrl-arrow jumping around. And that was pretty quick! But I've lost track of what editors do that well, so this tool comes in handy.

Wednesday, December 9, 2020

the forager brain

Quote from Joshua Quittner, I think from Time Magazine circa 1998:

I am nuts for information-- as are we all, I suspect, most real men and women.  I can't get enough of the stuff.  When I'm clicking through the hundreds of E-mail messages that await me each morning, sometimes I imagine I'm a mighty information whale, sifting through thousands of tiny (but nutritious!) krill bits.  Yum!  Whether it's reading the cereal box or scanning the advertisement slide show some genius thought to project on the big screen at the movie theater, my appetite for information is unquenchable. 

This metaphor is kind of formalized as Information Foraging Theory. The claim is humans forage for information the way other animals forage for food - and that can be usefully applied to analyze "doom scrolling" and kneejerk email checking  and similar behaviors, where we swing back to the hunting grounds, and then stick/scroll around for periods of time based on the likelihood of something good showing up.

I was thinking about how I also stockpile information, and I use a motley collection of apps and websites to do so:

Simplenote App:

  • Projects Done
  • "Wisest" quotes
  • "Factoids and Intermittently Useful Information"
  • Medical events / things to discuss with my doctor
Google Docs:
  • Shared shopping list with my partner
  • Shared mailing list and zoom info for my science and spirituality reading group
  • Shared idea for future top list
Tot App:

  • Music to Get
  • Videos/Shows to Watch
  • Work Items to Do
Homebrew Online Database:
  • Passwords + Account Info
  • Media Journal
  • Random Useful Websites
For a bit it seemed weird that I don't have trouble remember what's recorded where... but now that I think about it, it makes sense that my brain is pretty well geared at remembering where any given "information hoard" is stored.

I think similarly, I've never been a fan of "RSS style readers" that take pure information content and put it into a generic template... the information loses that extraneous sensory data that helps me intuitively identify and recall the source/hunting ground..

Sunday, December 6, 2020

so random

 Nice piece on js coding with randomness. I need to get to making more artsy stuff myself!

preact and wmr - possible substitute for create-react-app

I am legit astonished at how much create-react-app - the de facto default - pulls. 250 Mb for just a Hello World! I really really really don't understand why the default brings so much... I'm tempted to make a package called "kitchen-sink" and lobby to get it included as part of the default.

JQuery (and modern CSS) really enhanced my homebrew programming, but Angular and React re-establishec the coding for work/coding for fun divide, in part because of this overhead... even though early React was more clearly meant to be part of an existing page, not presuming the "Single Webpage App" paradigm. I've done a few for fun projects in reat, but it never feels great, and since I don't usually use node on the backend, I get that "PHP for the JSON on the server" hubrid feel

I've had some better luck with Parcel. Another option might be wmr... it uses Preact which I haven't explored much, but might be more in tune with  my feeling of "I want to use basic React and JSX in a minimalist" way

on the naming of things (by other programmers)

A paraphrased quote I've gotten a lot of use (and some laughs) at possibly over the years:

It is a near universal belief among programmers that their peers can't name anything properly. Not variables nor subroutines... definitely not servers. Possibly not even their own children.

I decided to look up the original quote... looks like I grabbed it in September 2000 as 

How to tell you're becoming an technology prima donna:
You become convinced that none of your coworkers can name anything properly, whether it's machines, files, or their children. [...]

Alas, I failed to cite it properly and my sites are all Google knows about the original wording.

Thursday, December 3, 2020

php/js hack script to merge json files, keying on file name

 I know I "should" be using node for this, but:

Here is a php page that reads a bunch of files (in this case the files are "raw/_KEY_.json") and then prints out a single json object:

<pre><script>const raw = <?
$path = "raw";
$files = array_values(array_diff(scandir($path), array('.', '..')));
$tree = array();
foreach($files as $file){   
    list($key,$rest) = explode(".",$file);
    $tree[$key] = json_decode(file_get_contents("$path/$file"));
}
print json_encode($tree);
?>;
document.write(JSON.stringify(raw,null,' '));</script></pre>
For some reason the PHP version I had didn't seem to have JSON_PRETTY_PRINT defined (or I was doing it wrong) so I duck into js to do the pretty printing of the result... kind of an ObHack, that :-D

Tuesday, December 1, 2020

walk a json object, display paths of all parent nodes

One of the interesting things about styled components is that they can handle objects full of CSS stylings, not just strings.

So we have these json objects represented nested stylings, and I wanted to see all the keys (with their full paths) that had children (i.e. ignore any { "color" : "red" } simple properties) 

So a pretty good Comp Sci 101 exercise... 

const json = {
  "header":{
      "large":{
        "companyname":{
            color:"red"
        }
      },
    "small":{
        "companyname":{
            color:"green"
      }
    }
  }
}
let buffer = '';
showFullKeysOfParents(json,'');
console.log(buffer);

function showFullKeysOfParents(json,path){
  const keys = Object.keys(json);
  for(key of keys){
    if(typeof json[key] === 'object'){
      const newpath = `${path}${path===''?'':'.'}${key}`;
      buffer += `${newpath}\n`;
      showFullKeysOfParents(json[key],newpath);
    }
  }
  
}

I decided to just punt and use a global variable rather than waste more time fretting about return values and what not. 

The result of that is:

header
header.large
header.large.companyname
header.small
header.small.companyname

I made a code pen for it. Sidenote: I had to turn off "Match Brackets/Tags". I really don't understand why that kind of auto-complete is the default preference, and why coders like it... the "convenience" of saving a key or two comes no where near outweighing the unpredictability, and if you, say, go back to change the quote situation in a string, you can end up in a nightmare of appearing and disappearing quotes and single quotes.

Sunday, November 29, 2020

boop

boop

(react implementation of a nice little hover effect, a bit of jiggle vs a transition to a steady hover state)

timearch

A while back I started playing with timelines - I wanted to be better able to see the footsteps of my life so far. 

That's one thing about life: it's easy to forget how much of it many of us our blessed with. Days rush by, weeks drags, and years can fly past - but there's a lot in there if you pay attention. That's good news if you're living a life (as long as you're having a reasonable time of it!) but bad news if you're trying to make an information-rich detailed graphical representation of it.

In making my main timeline, full of photos of places and people that I've loved, I experimented with different visual displays. This weekend I put together one more form: the rainbow-like arch

As usual with the experiments, I condensed things to where I've lived, jobs I've had, and people I've had some kind of romantic connection with. 

Using a divided arch was interesting - it's more bounded than a simple linear timeline, and the curve gives a bit more room to cram stuff in, making better use of the plane. 

Although Tufte famously warns against pie charts, I think this display does invite comparisons of ranges, without too much distortion. 

(Also, I was thinking a bit about the Jastrow illusion where two identical thick curved rails appear vastly different in size depending on how they're nested.)

Tuesday, November 17, 2020

storybook composition embedding static storybooks - the CORS silver bullet (get it? like the beer? oh never mind)

TLDR: if you're needing to make an end run around CORS/Access-Control-Allow-Origin errors while hitting a locally running http server, you can try running 

npx http-server . -p 9999 --cors='*'

(Obviously you can pick your own content directory and port besides . and 9999)

Giant pain tracking this down.

It's trivially easy to embed an existing running storybook into your "local" storybook

Just add something like 

  refs: {
   'design-system': {
     title: "Storybook Design System",
     url:"http://localhost:9999/"
   }

to the modue.exports in main.js or ts or whatever.

But what if that other storybook is static? (i.e. the files you generate with npm run build-storybook?)

At first it won't work, and you may see requests for /stories.json

The docs aren't crystal clear on it, but you need to run 

npx sb extract

in order to generate that file. 

But once that was done I was still seeing:
Access to fetch at 'http://localhost:9999/stories.json' from origin 'http://localhost:6008' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Luckily bardiarastin on this github page had an answer:

npx http-server . -p 9999 --cors='*'

That seemed to clear it up and Storybook composition worked.

when the storybook panels disappear

I generally ask more questions than I answer on forums, but on Storybook discord I was pleased to give the answer-er in this exchange:

When I build static storybook page I have a toolbar with controls and events, but when I run it with start-storybook -p 6006 there is no toolbar. How can I fix this?

Have you tried hitting "A" and "D"  (show add-ons and change orientation, from the "..." menu)? I've found sometimes the panel below gets hidden offscreen - sometimes a combination of A + D along with resizing the window (especially if it used to be on my portrait mode monitor) gets it back

Thank you! Changing addons orientation helps me! 

Trying to field the easy questions so maybe the experts will help me more with my tougher ones... 

death of the net, film at 11

Recently there's been some kerfuffle about all apps on Macs phoning home and privacy concerns in general on Apple products. I haven't been tracking too closely to know if Apple's explanation and promise about not logging stuff, mostly using it as an anti-malware measure, satisfies those concerns.

It does remind me of the role of government in general. I value freedom but I'm no Libertarian, and I think one of the essential purposes of government is to stop exploitation of the weak by the more powerful. In some ways I do want a "bigger brother" because I more fear what groups at intermediate levels of power will do, especially with nothing like a ballot box to put them in check.

I see a pretty obvious parallel, then, with what Apple's doing. Free Software stalwarts like Stallman would absolutely stress the need to unfettered use of general purpose computation as a human right! But I think for many of us, the "walled garden" approach - so long as the walls aren't too high or confining - suffices.

I've also been thinking about this answer to Is Google in Decline? Borislav Agapiev uses this chart about the number of websites (even though some estimate 1/4 of them are parked domains) to point to a "Yes" answer:


Agapiev goes on to say how this means Google's fundamental assumption of fresh links and being the start page for everything on the web is not wellfounded: 

First there are big vertical silos, starting with Amazon, but also including other big walled gardens such as Facebook, Twitter and a host of others such as Netflix, Spotify, Shopify, eBay, Craigslist etc. So the best deals, social chatter and tweets, song and shopping recommendations, auction deals, free ads etc. are to be found elsewhere.

The same really goes for basically every vertical. Way back (remember Googlebase?) it was thought nobody should bother with any vertical as Google had it in there anyway. Googlebase is long gone and people go to CarGurus or Carvana for cars, Zillow for online house listings, Indeed and others for job postings etc., the list goes on and on.

Heh, happy to have worked at CarGurus, even as I'm at one of "and others for job postings" right now. 

It also reminds me of a recent 99% Invisible podcast I enjoyed, The Lost Cities of Geo, about Geocities, a remarkably egalitarian way to get people putting stuff up on the early web. I suppose Facebook is even more egalitarian, for better or worse! And I think they still benefit from being the only place in the US market to really connect people's real life persona to their online one, in a way Twitter or Tumblr hasn't. People have a lot of privacy reservations and what not about the place, and some have decided that remote family members and old classmates don't have that much of interest to say, but I understand the continuing appeal of it, and rely on it as my best connection to any kind of audience. Its proficiency as a vector for disinformation not withstanding...

I still bumble around on the independent blogosphere, because well-established patterns die hard with me - (almost 20 years of daily posts with hardly a day missed at kirk.is!) and I find great value in being able to look up every half-remembered quote, as well sharing and looking back on old photos and what not. 

Ah well, just some thoughts about the state of the online world!

Thursday, November 12, 2020

when MDXCreateElement shows up in storybook

 I've had a frustrating Sprint with Storybook; as the dev who was working on it before put it:

I was trying to make that work - pull the args from prop definition - but wasn't able to get that working […] As I discovered, it could be explained by anything, including position of planets. At least that stable it  felt.   :-)

The Template.bind() method suggested in the docs ends up putting MDXCreateElement rather than the actual JSX component names behind the "Show code" button. Luckily this comment in a github ticket pointed to a way to fix it (even in pure MDX, some of the other suggestions assumed you were in jsx/tsx) by bypassing the bind. 

A sample page I ended up with was

import { Meta } from '@storybook/addon-docs/blocks';
import { Checkbox } from './checkbox.component';
import { useState } from 'react';

import { Canvas, Story, ArgsTable } from '@storybook/addon-docs/blocks';

# Checkbox

<Meta title='Components/Checkbox' component={Checkbox} />

<Canvas>
  <Story name='Example' args={{ label: 'Example' }}>
    {(args) => {
      const [checked, setChecked] = useState(false);
      return (
        <Checkbox
          {...args}
          checked={checked}
          onChange={() => setChecked(!checked)}
        />
      );
    }}
  </Story>
</Canvas>

<ArgsTable story='Example' />

which uses useState to let the pure functional stateless component still do what QA expects it do when a user clicks on it...

web stuff

An ever so slightly PG13 intro video to ARIA + Web Accessibility...

A piece on Flex Grow and Shink pointed back to the CSS Tricks Alamanac that seems worth a browse.

Tuesday, November 10, 2020

quicknote: better dates and time in javascript

A medium article claims Luxon.js is the new hotness of date and time manipulation - usually when I have a need I tough it out in the standard Date object, but I should probably be quicker to look for some help... interesting to think about "immutability" in date objects as well, as long as you can trivially construct a new object based on an old one plus an offset I think it's good...

Monday, November 9, 2020

sets and maps instead of objects and arrays

When Not to Use Objects and Arrays to Store Data: ES6 has other ways of handling data structures and values in the form of Set and Map

It seems pretty cool to use these things... but I'm not sure if they will ever achieve their full place when object keys and arrays work "good enough" and have a bit more syntactic sugar- especially in terms of JSON... 

(I am convinced that the cleanliness of JSON - combined with the sheer power of arrays and key/value pairs, and the trivialness of "parsing" JSON - has been somewhat responsible for JS' ascendency, and DEFINITELY for JSON being preferred over XML for many config tasks. Though a little weird that JSON is stricter than JS - like JS can have "bare" label keys but JSON only has strings... (really annoying if you have an eslint that says all strings should be single quoted...)

Monday, November 2, 2020

back to the tech - and what to do when you get errors in storybook

Interesting aside from this page on alternatives to SPAs:

But the main caveat is that they assume that you know JavaScript and the DOM, which are not necessarily universal skills anymore. A lot of developers growing up on React have acquired a real blind spot for native browser APIs.

A manager mentioned something like that to me before, when I was wondering what my long-range experience brought to the table when young hot-shots who are quicker to find and use a good library than I sometimes am could make such cool stuff-- he claims he's interviewed folks who just really have no solid concept of the DOM. For better or worse my working knowledge of declarative languages such as Angular and React were built on the transition from "CGI"-style whole pages through pages turbocharged with JQuery. But some of these whipper-snappers are at a loss to really understanding what the DOM means...

Anyway!

I haven't had a lot top say on this blog last month, sometimes that's a reflection of what I'm having to gear up for in my job. October had a lot of wrangling with storybook. Storybook is more of a dynamic work in progress than I prefer. (Also I find it interesting that their main support community is on Discord!) Right now they're playing catch up with the new version of React - while React 17 is a stability release without a lot of contract changes, libraries gradually switching over their dependencies can create conflicts. One bit where I tried to "pay it forward" and be a helper rather than a helpee on the discord:

If you [have a blank screen on starting storybook] and see something like "Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:" [in the console] you are probably caught in the local hassles w/ React upgrading. The general advice is to "run with --no-dll", I did that my having these two lines in my package.json instead of just the first:

   "storybook": "start-storybook -p 6006 -s public",

    "storybook-no-dll": "start-storybook --no-dll -p 6006 -s public",

and then running npm run storybook-no-dll instead of npm run storybook

(I could reproduce the problem by running:

npx create-react-app my-app

cd my-app

npm start

and then 

npx sb init

npm run storybook

The other biggest hassle I dealt with was, before upgraded storybook version, we kept using "*.storybook.*" as our filter for what storybook should find, even though the new standard is "*.stories.*". That seemed to work ok, until I wanted to start publishing "*.storybook.mdx" - you should really stick with stories.* OR be prepared to get deep into the webpack config - webpack is doing special processing to process the "mdx" Markdown + JSX stuff.

Monday, October 26, 2020

software art not software engineering?

David Heinemeier Hansson (creator of Ruby on Rails and CTO of Basecamp) in an article Computers Are Hard 

This whole self-loathing a lot of software engineers engage in is entirely unproductive and is never going to be resolved. The idea that software development is a young industry and if we just give it another 30 years of ISO compliance or whatever rigor, we’re going to arrive at a romanticized notion of engineering they have in aerospace, or elevators, or bridges… no, we’re not. This is a fundamentally different domain that requires a fundamentally different approach.

We already have many of the answers. We’re simply afraid of embracing them. For example, in traditional engineering estimates are a huge part. Things run on estimates and on critical path diagrams because that’s simply the way you build a skyscraper. You don’t get to reconfigure how the pylons go after you pour the concrete. Software development is nothing like that. Software in many ways is far closer to the creative process of writing, game making, movies. Experiences where you design the unknown and you don’t know whether it’s good or not until you see it.

Look at movie making. We’ve been making movies for a hundred years. Haven’t we figured out the creative process yet? No! We haven’t. You can take a great director, a great cast, and still make a totally shitty movie. Versus in building, largely speaking, if you take a great architect, a great engineering firm, and a great general contractor, you’re gonna arrive at a building that works. You may make minor mistakes but the basic structure is going to be sound, unless someone makes a completely negligent error. In movie making, in music, in software things fail all the time. Even when good people who know the techniques of how to build things get together and work on something, they still end up failing.

Also I loved his take on programming languages:
Yes, for a person. A programming language can be better or worse for an individual. I think they can also be better or worse on an objective level, but that discussion is almost uninteresting. The interesting discussion for me is one of personal truth.
I wonder if that can be extended to other parts of software development, or if I'm just making excuses for my seeming lack of thoroughness - like my relative skepticism about unit-level testing vs other devs looking to it as such a holy thing, or even my lean into make whenever it comes into make vs buy. I think there is a chance that some of my preferences don't scale so well; that I'm pretty good at lone wolf projects (and have ones that have survived for decades!) but some of my mojo is less good when things need to massively scale, like team-wise or across distributed systems.

It's funny that Hansoson makes so much sense to me when I really didn't enjoy briefly playing with Ruby on Rails, the "assuming everything you do is this basic CRUD operation and so can just be more of a configuration than regular coding... but I'm not sure if I really think that stance is wrong (and hard to customize when it's not a perfect fit) or just less fun. 

Sunday, October 25, 2020

atomic music and a gripe about Apple's music search

Apple got its hooks into me in 2004 when I bought my first iPod and ripped my entire CD collection.  At the time I wrote

Being able to put my entire CD collection in such a tiny little box...it's pretty amazing. But besides the road music and trendy group identification, I'm hoping it will bring me back to my music collection in a way I've lost. I just haven't been listening to CDs that much lately. Of course, it won't be like the old days anyway; I'm not much of a music purist, but it seems like the iPod encourages people to treat songs as free floating atoms, not as part of larger album molecules.

Since the days of mixtapes, I've realized that a typical album that I like has 2 or 3 great tracks and 7 or 8 songs of filler.  So I went through all those CDs I ripped, and rated each song, and only 3 stars or above made it onto the limited space of my portable device.

Shortly after started the golden age of music for me - able to purchase new singles at a buck or two per pop (Eventually I started recording the new music I added each month - I like to focus on new songs in my collection before they get lost in the 3000 songs of shuffle.) I like paying artists for their music, but I don't like playing for songs I'm not going to listen to. 

Apple's smart playlists kept me loyal to iPhone over Android - other devices could surely carry and play my MP3s, but would they make it easy to get this reverse-chronological-order playlists-by-rating? It was never worth the uncertainty. 

So I'm wary about Apple's continued support for my prefered ways of living with music. A few years ago iOS dropped the ability to do star ratings on the device (in lieu of a simpler heart/no heart system) but user protest forced them to bring it back (though it's now an extra tap or two away than it was)

Plus streaming seems to be the way of the future - users love the selection and flexibility, and companies love collecting rent.

And, following the loss of the aux jack and a new emphasis on magnetic charging,  I'm be surprised if my iPhone in 5 years had ANY socket - and since I like to keep my files nicely backed up on my laptop, I have to hope there's some equivalent to the USB syncing I now enjoy.

But there's another, odder problem - Apple is just not great with search, even on its own devices. I couldn't remember the title to Rilo Kiley's "A Better Son/Daughter", I just remembered the term "better". I don't know if it's because I have a lot of playlists labeled "better" but for some reason I was only seeing albums and playlists, not song results... and it seems like the gadget cuts off at 20 search results. Searching for "a better" found it, but still, what is this crap?

The new "Music" app on desktop had different sections for Song, Album, Playlist search results so I could find my stuff. But still, their 'iTunes Store' search is weaksauce. It craps out at 100 results, and ends with the insulting 

Less relevant items are not displayed. To narrow your results, use more specific search terms.

Sometimes that is literally impossible to do! If you are trying to browse for a specific version of a well-covered song, or a song with a short name, you lack the information to add in more search terms - and it's just a flat text box, I don't think think there's a way to say 'only where the song title matches', or 'artist name only'. 

Such a simplistic search box and limits on results is an ok 80/20 solution but sometimes that missing 20 is really annoying. 

Monday, October 19, 2020

today's news as seen on ipads in 1995

In October 1995, Wired magazine had an interesting special issue: "Wired Scenarios 1.01: the Future of the the Future." One part that really stuck in my mind was "A Day in the Life", four two-page spreads with first person perspectives of people looking at October 19, 2020's - today's! - news on their distinctly iPad-like tablet devices.

The article says "Industrial Design and Alias work by Lunar Design" and attributes photos to James Porto. I can't find too much information on this article, or in fact, the entire issue --it seems like the thing was made when Wired was still uneven about getting its material online. The design work is pretty cool though -- with the exception of the "Porsche Cortex" they're not quite as grindingly minimalistic as the iPad. The Swatch one seems to be designed for bicycling, and the "SonyShack" device has a custom button for the wagering/betting that all the models support.

In trying to dig up information on this article I found a 1998 Digital Systems Research Center report on The Virtual Book, that reminded me the concept wasn't entirely new: the movie and novel 2001 had the "Newspad" (Commentators in February of 2010 loved pointing this "ripoff" out, making fun of the name 'iPad', and generally predicting it would be a big flop) and there was also Alan Kay's 1968 Dynabook concept. (Also some interesting contact between Kay and Steve Jobs...)







Of course, there was another, arguably more memorable feature in that article that seems weirdly on topic: the nightmarish semi-apocalyptic scenario "The Plague Years: 1996-2020" (with its (at times badly) photoshopped yet evocative images of a 747 being torched at Singapore airport (to try to contain the "Mao Flu"), corpses floating in a bay ala Katrina, and United Colors of Benetton ad sporting a rainbow of gas-mask/hazmat ensembles). Andrew Stern did a set of scans here

Friday, October 16, 2020

sococo - virtual office space

A current coworker mentioned his previous company used, and like, sococo - a kind of faux virtual presence thing:

Sococo Explainer Video from Sococo on Vimeo

I'm sort of fascinated by this idea of making telepresence less abstract...

(Also there's gather.town but I haven't had a chance to play with that one either...)

Thursday, October 8, 2020

blank spacer icons on iOS

 This medium post on iOS minimalism had this rather striking set of iOS screenshots:


Turns out the secret is iEmpty, letting you add blank icons with empty string captions. (I have not tested the procedure.)

The results can be beautiful, but I'd say a bit fragile... you might be tempted to remove an unneeded icon or slow to add in something new just to preserve the lovely spacing.

Anyway, at work we were just talking about the bad old days of spacer.gif ... 

Saturday, October 3, 2020

iphone widgets and widgetsmith's "fuzzy time"

So far, the biggest hit of iOS 14 has been the ability to use new icons for specific apps (via "shortcuts") and to add widgets to the homescreen. Daring Fireballs "The Talk Show" podcast had a rather long chat with David Smith who created "widgetsmith", the breakout hit of this release. 

Smith has a notably generous approach with pricing for widgetsmith - the basic version is free, the upgrade is a subscription (taking pains to be clear about what's on offer) where the new features are things that cost HIM money - e.g. tide and weather data.

But what I'm in love with is "Fuzzy Time", a block that puts the current time in words, and rounds off - much like a human does. Here's my current home screen:


You'll note the time was actually "3:16". And that's fine! That's such a more human way of thinking about time, sometimes I really resent how "digital" time has become, how nerdily exact in a way computers naturally are but humans generally aren't. Reading the time as words and having to think about it just a smidge activates a different part of my brain and makes it more likely that I get feel for a time as the time, not just as a bunch of abstract numbers - and that I'll remember/internalize it.

I implemented a javascript prototype of something similar a decade ago (I was a little wordier, saying "a bit after half past three" rather than "Twenty-Five to Four") and was tempted to buy a Pebble watch and code it as a custom watch face. Infamously, Apple's doesn't allow custom watch faces, though Roughly, the time in words adds a large "complication" to other faces that has a similar result.

I'm still wavering on if I'll ever get an Apple Watch - the health stuff is temping, but I already feel like I'm a slave to time without having the shackle on my wrist to remind me!

Also you'll note Apple's default calendar widget, which until "Fuzzy Time" was the only thing I found worth the real estate. Here I appreciate the visualization of the entire month... I think it might help me get a feel for the progression of a month, I hate that "wait, the month's date is in the 20s ALREADY???"

Thursday, October 1, 2020

prevent browser scrolling / dragging while drawing on canvas on mobile

I'm making a minimalist shared whiteboard app using p5 / p5.js, which is my favorite way of doing canvas tag stuff. Believe it or not this is a runnable drawing program in p5:

function setup() {
  createCanvas(400, 400);
}

function mouseDragged(){
  line(pmouseX,pmouseY, mouseX,mouseY)
}

Anyway, the program, with a PHP backend, was coming along fine, but was frustrating on my phone and tablet - the same events to draw on the canvas would drag the whole window (even though there was no need to scroll, all the content of the page was visible.) How to ignore finger scrolling in these cases?  (grep bait: block drag scroll event p5 ignore disable)

Tried some CSS trickery - the most promising was making it "position:fixed;" but somehow the touch events were being scaled vertically (I think the page was being moved behind the canvas, and somehow that was where the x and y were being calculated from)

As always, stackoverflow to the rescue. I ended up making a function like this:

function stopTouchScrolling(canvas){
// Prevent scrolling when touching the canvas
document.body.addEventListener("touchstart", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });
document.body.addEventListener("touchend", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });
document.body.addEventListener("touchmove", function (e) {
    if (e.target == canvas) {
        e.preventDefault();
    }
}, { passive: false });

}

To call that in p5, I had to retrieve the actual canvas DOM element. There might be an easier way, but setting the id of the canvas and then using the plain old document.getElementById() worked fine:

  createCanvas(800,800).parent("canvasParent").id("drawingCanvas");
  stopTouchScrolling(document.getElementById('drawingCanvas'));

Works great on iPhone, iPad, and I had a buddy test it out on Android Edge and chrome.

jazz typography

Oh, these are so good! Reagan Ray isolated the lettering of the artists' names on 100 jazz records. I've always loved this kind of design work.








Saturday, September 26, 2020

Fail Faster. Follow the Fun.

Marc "MAHK" LeBlanc on game design: 

"Fail Faster. Follow the Fun."

That quote via this video:

I'm proud of the little games I've made but sometimes I wish I had fleshed out more of them... most are just barely enough wrappers for playing with a lovely little mechanic.

awesome modern css layout tropes

Excellent video, "10 modern layouts in 1 line of CSS"


I think the name is mildly misleading (the 1 line is the core idea but you'll still have other layout work to do) but it's great stuff! It has an accompanying website with CodePens.

Thursday, September 24, 2020

the importance of rapid iteration and proximate feedback

A couple things I've been experiencing (reading, listening to, and programming) are having some synchronicity:

Daniel Kahneman, talking with Sam Harris on what it takes to develop intuition - to impress knowledge into your immediate, System 1 processing vs your slower, rational System 2:

Now, in order to recognize patterns in reality, which is what true intuitions are, the world has to be regular enough so that there are regularities to be picked up. Then you have to have enough exposure to those regularities to have a chance to learn them. And third, it turns out that intuition depends critically on the time between when you're making a guess and a judgement, and when you get feedback about it. The feedback has to be rapid. And if those three conditions are satisfied, then eventually people develop intuition. 

Maddy Myers talking on the podcast Triple Click on Which Games Do We Wish We Were Better At? - specifically at around 16:00, on playing at local competitions for fighting games

And then hearing from people, in person, feedback on what I was doing wrong and then using that immediately to improve...you really can't beat that [...] because you're getting that hands-on lesson constantly... and matches are short enough that you can get actually quickly implement that! Which I feel is another reason why I could more immediately see improvements there then at something like Starcraft, where I feel like I did 600 things wrong, and the next match is going to be completely different than this, so who frickin' knows! - But at least in fighting games you can change one thing and see a big difference and that always worked better for my learning style.

And I'm back on my own, why does my System 1 have a such a dislike of unit tests and disinterest in locking down javascript via typescript, when so many other smart developers love both so much? 

I think I answered this question on this blog in 2016:

I've found SOME parallels in the way I write code relative to the Proper Unit Tester (PUTter). I'm a ridiculously incremental coder; I hate being "wrong", and kind of scared of making a block of code so big that when I'm finally ready to run it I don't what part might be going wrong, and so I've always relied on tight code/run/eval loops... lots of manual inspection and testing of assumptions at each little baby step. Often I'd even write little homebrew test functions for the various edge cases. The difference between old me and a true PUTter, then, is I would then throw away those little functions and logging statements in the same way a building site takes down the scaffolding once the building is standing. But PUTing says - look, that's how you know this code still works in the future, nurture that scaffolding, keep it around... make it survive any refactoring, fix all the mocks when the endpont input or output gets added to, etc etc.  That's a huge cost, and I'm still trying to convince my self it's worth it.

TypeScript is a bit of friction on that kind of iterating axel... it tends to violate DRY; if you are messing with the interface of a function, and especially if your typescript system is a bit hair trigger (like yelling at you for unused values) you might have to make changes 3 or 4 places. Yeah, it's better than undocumented "oh we assumed this random key was in the props object but forgot to tell you", but it's also not much of a replacement for updated real documentation. 

Unit tests can be similar, especially for UI. I'm not sure if I've just never landed in a place that was doing it right, but every place I've been at, the correct response to "oh the unit tests broke!" is not "time to fix the code!" but "time to update the unit tests!" In general, basic developer testing confirms the new feature is working, and the old functionality isn't blatantly busted - and unit tests are often awkward enough to set up (in terms of mocking an environment for the code to run in) that they are almost always more fragile that the core code... they are canaries in the coal mine that keel over if a miner passes wind.

The other thing about UI is that dependencies often aren't well described. Today we ran into one where a change to the CSS line-height property of a container label was making our checkboxes break. There wasn't really a way to capture in that in a unit test, unless you were doing screenshot-y ones. (We use text-based snapshots... a few years back I interviewed at one place that was using graphical screenshots which might be more revealing) 

A Unit Test is setting up a fragile glass ant farm to make sure a few little ants are still toiling away - but that's no way to test the health of the colony, and I don't see why so many developers don't see the costs of them in terms of developer time, both at the outset and as the codebase extends. 

The errors that do show up as a codebase extends are emergent... most well sized units are too small to fail, the trouble happens at higher levels. And yadda yadda, what if you have to refactor the unit, and want to make sure it works? Again, the number of subtle problems I've seen introduced with that kind of unit refactoring in real life I could count on one hand.

typescript and style components gotchas

Sometimes typescript + style components make a hot mess of build errors as you pass around various interface-y objects. This article outlines some good practices, like how you can define the props your styled component is using:

type ButtonProps = {

  primary: boolean;

};

const Button = styled.TouchableOpacity<ButtonProps>`

  opacity: ${(props) => (props.primary ? 0.5 : 1)};

`;

Monday, September 21, 2020

understanding package-lock.json

A coworker recommended this article when I was trying to figure out why package-lock.json should be checked in.

I could see the appeal of package-lock.json as a snapshot thing, so you could trace back and recreate an environment in production or whatever. But the idea of pulling down another dev's updates that might have changed both it was and good old package.json was weird... like the latter is "what the versions should be" and the former "what the versions actually are", so until you run npm install, you're kind of living a lie?

In short I was trying to reconcile other documentation that made clear 

One key detail about package-lock.json is that it cannot be published

with this newfound passage:

The idea then becomes that instead of using package.json to resolve and install modules, npm will use the package-lock.json. 

I guess npm using package-lock.json to tell it what to install is the weird/new bit for me... so npm says "I will install what's in package-lock.json, knowing what needs to be installed by comparing it to what's actually in node_modules... unless package.json needs something newer, in which case I will install that newness and update package-lock.json accordingly"...

I guess it makes sense but it feels a little weird, like there's not quite a single source of truth for stuff.


Friday, September 18, 2020

mocking fetch

Had a rough week with unit test. The status quo of unit testing in React seems a little rough; the fake-y environment you set up to fake being a browser seems at least at delicate as the actual code you want to test...

I had almost forgotten discovering react-testing-library which seems to be the future, and a little closer to unit tests that simulate users rather than Enzyme's way of getting lost in a see of props. There was some learning curve though; the finders like screen.getByLabelText() and screen.getByRole() seem designed to help get devs thinking in terms of a11y issues (like making sure aria roles are accounted for etc) so if you're used to thinking "oh I'll just grab it via the element id".... it kind of discourages that sort of thinking.

I had a surprising amount of aggravation faking the client/server response. I was hoping code like this would set up Mock Service Worker as a nice little endpoint:

import { rest } from 'msw'
import { setupServer } from 'msw/node'

//... later in the test: 

const server = setupServer(
  rest.get('/endpoint*',  (req, res, ctx) => {
    return res(ctx.json({ results: ['abc','def','ghi'] }))
  })
)  
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

Though I'd also have use a polyfill for fetch

const {Response, Request, Headers, fetch} = require('whatwg-fetch');
global.Response = Response;
global.Request = Request;
global.Headers = Headers;
global.fetch = fetch;

But I couldn't get it to work; somehow the fetch().then would never resolve. It's still easy to get trapped up on this asynch stuff!

So after banging my head against it I went with the less recommended practice of handrolling a stubbed out fetch:

const mockSuccessResponse = {results: ['abc','def','ghi']};
const mockJsonPromise = Promise.resolve(mockSuccessResponse);
const mockFetchPromise = Promise.resolve({
  json: () => mockJsonPromise,
});
global.fetch = jest.fn().mockImplementation(() => {
  return mockFetchPromise;
});

//..and later
global.fetch.mockClear();
delete global.fetch;

Blargh! Good enough for the moment I guess.

Tuesday, September 15, 2020

Saturday, September 12, 2020

the ux of scroll direction: natural and y-axis: inverted

I recently reconfigured my work-from-home desk to have my laptop on a stand - it raises the webcam to a more flattering level, makes its screen easier to glance at (next to my main monitor, rather than beneath), and keeps my wrists from the unpleasant heat of a warm machine.

I switched to a plain old mouse after a failed attempt to use a "magic trackpad" in a laptop-like configuration. Macs are frustrating though because they have a single "scroll direction: natural" setting that applies to both mice and touchpads - but I want exactly opposite behaviors for the two.

The "Natural" setting makes the touchable surface of the trackpad act like the surface of an iPad: if the image on the screen were of a piece of paper, it's like you're dragging the paper with your two fingers - so to see the lower part of the paper in the glass of the screen, you drag up. 

But historically, mice scroll by dragging a little marker in the scrollbar, and in the 90s mice added a physical scrollwheel (it's so nice to have that physicality back with my cheap bluetooth mouse - though occasionally frustrating since I can't easily scroll left and right with it.) Anyway, with that scroll marker, moving up moves the viewport up... so if you want to see the "lower part of the paper in the glass of the screen" you drag down.

But Apple treats this as one setting! (I'm not sure what it feels like to use Apple's "magic mouse" that has a trackpad-ish surface...) There are programs that allow you set the two differently, but the hack I installed long ago has noticeable lag where a scroll starts moving the wrong way and then corrects.

There's an interesting parallel to life in video games, especially 3D run around and shoot games. The "standard" controls for aiming the crosshairs make a certain amount of intuitive sense: if the target is above where you are aiming, press up on the controller to aim at it. But for a certain population of gamers they will immediately head to settings to reverse that y-axis - they want to press down to aim at the higher target.

This diagram attempts my best guess as to why:


The first example, "normal", shows how the controller (represented as a compass rose) is mapped to the tip of the gun. So to aim at the higher target, you press up (and the character in the viewport moves down).

Gamers who prefer inverted controls do a different mapping... it's to the viewpoint, or you could say the top of the avatars head. To hit a higher target you pull down - or rather, back, and the viewport slides up.

The third sketch shows how this is akin to how flight simulators or flying games in general work - a pilot pulls back on the flight stick (which corresponds to down on a more humble controller) and the plane tips back and ascends. 

I find this difference in expectation among gamers fascinating (and frustrating; some games, like "Luigi's Mansion 3", don't bother to put in a control scheme to accommodate the "inverted" preference.) I think gamers who grew up with keyboard controls, mouse aiming will hardly ever long for inverted-Y controls

And there's that parallel with the mouse/trackpad scrolling: my girlfriend thinks I'm weird for ever using "natural" scroll for my Mac trackpad - I'm guessing her model of it is based on the scroll position and/or the viewport, rather than the content.

And they say there's a similar ambiguity in how people map space and time - does "we had to push the meeting forward 2 days" mean the meeting is now earlier or later than it was planned? Your answer may have to do with if you see yourself as fixed, and time heading towards you, or time is fixed and you are travelling through it... and some cultures have entirely different ways of mapping the two.

Fun stuff in UX! Don't assume your audience maps space the same way you do...

Friday, September 11, 2020

ui and testability: the ant farm, the GOTO statement

I have never been a true aficionado of unit testing; 

  • I've seen too many that test implementation and not true functionality and that break even though the underlying code is fine after a refactor
  • as a form of "documentation" they aren't particularly easy for a human to read and glean information from (though I admit they are more constrained to be updated along with the code, unlike external documentation)
  • when written by the same coder who wrote the code under test, they assuredly won't test much that the coder didn't think of when doing the implementation, and most true small units should - frankly - be "too small to fail".
  • when implemented and providing high code coverage, they're sometimes cited to give a false sense of security

But mostly, especially for UI, the bugs I've seen that make it to production all depend on context; they're an emergent property of interacting parts that don't properly understand each other enough to play well; 

  • the unexpected format of the response from the server - (oh yeah, the format in the db and endpoint updated 2 sprints ago but we forgot to update the code and the tests!)
  • the odd browser incompatibility for a CSS or even Javascript syntax
  • the surrounding DOM of the page leaking into the embedded unit and doing odd things
  • the text value from the server (or the user input) was much longer than the happy path examples on the designers happy-path mockup and things look weird
  • a surprising race condition or other sequence-based context-y problem
None of these issues are particularly amenable to being caught early by the isolated confines of a unit test. (And half of them aren't easy to see if your test runner output is based on a command line and not human inspectable UI.)

When you make up a unit test, it's like you set up a tiny 2 or 3 ant ant farm and carefully observe your ants correctly doing their own thing in those glass walls, and sure, it's important to make sure your ants are basically healthy - but there's only a small chance that that's how you're going to catch the problem with all the ants of the colony ahead of time.

The sweet spots for unit tests are in functional programming: ALL relevant input is known / there is no other reliance context to botch things up, a manipulation of that input  - complex enough to be worth testing! - is performed, and the results can be inspected in their entirety. And one reason why declarative programming for UI has gained so much popularity is that of all styles of UI code it has the highest chances of meeting that criteria... but even then the tools for making a component, faking an interaction with it, and seeing the result are just so-so at best. 

Anyway, I didn't mean this to be quite this long of a ramble - mostly I wanted to set up this quote I snagged in 1998:

"Menu items are the modern programmer's way -- even that of the Java programmer, who is too pure of heart to use pointers -- of putting an obscene number of unpredictable GOTO statements everywhere in his code." -- jhayward@imsa.edu via Usenet's "rec.humor.funny"

 Very old school in both tech and gendered language, but I think about that in the context of UI a lot.

Tuesday, September 8, 2020

safely unpacking nested key/values in javascript/ECMAscript - the mess of the null propagation operator

 So if you have an object like 

const foo = {
  bar: {
    val: 'got this!'  
  },
  apple:{
    banana:{
      cherry: 'fruit'
    }
  }
};

and you want to safely get foo.bar.val or check on foo.baz.val without getting errors... there's a good syntax for it based on question marks - but isn't yet part of the the standard: foo?.bar?.val or foo?.baz?.val - it's scary, because it seems to work in some browsers, but isn't considered standard.

I made up a code pen that says something like this function might be an ok substitute, if less clean:

function getNested(obj,...keys){
  keys.forEach((key)=>{
    if(obj === undefined || obj === null) {
      return;
    }
      obj = obj[key]; 
  });
  return obj;
}

Then you can call getNested(foo,'baz','val')

Sunday, September 6, 2020

the return of the obhack

Back in the 90s I was often on Usenet - a distributed set of conversational message boards. The level of discourse was generally pretty high, maybe because of the system's academic routes and relative lack of anonymity, and you could use whatever newsreader you liked and your single account to interact with all kinds of topic-based groups - kind of like Reddit, but more geared to writing in paragraphs rather than sentences.

Besides "rec.games.video.classic" and "alt.fan.cecil-adams" my favorite group was "alt.hackers" - hackers in in the sense of "making cheap and cheerful kludges" vs "hacking into computer systems". (Or the MIT sense of "grand stunts") It was "self-moderated" - there was a specific technical trick you had to pull in order to post there. The "netiquette" of the group suggested you post an "obligatory hack" or "ObHack" if your post would otherwise be off-topic.

I kept a list of my own ObHacks for future use, and there's still a part of my brain that thinks "oh, that was a clever little thing I came up with, I should file that away for an ObHack!" So here's two of those about the lockscreen wallpaper for my phone.

One is for band: I take a snapshot or screenshot of the setlist and then post it as my lockscreen, so I can quickly see what songs are coming up without fiddling with my phone too much. It's not quite as classic as taping a list to the floor but it's a lot less work.




(Plus then afterwards I have a nice memento of the concert until I remember to put my wallpaper back...)

Anyway, I noticed that changing wallpaper and case is a nice way to make a phone feel refreshed and new, so I got this bright yellow case to replace the blue silicone one that was starting to wear. I decided to lean into how "bumblebee" like it made my phone look and made up this wallpaper:

The slight ObHack cleverness was using a screenshot to layout where the bee appeared - I wanted it so that even if a song or podcast was playing, I could still see the bee, so I took a screenshot and used it as a layer to get the placement right:


Then I hid the layer and saved. (In practice, the bee was a smidge lower than where I thought it would show up, but I decided on a new shade of blue so I had to redo it anyway.)

Incidentally, Piskel was a lot better at making the pixel art bee (I stole the design by googling "pixelated bumblebee" and seeing these cool Etsy earrings)
 




Friday, September 4, 2020

jmespath - query syntax for json

I hadn't heard of jmespath before this slack msg:
Haha my coworker said she is naming her first child Jmes, in honor of Jmespath lol

but I dig it, I've sometimes thought I needed something like that. 

the spatial ux of thinking about time itself

I've always been interested in how humans visualize and put metaphors to time ("life's like an hourglass glued to the table" I've been told) Some of my interest was sparked by recognizing how idiosyncratic my own way of spatializing the course of a year and the course of a week as counterclockwise circles (I made visualization of those timehoops a while back)

All of these are akin to synaesthesia - time isn't inherently spatial, but we find the metaphors for it useful.

This Anthropology.net article discusses a few of those metaphors that were less familiar to me
  • I knew of the Aymara of the Andes, who reverse the more common view of marching into the future with the past at our backs - "the past is known and has been seen, and thus lies in front. The future remains unknown and unseen, and is relinquished to be behind the ego".
  • For many speakers of Mandarin, "the past is referred as above the speaker. And the future referred to as below the speaker." (I'm not sure if the metaphor is that of plummeting? That's almost as morbid as the hourglass glued to the table!)
  • For the the Pormpuraawans of Australia "time always flows from east or the past to west or the future" regardless of the current location and orientation of the speaker.
  • For the Yupno peoples of Papua New Guinea, "time is a topographical concept, time winds its way up and downhill." (The article points to speculation on how this might relate to the group's literally uphill migratory history.)
If you dig this topic, you might like the book "Einstein's Dreams" by Alan Lightman, that posits the great thinker dreaming of different ways times might behave, and how humans might respond. (If time slowed down noticeably with velocity, would people attempt to live their life always in motion in order to have more time, put their houses on wheels and go go go? Or in a universe where time slowed based on proximity to a central point, would adults with young children or old people journey to be nearer that point, while people trying to flee bad memories would head as far away from it as possible?)

Thursday, September 3, 2020

Tuesday, September 1, 2020

workspace noodling: laptop in front vs old school keyboard and mouse

 Random self-indulgent first world nerdery: for a long time I've really liked having a second monitor up above my laptop, using the laptop as the keyboard and trackpad and secondary monitor. It seemed like such a no-brainer, I almost had pity on my coworkers who put the laptop on a stand and needed a separate mouse and keyboard. I loved how the trackpad is right there beneath your thumbs, none of that reach over for the mouse, and just how efficient it seemed in general - and also the elegance of having the same arrangement when on the go or at the desk, so never having to retrain my hands...

Well... I've been having second thoughts. Honestly it's mostly because I was tired of warm wrists from overheated laptops, but also I realized I was using the laptop screen less because it was so low, plus I knew I would get a better webcam angle with the laptop riding higher.

Sadly, I don't think anyone makes a good "keyboard with trackpad integrated in front" (honestly, if I could somehow adapt the new iPad Pro magic keyboard/trackpad combo for use on a Mac, that would be ideal...)

So I bought a laptop stand, grabbed an old Apple Apple "magic" keyboard Melissa wasn't using much, and bought a "Magic Trackpad" to place right in front of- recreating the laptop w/ trackpad-at-the-thumbs experience. But, it was uncomfortable, and prone to accidental hits... even after several revisions of lego-constructed wrist rests:

So I guess I'm back to keyboard plus mouse... I still find myself reaching my thumbs down but there are some advantages to the mouse: the cheap bluetooth mouse I got has a scrollwheel, which is a tactile pleasantness I had forgotten, and a distinct button for right clicks, which Mac still supports, albeit grudgingly. Still, it feels so oldschool to need a mousepad (for my white IKEA desktop) -- it's like I'm back in the AOL generation... 

Sunday, August 30, 2020

the apple family

The Lost in Mobile blog (and its watch-based spinoffs) has be reformed as McGST, a very enjoyable read. In a recent post about his family, Shaun noticed how Apple-centric they all were.

I too am Apple-centric with most of my gear. I wrote:

Yeah, seems like it’s a mix of:
– loyalty / other competitive products decent but not having benefits worth re-learning (phone)
– anemic competition in the category (watch, tablet, laptop (at least if you like Unix-y things))
– prestige and/or superior design (wireless earpods)
– familiarity w/ and cohesion of the product line landscape

Alan Kay said “People who are really serious about software should make their own hardware.” – Apple has been doing that in a more cohesive way for longer than anyone. Samsung doesn’t do much in terms of software (tho their smart TV UIs had made tremendous strides, I’ve lived through) — Microsoft was late to hardware and never got the hang of mobile, Google has chromebooks and seems to not be excited about pixel….


Saturday, August 29, 2020

laws of ux

 The Laws of UX has one of my favorite maxims that I learned from Larry Wall who invented Perl:


Postel's Law: Be liberal in what you accept, 

and conservative in what you send.

minimal react

 Kind of a nice intro to minimal React, with as few libraries as possible