Wednesday, July 29, 2020

the good ol' gadgets

Gizmodo's I Miss series is pretty fun.

clumping and the pleasure of recreational computing

Interactive version at toys.alienbill.com/ahaclumps
I'm rereading Martin Gardner's book "aha! Gotcha: Paradoxes to puzzle and delight" I found this book in my Aunt and Uncle's library and it left an impact on me, teaching me things like the "liar's paradox" ("this sentence is true!") and the weirdness of the Hotel Infinity, where the seemingly full hotel can make space for any finite number of new guests by having all the current guests move up that many rooms, or even an infinite number of new guests by having everyone take a room that's their current room number x 2.

In the section on Statistics Gardner talks about statistical "clumping". I remember this passage:
A striking experiment in clumping was discovered by A. D. Moore, an engineer at the University of Michigan. Moore calls it the "nonpareil mosaic" because it uses large quantities of nonpareils, a sugar candy manufactured in the shape of tiny colored spheres. Obtain enough red and green nonpareils so that you can fill a glass bottle with equal amounts of each. Shake the bottle until the two colors are thoroughly mixed.

Inspect the sides of the bottle. You would expect to a see a homogenous mix of colors, but instead you see a beautiful mosaic made up of irregular large red clumps interspersed with equally large green clumps. The pattern is so unexpected that even mathematicians, when they first see it, believe that some sort of electrostatic effect is causing spheres of like color to stick to one another. Actually, nothing but chance is operating. The mosaic is the normal result of random clumping.

If this seems hard to believe, try this simple experiment. On a sheet of graph paper, outline a 20-by-20 square. Take each cell in turn and color it red or green, choosing the color by flipping a coin. When the 400-cell square is fully colored, you will see the same kind of mosaic that appeared on the sides of the bottle.
But being in a page of relatively plentiful computer power, I made a digital version of this this morning and saved myself the 400 coin flips... see it yourself at ahaclumps

I made it so if you click higher or lower you get more or fewer colors (up to 8) and if you click left or right the number of squares in the grid changes. With small squares, I feel the clumping effect is a bit less pronounced, so I'm not quite sure I believe the original jar-of-nonpareils effect is well demonstrated here.

It is nice to be able to whip something like this up in an hour or so... two minor bits of cleverness, one is I do love p5's random() function that will return a random member of an array that you pass into (or an ordinary bounded random number  if you pass in numbers). Also if you look in the code there's a good excuse to use a little curry function (so I can put x,y into a single-ly dimensioned array) and then the code to show the current settings and then remove them with a timeout was some decent UX (IMO).

Tuesday, July 28, 2020

Saturday, July 25, 2020

the internet's first shareholder proxy voting system

Back in the mid-90s I was tasked with making "vote-by-net.com", the Internet's first Shareholder Proxy Voting system.


It even got a brief mention on the first page of the Wall Street Journal! (I'll make a scan if I run across the sheet again.) 

It was a bunch of Perl scripts, with a bit of JS flavoring. Had some weird bits like translating into IBM's old punchcard-based encoding EBCDIC as well.

Cleaning up old files I ran into this set of handoff documents (including servers and directories and passwords, oh my - but long since defunct.) 

Friday, July 24, 2020

good react-testing-library tutorial

I've never had an intuitive love of unit tests, preferring to test at higher levels -- but because many smart people disagree with me, and because unit tests give the warm fuzzies to so many manager-types, I don't make much of a stink about it.

My favorite low-key slogans expressing my view, which all revolve around the same core:
  • Unit Testing like testing 100 trees and assuming you have a forest
  • Bugs are usually an emergent property from connecting parts. 
  • A well-scoped component will usually be "too small to fail", internal errors should be pretty visible on inspection without much place to hide.
But I am of course compelled to make the best of the state of the world which considers unit test coverage to be table stakes for professional development. (And there are some advantages - a good set of tests can act as a form of communication to future developers.)

One positive development is the move towards React Testing Library over, say, Enzyme. The emphasis is on using the component more like a user would. I would suggest Robin Wieruch's How to use React Testing Library Tutorial.

A few thoughts I jotted on it:
  • love the whole "screen" element of it, and screen.debug() for high visibility
  • getByRole() seems pretty brilliant, especially the way you can leave it blank and the output of running it will make suggestions about what roles are available in the component - a clunky (but useful!) form of auto-complete.
  • the await stuff is interesting. (I admit I don't yet 100% deeply grok the "await" syntax at times :-D )
So, good tutorial for a good tool.

Thursday, July 23, 2020

adding minification via terser or uglify

I've never been much of a build engineer; in fact up until this year I was always more of a "<script src='..." kinda dude.

My lead asked me to add in some minification to our rollup-based build system, but luckily he'd already done most of the hard work, and trying different plugins was pretty easy! (Kind of one of those ones where it was going to be really easy or really hard.)

Uglify vs. Babel-minify vs. Terser: A mini battle royale provided some comparison, I decided just to go for uglify (which seems like it used to be the favorite) and Terser (which the article seemed to like.) I tried both but settled on Terser (looking back now in writing this I see that npmjs.com/package/rollup-plugin-uglify says "Note: uglify-js is able to transpile only es5 syntax. If you want to transpile es6+ syntax use terser instead" so it feels like the future is with Terser.

Both were easy to setup for Terser it was
npm i rollup-plugin-terser --save-dev
then adding
import { terser } from "rollup-plugin-terser";
and
terser()
in the plugins array of rollup.config.js

(Also adding typescript support with declaration files was pretty easy, see this stackoverflow.)

good newsletter for UI

Frontend Focus is a better than average newsletter on UI-ish things, very well-curated.

This post on CSS Grid was great. CSS Grid sometimes gets ignored because it's a bit fiddly and flexbox solves SO many design problems, but grid is pretty hip, and the article presents a nice answer for "content mostly constrained to a middle column but with some full width hero-ish images"

Wednesday, July 22, 2020

best options for shared screens on code interviews...

https://codesandbox.io/ seems pretty good for interviewing a candidate but.I think they need a github account? And the old fiddle https://jsfiddle.net/ seems less real-time share-y.

For codesandbox.io the trick seems to be doing "create workspace", a button in the lower left corner, and then maybe sending the link at top after creating a pen. But they do seem to need a github account.

On both sides of the interviewing table I've definitely had some frustrations with glitches in these.

ux ux ux

t's a little heavy handed but MS's medium post on their upcoming UI is pushing things in UX ways

Thursday, July 16, 2020

stating the obvious about the need for "mobile first"

Folks at my current company had to trace down a bug that occurred on specific phones with people uploading resumes... it made me write up the following:

[One take away for me is ...] it's just how people who have been a "techie" for over a decade or two might not fully get just how "mobile first" many folks' lives are! If you are half the time on your laptop anyway, stuff like applying for a job or deeply searching for a good used car - I would never start with my phone, a phone feels like a more casual thing. But - and I know this isn't a news flash- for a wide swath of folks, smartphones are THE way to the Internet. Like, every day the Apple App Store gets more new games than the entire decade run of the Nintendo Entertainment System (not double checking that factoid but it's at least roughly right) Tech's egalitarian nature has kind of exploded, and developers and designers - even the moderately hip ones - need to keep in mind that not everyone is as intimate with tech that sits on a tabletop as they are... :-D

Tuesday, July 14, 2020

a lerna learner, standing up a monorepo from existing repo/packages

Earlier I talked about our use of verdaccio so each developer can trivially stand up their own npm repo. At work we are heading towards a "monorepo" model, with one overarching project and github repository. This should not be confused with a "monolithic architecture": each project is about as standalone (or dependent on others as an npm package as always) as always, but lerna makes it easier to manage versioning 0 and to update a library and quickly start using the changes in a dependent package without the old version update tango... as I put it to one coworker:
w/o monorepo, a dev making a change in a library and seeing it work in the app using it was:
  • update the code in the library
  • update the version of the library
  • publish library to npm
  • update the app so it knows of the new version of the library
  • rebuild the app
But now that's like:
  • update code in library
  • run lerna command to rebuild
and that's it!
For my first example, I went to make a new monorepo called "one-love" to encompass two previously existing packages - ux-poc-stylish-app and the component library prototype it depends on, ux-poc-stylish-components.

Things were pretty well set out at lerna.js.org-
npm install --global lerna
is the obvious first step

Next steps:

git init one-love
cd one-love
lerna init

At this point I had to set up the git repo - I'm not positive you have to stand up the remote on github, but it seemed to help (It's funny how often I turn back to my git 101 notes - it's not like the steps are that hard...) Without standing up the repo, you get somewhat obscure errors like 

lerna publish:Error: Command failed: git rev-parse --abbrev-ref HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree

With the basic git repository I could use lerna import, bring in repos from my local file system:

cd packages
lerna import ../../ux-stylish/ux-poc-stylish-app 
lerna import ../../ux-stylish/ux-poc-stylish-components 
cd ..
lerna bootstrap --hoist

The "--hoist" argument was crucial, but not mentioned much in the main lerna docs.

So then in one terminal window I went to ux-poc-stylish-app and ran npm start. (It had been set up from create-react-app so changes to the core app were instantly visible) 

I updated a component in ux-poc-stylish-components, and then back in main one-love directory I ran "lerna run build" which replaced running "npm run build" in the library. ux-poc-stylish-app then noticed the change in the underlying library and rebuilt and reloaded itself.

UPDATE: javascript-monorepo-with-lerna is another decent overview, but starting packages/from scratch not importing.

UPDATE 2: fair warning, if you're using verdaccio and npm, your package-lock.json might be full of localhost:4873 ... they say npm is now agnostic about which registry you used to generate the package-lock.json but I'm not sure if that means the hosts in the URL don't matter??

Sunday, July 12, 2020

play a sound now if you want to play a sound later (challenges with sound playback on mobile devices)

(Shh, don't tell, I plan to get lots of mileage reusing this virtual card this year 'til July 4th next year, but I figure no one I want to reuse this for actually reads this blog... actually, I don't think anyone reads this blog.)

I had an idea for a fireworks-with-drum-sounds for a July 4th virtual toy (see also this one for loveblender and this one from 2009) but didn't make it in time, but my friend Johnny's birthday was a week after... and he is a drummer! So I made it for him since it was so on-topic and I miss his bass drum with my tuba.

It came together pretty well, you can see it here: toys.alienbill.com/johnny2020 , but sound wasn't working on mobile. Debugging can be such a pain in the butt, I tried like half a dozen things (MP3s not WAVs, make sure there was a touch even before loading the sounds, switching libraries, etc) because I know browsers and especially mobile are fussy about not playing a sound 'til after an interaction... turns out all my sounds were triggered by setTimeout()s, but if I played a sound immediately after click, even "the sound of silence", all the other sounds worked as well.

I also did the CSS `user-select: none;` to stop text from autoselecting with inadvertant doubletaps. I hoped "touch-action: manipulation; " would similarly stop the zoom in/out but less luck there... but I've spent enough time on this today.

Saturday, July 11, 2020

regularly updating in react with pure functional components

I think it's fair to say that playing nicely with setTimeout() and setInterval() is not React's sweetspot, especially when using pure functional components. I feel like I might be missing something (but even Dan Abramov seems to agree) but either something's inside the render (using useState, but being reset all the time in render) or it's outside, and it can't easily hit the state, or you do a mishmash and get an infinite loop of rerenders...

Making things a bit trickier was I needed to instances of these things (I might not have noticed how tricky this was if I was accidentally only using it in a singleton kind of way)

I think this works ok, for a little timer bar that sweeps across its parent...

import React, { useState } from 'react';
import styles from './RiffGrid.module.css';
import { millis2pixels } from '../Utils.js';

const CurrentTimePointer = ({ startTime, isPlaying }) => {
    const [nowish, setNowish] = useState(0);
    let timerRef = null;

    if (isPlaying) {
        timerRef = setTimeout(() => setNowish(Date.now()), 100);
    }
    if (!isPlaying) {
        clearTimeout(timerRef);
        return null;
    }

    return <div className={styles.timePointer} style={{ left: `${millis2pixels(nowish - startTime)}px` }}></div>;
};
export default CurrentTimePointer;

The trick seemed to be setting state with something from outside the system, in this case Date.now(); trying to pull from state for a simple increment gets all confused.

Friday, July 10, 2020

the bad ux of a microwave timer

So here is a bad photo of our serviceable little microwave:

It has a timer function on it, which is convenient, but I really wonder about the design choice to switch back to displaying the clock time after about 5 seconds. Even if you press the "timer" button to go back to looking at the countdown, after about 5 seconds it bounces back to the current time.

Not such a big deal, but I really wonder what went through the mind of the person who set it up that way. It's not like people are gonna set timers all the time, but when they do, isn't that "obviously" the most important thing they're using the microwave and its display for?

Sunday, July 5, 2020

refactoring to more idiomatic react keeping argument names with the spread operator

I'm making my first large React-based personal project, and I caught myself putting too many plain old function calls in my JSX, stuff where I might have a function like

const renderRowLabels = (soundSet, keyCurrentlyPressed) => {

being called by code in (in JSX) like

{renderRowLabels(soundSet, keyCurrentlyPressed)}

it's more idiomatic in React to make such DOM-element corresponding things look more like a tag... so the function becomes

const RowLabels = ({soundSet, keyCurrentlyPressed})  => {

since those two arguments will be passed as keys inside a props object, but we can destructure them on the fly so we don't have to refactor any code below.

Then we change the call to something like
<RowLabels soundSet={soundSet} keyCurrentlyPressed={keyCurrentlyPressed} />

But that's a little ugly, right? Redundant. With ECMAScript hotness, we can take advantage of how we are using the same names for variables in both places, and packup a nice properties bit again with the ... operator:

<RowLabels {...{ soundSet, keyCurrentlyPressed }} />

A little weird looking the first time you see it, but more true to how React sort of wants to be written...

(Note this assumes you are using the same variables names in the parent and the child. Otherwise feel free to mashup this use of the spread operator with regular properties, like
<RowLabels {...{ soundSet}} key={keyCurrentlyPressed} />)

I remember a few months ago when I first "got" the spread operator - how it feels like letting things bust out from serial to parallel, somehow...