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...

Sunday, June 28, 2020

the joy of craft

My friend linked to Craft is Culture which had a big emphasis on Working From Home as standard practice. (Oddly I think that's what is using the term "Digital by Default" for, which is a rather misleading way of putting it, IMHO.)

Danco writes
There are many reasons why the west coast won, but one of the most widely agreed-upon was the fact that California state law forbids non-compete clauses.
I only agree with the part of that before the comma. For my career since the mid 90s at least, they've always been thought of as probably not-enforceable and generally ignored, though obviously the same explicit-IP-protections apply.

I'm not sure of all the reasons for the coast migration. MIT + Harvard and then military contracts like Lincoln Labs and Raytheon were early anchors. But other companies like Intel, Microsoft, Atari, Apple, those were all West Coast, and the new anchors.

I think that there's a limited time when a techie is likely to make a big move to follow a job (though I guess I can think of more examples than I first realized if I try). But there's a big anchoring effect... you go to college, then you either stay in that area, return to your hometown, or maybe land a new job someplace new to you. Then there's about one period in your late 20s where you might relocate again.

The thing about follow your craft is... I think the majority of techies are rather bad at monetizing their craft. They really rely on businesses to make money. Many coders are as stupid about the very basics of how a business can scale up to afford salaries (and health care) and rent - as stupid about those basics as the non-techies are about a full website works. So the 40 hour grinds continue.

It follow from that that I think most techies are fairly risk averse. They might takes some swings w/ a low salary but uncertain high reward in a startup, but that's about it. Entrepreneurial crafters are not so common.

Danco brings up the Cathedral and the Bazaar - and indeed, Linux is amazingly impressive. But I think projects like that work by programmers "scratching itches" as they say. I think Linux was an usually fortuitous mix of some folks who wanted to take on the "big itch" of a whole damn OS, and a legion of people happy to work a bit smaller. Going back to my earlier point, folks coding for the love of craft are usually not working on something that will be as universally useful as Linux has been - or anything that they have a real hope of making a living off of.

easy set of radio buttons in react

It's funny, a few basic elements are a bit tricky in pure-function React - but then again checkboxes  and radio buttons and select/options could be a bit of a semantic pain in JQuery too.

(One real pain was using setInterval - I can use the approach outlined here but it's kind of brittle, like it needs to be inside the render...)

Anyway, here is some quick and dirty code for making a set of radio buttons:
const RadioSet = ({ selectedVal, setter, valToCaptions }) => {
    return Object.keys(valToCaptions).map((val) => {
        const caption = valToCaptions[val];
        return (
            <label key={val}>
                <input onChange={() => setter(val)} type="radio" checked={val == selectedVal} />
                {caption}
            </label>
        );
    });
};
In my case selectedVal and setter are what I get from useState(), and valToCaptions is a just a simple object of key/val pairs. Nothing fancy but I stopped violating DRY with so many radio buttons...

Friday, June 26, 2020

simple checkbox in react using hooks / useState

One of those, oh right duh --
const [thereminMode, setThereminMode] = React.useState(true);
and then the checkbox:
<input checked={thereminMode} type="checkbox" onChange={() => setThereminMode(!thereminMode)} />
It took me a second to realize, we don't have to read anything from the event or the checkbox itself, the verb "change" is enough to do the toggle ourself...

preventing nativeEvent offsetX / offsetY from being blocked by child

"Last night Wes Bos saved my life"...

Well, it was this morning, not last night. And maybe "my life" is overstating it...

But Wes Bos (his React for Beginners class is stellar, and I need to get back to his Javascript 30 - seems like serious playful fun) had a tweet that was hugely useful.

For yesterday's bad react paint program turning into a music tracker, I added a large row hilight div, but it became obvious as the hilight kept jumping that it was blocking the handleMouseMove logic that was getting
const { offsetX: x, offsetY: y, buttons } = e.nativeEvent;

(The offsets were wrong, I guess because the "target" was changed)

That tweet thread suggested some weird updated math when the event target wasn't the current thing (but how to get the "current thing" in React is a little weird?) but luckily there's a trivial (and oddly CSS-based!) solution: on the child element, putting

pointer-events: none;

lets the parent div do all the math.

(That explains why some of the pixels in my bad paint program show up in the top left corner...)

Thursday, June 25, 2020

loading extra files (libraries and binary/sound files) in a parcel app

This is Parcel 101 (or maybe 102) but as I make version 2 of a vanilla js app in React using Parcel, sometimes I forget how things work in this kind of bundled app... you can't just refer to external js libraries in a script tag, and you can't just load a sound file via URL.

The library in question is pizzicato.js, and I put a bunch of files in "src/wav/sound_##_##.wav" where the ##s are two digit numbers.

The lines of code then are:

import Pizzicato from './js/Pizzicato.min.js';
import bundledFiles from './wav/*.wav';

Using Pizzicato is then straight forward (new Pizzicato.Sound() or whatever).

The sound files are a little weirder, you get a js object where the keys are what was put in the wildcard, so sound_06_27 was the key used for the ./sound_06_27.c7ca9f08.wav which was a path I could pass to Pizzicato.

Mischnic's answer on this page was helpful in figuring out the syntax.

Oh, and luckily I remembered Parcel's weirdness in assuming it is serving from the root URL of a site, I overcame that with this line in package.json:
 "scripts": {
        "build-prod": "parcel build src/index.html --public-url ."
The "--public-url" makes it happy to go where it is put.

building a bad paint program in react with parcel

I've had some success making the Atari Sound Forger, a webapp that lets you play with sound files representing noises an Atari 2600 can make by treating the computer keyboard like a specialized piano keyboard. It can even record the loops as you bang them out and play them back in browser or generate a small batari Basic program to listen on a real Atari or emulator!

One user ("Random Terrain", gatekeeper of the batari Basic command list suggested it would be more fun/useful if you could paint on the "piano roll" display ala Mario Paint or what not) - and damn it he's right.

The Sound Forger uses some semi-clever techniques with setInterval and setTimeout to let the browser do a fair job of pretending to be an Atari, but I kind of painted myself in a corner... fundamentally it's recording sound start and stop times in milliseconds (i.e. rather native to Javascript) and then extrapolating to the "frames" (60 per second) the Atari uses. (The sound engine is a pair of single voice/single timers that switches between notes and periods of silence) The algorithm screws up when you overlap sounds though... also while it worked pretty well for "sound on, sound off" approach, more complicated ADSR/sound envelope technique (i.e. hitting the note then reducing volume, like a piano striking a note) was going to be clunky at best.

So I decided to start from scratch, but grabbing tricks and techniques from my old code. Also I thought it would be good practice to switch into React, rather than doing yet another Vanilla JS project.

(Actually, it might make more sense to switch to P5.js, like I did for my playfield graphic editor playfieldpal-bB-DPC  - or maybe at least use a canvas-in-react approach which I would have to study up on, vs the "lets just throw DOM elements at it" approach I'm starting with)

I'm also a little burnt out on the "ALL THE THINGS!" approach of create-react-app, so I decided to fire up parcel. During that process, I (think I) had to update node and even download xcode on my new machine because of some js dependencies.) Also, the one bell-and-or-whistle I wanted was using CSS modules, so I had to follow a few more steps, running
npm add postcss-modules autoprefixer
and then making a .postcssrc file with
{
  "modules": true,
  "plugins": {
    "autoprefixer": {
      "grid": true
    }
  }
}
after that importing a "Widget.module.css" worked as expected and I had nice bundling of components with the CSS that applies to them only.

I decided to start with a simple Proof of Concept paint program... cutting to the chase I ended up the stuff I put in this codesandbox.io. (Out of laziness I punted and went back to normal CSS inclusion for the sandbox)

I used the useState hook, and to keep it simple I collapsed what might have been a 2D array into a map-like object by having the key be x + (y * width) (old programmer trick).

I'm plucking things out of the nativeEvent property of the event object my handleMouseMove function gets:
const { offsetX: x, offsetY: y, buttons } = e.nativeEvent;
I'm not quite sure what e.nativeEvent is... I could dump it out to console.log() ok, and pull out the stuff I need (offset values so the mouse position relative to the top left corner)  but if you go over the keys or call JSON.stringify on it it claims the only key is "isTrusted" (set to true).

So, it's a pretty lousy paint program, missing a lot of dots! (when I made a simpler editor, I used a trick of treating the previous mouse position and current as line endpoints to get all the dots inbetween). But for the app I have in mind, the grid is much less "fine" (it may even use clicks instead of drawing for the most part) and I think this technique (of putting small pixel-y <div>s  over the parent space for the dots) should work ok.

Wednesday, June 24, 2020

remembering AOL instant messenger

Nice tribute to AOL Instant Messenger. I feel like my friends and I were funnier on AIM than we are on the current chat options. Maybe it's the setting? Like it's easier to think of something clever typing on a normal computer with a keyboard and a big screen than tip-tapping on a mobile device?

The article mentions the art of the away message... I think that tends to be a youth thing. Like in college, we had ".plan" files, what people would see when they ran the "finger" command on your account (and yes, the jokes about that verb were plentiful and rarely subtle). It shared that youthful romance energy as mentioned in the article, wistfully seeing if your crush had logged in and checked your email and not bothered to reply, and leaving a message that you hoped they might see but might never know if they did.

(Not even sure if there's a social media equivalent of "away messages" and .plans - maybe avatar photos and what the banner image on your FB profile page?)

gmail feeling like an old car

A piece going over some of the features of the Hey e-mail service, and how they cleverly borrowed interface patterns from other things like social media and the MacOS dock to make a better e-mail experience.

It makes me realize that I've been using gmail for about as long as I've had my current car, about 16 years. Besides the value of 16 years of mail archive (and my hesitation to use an email service where I assume I'd lose my account if I stopped paying - "free" is a dangerous and addictive drug!) the gmail feature I'd miss if it wasn't well-replicated is sorting my inbox into "Important and Unread" vs "Everything Else" (with a little section of starred items to get back to.) That separation of the sheep from the goats works better for me than more fine-grained categories.

Monday, June 22, 2020

good dev articles

Underrated HTML tags - big fan of details/summary, hadn't heard about progress...

I have a hard time being snarky about clichéd font choices, but this article has some good counter-suggestions as well.

10 Tips and Tricks That Will Make You a Better ReactJS Dev - I think the title is misleading, but it's a great overview of some of the more recent trends in React land - Functional Components w/ Hooks, Context API, Styled-Components, Fragments, Error Boundaries, Typescript, Jest/Enzyme Testing, Conditionals, Higher-Order-Components, React Dev-Tools, Plug-ins for VS Code.

Here's a trick for better names for Styled Components - just the other day we noticed that was kind of a problem, nice to know there's a fix for it, setting .displayName on the styled.whatever`thing`.

Friday, June 19, 2020

creative coding (with face tracking and sound generators!)

Man, I love P5.js and creative coding -

The use of clmtracker to do some basic webcam face recognition work was especially inspiring.

UPDATE: I decided to retrace her steps and it was a little tougher than I expected - it's not easy to follow code footsteps in general and in particular proper loading of the clmtrackr library was a oddly challenging - the CDN link she uses seems to be defunct, and a few other attempts to pull from a CDN, from github, or my own webserver didn't work (blocked by CORS errors) but finally I got it by downloading the raw clmtrackr.js file linked to from the github README, then going to the left sidebar (the arrow under the "Play" button) then hitting "Sketch files | Upload file") and putting it there, then editing index.html so it pointed to it:
    <script src="clmtrackr.js"></script>

At first I didn't do the sound oscillator she does, but here's a version that just puts circles on all the tracking dots and here's one where I play with making a virtual mask with a responsive mouth, like a very poor version of Animoji...

(The face tracking really isn't great, sensitive to both lighting conditions and me wearing glasses.)

Finally I put the same kind of sound oscillator she does back in for a full mask and sound fest... hold the mouse to make a noise, the distance of your nose from the center controls the frequency, and how open your mouth is is the volume...

Thursday, June 18, 2020

"I could hit a dozen with a bread roll from where I'm sitting."

"Now wait," he interrupted before Richard even had a chance to start, "don't I vaguely remember that you had some sort of computer when you were here? When was it? 1977?"

"Well, what we called a computer in 1977 was really a kind of electric abacus, but..."

"Oh, now, don't underestimate the abacus," said Reg. "In skilled hands it's a very sophisticated calculating device. Furthermore it requires no power, can be made with any materials you have to hand, and never goes bing in the middle of an important piece of work."

"So an electric one would be particularly pointless," said Richard.

"True enough," conceded Reg.

"There really wasn't a lot this machine could do that you couldn't do yourself in half the time with a lot less trouble," said Richard, "but it was, on the other hand, very good at being a slow and dim-witted pupil."

Reg looked at him quizzically.

"I had no idea they were supposed to be in short supply," he said. "I could hit a dozen with a bread roll from where I'm sitting."

"I'm sure. But look at it this way. What really is the point of trying to teach anything to anybody?"

This question seemed to provoke a murmur of sympathetic approval from up and down the table.

Richard continued, "What I mean is that if you really want to understand something, the best way is to try and explain it to someone else. That forces you to sort it out in your own mind. And the more slow and dim-witted your pupil, the more you have to break things down into more and more simple ideas. And that's really the essence of programming. By the time you've sorted out a complicated idea into little steps that even a stupid machine can deal with, you've certainly learned something about it yourself. The teacher usually learns more than the pupil. Isn't that true?"

"It would be hard to learn much less than my pupils," came a low growl from somewhere on the table, "without undergoing a pre-frontal lobotomy."

"So I used to spend days struggling to write essays on this 16K machine that would have taken a couple of hours on a typewriter, but what was fascinating to me was the process of trying to explain to the machine what it was I wanted it to do. I virtually wrote my own word processor in BASIC. A simple search and replace routine would take about three hours."

"I forget, did you ever get any essays done at all?"

"Well, not as such. No actual essays, but the reasons why not were absolutely fascinating [...]"


--Douglas Adams, "Dirk Gently's Holistic Detective Agency"
This anecdote -in particular the "I could hit a dozen with a bread roll from where I’m sitting" line - has always stuck with me, and I thought of it when I was talking about programming to a friend (she brought up a lesson she had had at computer camp, where you have to give painstakingly step-by-step directions for making a peanut butter sandwich to another camper who has to follow them extremely literally.)

I do think that anyone who can write down a recipe a beginner can follow is in good shape to try programming.

Wednesday, June 17, 2020

not the hill I'm willing to die on but - yeesh, unit tests

Sometimes in my recent round of job interviews, I would let it be known that I have an unpopular opinion- that unit tests are wildly overrated.  Based on the reaction I get from people -- and some biased googling I do -- it feels like I've stumbled into a bit of an Emperor's New Clothes situation - many coders seem to agree with my sentiments. But there is a large group of influential people - either coders or managers - who I assume would say I'm spouting lazy and reckless nonsense.

Here are some ways I have of putting it:

  • An extreme focus on unit tests - especially at the cost of pulling attention and resources from higher levels of testing - is like obsessively inspecting all your individual Lego Bricks for cracks and defects. Yes, it's important to be building with solid bricks, but honestly that's not where the problem in your structure is going to show up! 
  • Bugs are emergent properties! A well designed unit should be just about "too small to fail"
  • The problems I see actually show up in production are coders coding along the "happy path" - and then that same "happy path" is what is baked into the setup of the unit test. (I wish instead of testing the units, we had much more emphasis on firming up the contract between the unit and its environment...) 
  • And as for coders writing their own tests - it's very difficult to persuade someone to do a really focused search on something they don't really want to find - i.e. flaws in their previous work.
  • It's like testing 100 trees and saying "yup, I know this is a good forest"  
It's not a hill I'm willing to die on, I'm not going to be "That Guy" about it. If this is the Kool-Aid I'm being paid to drink, I'll have plenty of gulps. I understand there are some side benefits - it can get a coder to think more clearly about the inputs to the thing, it can make future refactoring feel safer, etc. But I'm going to be hard pressed to believe that that kind of benefit is worth the cost of making and maintaining this shadow implementation of every damn unit.  (And when I heard my manager's manager say "well we expect as unit coverage increases, the number of incidents in production will go down accordingly" I had to bite my tongue...)

I liked Mark Talbot's answer to the Quora "Why do many programmers think that unit testing is not worth it?" - in part -
The problem is that as soon as you replace some dependency with a stub or mock, you are no longer testing the system in the same way it works in production. All you have done is assume that your stub/mock behaves in the same way as the dependency it is replacing (at least as far as the unit under test is concerned) and then write your tests based on that assumption. But it is not valid assumption. If I come along and modify the real dependency (maybe it’s some 3rd party library that I’m upgrading) I have no idea at all whether your code really works with the new dependency, because all the calls to it in the unit tests are stubbed out. (And I’m not going to check all 500,000 lines of code manually - what is the point in automated testing if I need to do that?)
See also some bits I grabbed on Joel Spolsky on Complete Test Coverage...

Since some of the people who are unit test advocates are pretty sharp, I have to assume it's one of those "different ways of looking at the world" things - Douglas Hofstadter writes on holism vs reductionism and I think it may be one of those kind of things - reductionists assume it's mostly a matter of making sure each part works. But in general, I'm always more concerned about interactions - the surface of contact vs the essence of what something is in isolation... so I think unit tests are not worth the reputation they seem to carry.

Tuesday, June 16, 2020

tic-tac-toe

Heh. Just noticed the React tutorial is the same programming task I gave myself as a 9 or 10 year old kid: a 2-player only Tic Tac Toe game. (Ok, no, this is not demonstrably better than a piece of paper, that's not the point!) What's really striking for me is that it uses the same method of determining if there's a winner that I came up with as a kid - just see if any of the 8 ways of winning are filled with all "X"s or all "O"s. (I remember my Aunt saying she was impressed that I came up with that when I geekily showed off the method to her...)

some decent js and react articles

Learning JS synchronicity via a series of horse races is a clever way of showing how JS itself is pretty synchronous, but has asynchronous libraries and environments.

Write clean(er) Components & JSX was some pretty clear, no-nonsense advice showing common semi-mistakes, why they happen, and what's a better solution.

React Hook Form VS Formik

Stop Mocking Fetch - I like the way this person thinks about mocking stuff up. I've had some peers who I thought were otherwise brilliant, but when it came to tests, they encouraged "just make sure the mock is called the right number of times" and not worry if the right info was being passed into it, or even if the client was doing the right thing with the data...

Thursday, June 11, 2020

css hack: win the specificity wars by doubling or tripling up at the classname

Heh, styled-components.com advanced page had a hack that I hadn't thought of but seems obvious in hindsite:

.red-bg.red-bg {
  background-color: red;
}

Like, make sure it REALLY is read even if there was a .green-bg class defined as well.

Well, beats !important, I guess?

Wednesday, June 10, 2020

git 101

So, a bit of git 101, but not something you actually do that often: creating a new git repository, both locally and on your primary remote, from an existing folder (like maybe something created with create-react-app or similar) Like, I wasn't sure if you had to start making the remote archive, or you could push it straight to remote from local.

The answer is you kind of meet in the middle - set up the local repository, go to github and do a new repo there, then tell them about each other. This page walks you through it, but for future reference, the important thing was:
in the folder, do a

git init

then maybe a

git add .
git commit -m "first commit"

and that sets up your local repository

Then go to github, hit "New", give it the (probably same) repository name...
github then gives you the command hint you need, "...or push an existing repository from the command line":

git remote add origin git@github.com:COMPANY-ETC/WHATEVER-THE-NAME-WAS.git
git push -u origin master

and Bob's Yer Uncle.


good piece on design systems

Everything you need to know about Design Systems ... probably doesn't live up to its name but still is good.

atari 2600 homebrew programming - 88 lines about 32 pixels

I've been getting back into programming the Atari 2600 again.

This past week I updated my 2015 Global Game Jam project Loaded4Bear - now it has an aggresive but not too bright AI opponent option.


I've always liked Atari games that have the computer playing by the same rules as the human, and long was thinking I should get back to add that to the Loaded4Bear. - I wasn't sure if I could! So I'm chuffed to have done it.

Also, the music by Oliver Getz is amazing- I showed him the basics (no pun intended) and he did some great work back then.

This is all made feasible by batari BASIC - my first homebrew in 2004 was in assembly and cost me a year. The GGJ version of this game took a weekend, thanks to this language.

The canonical place to learn about the bB is Random Terrain's batari Basic command page though it is rather overwhelming! There are more tutorials and information at the AtariAge batari Basic forum.

Many bB users like coding in "Visual batari Basic" as an IDE though, besides the fact it's Windows only, I never could get my head around its version of asset management. There is a pretty good plugin for Visual Studio Code called "Atari Dev Studio" that makes the process look more familiar to folks who program as day job. It's cool to be able to copy and paste in a program listing, click the button, and have it run in an emulator.

I hacked together two simple P5.js tools for drawing the Playfield (background) graphics - one for the old school regular playfields and then one for the  highrez 88-line DPC+ playfields... for the former, it creates an entire runnable program, and the latter outputs something you can put in a standard DPC+ template. (The ability to just copy and paste into a single file, and then run and have a game, harkens back to the old days of magazines with type-in-listings. (Also Java Processing/P5, come to think of it) - just so elegant to have pure text turn into graphics and interaction!)

The DPC+ thing-- a lot of Atari 2600 homebrew has gotten away from the classic "4K Rom, 128 bytes memory" and using "DPC+" which offloads much of the processor work onto an oncart-chip. There's a temptation to think of this as cheating, but it's based on what Activision was doing with Pitfall II, and then what companies like Nintendo would do with Star Fox etc. Still, I think there's much charm to seeing what kind of a game can be made using the original limitations of the basic hardware and sofware.

GEEKNOTE on those editor tools I built - it was great to be able to make them in a hurry! (Though a little weird to be using such power technology in the tool chain for such old stuff.) The only bit of cleverness was A. a flashing cursor box to show you which pixel would be set and B. at first I just drew whatever pixel was under the mouse during the "drag" movement, but if the mouse was moving quickly, spaces in between would be missed.

I went from this simple check: (edited for clarity)
function mouseDragged() {
      const x = int(mouseX / PIXW);
      const y = int(mouseY / PIXH);
      grid[x][y] = isDrawing;
  }  
}
to this loop that imagines a line with 100 intervening points from the previous mouse position to the current mouse position, and runs the same check for each pixel underneath -
function mouseDragged() {
  for(let i = 0; i < 100; i++){
      const tx = map(i,1,100,pmouseX,mouseX); 
      const ty = map(i,1,100,pmouseY,mouseY); 
      const x = int(tx / PIXW);
      const y = int(ty / PIXH);
      grid[x][y] = isDrawing;
  }  
}
A little redundant but works great!

Tuesday, June 9, 2020

worst chart ever?

Wow. Daring Fireball pointed to a horrible, misleading, terrible, idiotic chart from CNBC.

The events are pretty simple to understand. One month, we lost 20 million or so job. The next month, we get about 13% of those back. (Or other jobs show up.)

How should we display that? NY Times showed "number of jobs" - starting with a baseline of 130 Million half way through the first Obama presidency, then steadily increasing until this spring. Finally, a plummet, with a bit of a bounce:


Here's how CNBC chose to display the same phenomenon:


It took me a second to even figure out what it meant. It's like "rate of change" in calculus or physics... from 2015 we see a small positive value, new jobs added. Then we lose a HEAP of jobs. Next month, we gain more jobs than usual - but all that means is 10-15% of the jobs came back, or got replaced. Not so good if you're one of the 85-90% of the millions who lost theirs!

Gruber pointed to this twitter thread with a few more honest depictions.

UPDATE:
looks like it's now like this:


that's a bit better than I guess. Using a bar graph shakes the idea that there is meaning to the area under the graph...

Monday, June 8, 2020

visual studio code: settings by User, Workspace, or Folder...

It's a powerful and easy to use idea once you know the trick, but it's easy to miss at first: customizations in VS Code are "by user" by default, but you can do it "by workspace":
In this case, I'm doing more work across packages (including mockup companies "PurpleCo" and "GreenCo") and setting a color theme that reminds me which space I'm in is great.  ("Quite Light" is my usual go-to.... and I still wish "Dark Modes" weren't quite so popular, for folks with astigmatism it's a world of dancing after images.)

Sunday, June 7, 2020

silicon valley is all about the database shoving

"One could criticize no-code for not offering the flexibility and nuance you can get by writing your own code, line by line. But the truth is, for all the hoopla about Silicon Valley's innovative genius, a huge number of apps don't do much more than awfully simple things. Seriously: Silicon Valley's main trick is just shoving things into a database and pulling them out again. I'm exaggerating, but only a bit."

Thompson is so right about the "trick". There's lots of details to get right - making sure people shove in the right stuff (UI) making sure the wrong people can't then pull out other people's stuff (security) ensuring lots of people can shove (scalability) and coaxing people to put the stuff in (UX) but 80-90% of everything is this database shoving.

That's also adjacent to a model I had to make to describe the priorities of some new-fangled systems for UI - there's been a strong tend towards "declarative" programming for making web apps - with an assumption that the best thing a UI toolkit could do is make it super easy to have the webpage instantly update itself to reflect the content of the data in the browser's memory - that way the programmer doesn't have to manipulate the page, just massage the data. It took me a while to realize that one reason I was slow to see the appeal is that I never thought the "in browser memory" mattered much - the stuff in your server's database is what really matters, and the presentation of it on the webpage to the user matters, but anything in between (like the data in the browser's memory) is just an artifact.

Friday, June 5, 2020

running your own npm repository with verdaccio

Verdaccio seems pretty good to set up your own local npm repository, like a poor man's artifactory (guess these all have passthroughs to the main npm).  Here's a decent walkthrough for a hello, world.

UPDATE A few weeks later, I'm more fond of verrdaccio. My guess is that using it is a more "real" experience than using `npm link` when you're pulling from your local repos, and it smoothly passes through requests for all the other packages that's aren't local, so
npm set registry http://localhost:4873/
is a safe enough thing to do - but then you have to make sure it starts up every time you log in or run it yourself (I kind of like having it in a background terminal window and watching it handle all those requests, especially now that I have an extra vertical monitor to run it on.)

Thursday, June 4, 2020

great twitter thread and article on how few coders actually remember everything these days

If You Want to Be a Senior Developer, Stop Focusing on Syntax has a delightful twitter thread starting
Hello, my name is Tim. I'm a lead at Google with over 30 years coding experience and I need to look up how to get length of a python string. --@tdierks
That's really the way of the world these days.

Tuesday, June 2, 2020

challenges prioritizing specific classes using sass themes and css modules

At work we're proof-of-concepting using Sass and CSS modules, trying to find easy, flexible patterns to allow projects to have their own themes while still having shared components carry their own CSS.

Things built up pretty well: we had a project that had its own .scss file, and then a subproject with a .scss file that imported the base .scss.

I made it so our shared components could take in a className property, so that individual instances of a shared component can use a different class - or rather, can use that class as well. That worked ok for the main project, but the subproject's defaults were being applied after the individual override class.

I thought of insisting that override classes be "inside" of the class their overriding, like:
.btn {
   .specialcaseclassname {
  }
}

But that wouldn't work for the subproject including the base projects "btn" (but overriding it) - the name were munged

Three possible solutions:

  1. !important would work, but everyone would hate that. 
  2. We could set up a rule that every override class in .scss would have to use @extend against the base class, and then change our components so it would leave out the theme's class.
  3. We can declare that all override classes (at least those that are shred by multiple subprojects) must be in a separate file (and the override Sass files must be imported after the main theme Sass)
It's really a bummer that the order CSS classes are specified in for a DOM element don't matter,
<div class="mainthing specialcase">
is the same as 
<div class="specialcase mainthing">

Otherwise we might have another option. But I guess "3" it is.

Sunday, May 31, 2020

adding git branch info to macos zsh prompt, and using pico

I'm trying to get a more fluent with command-line git, and it's pretty easy to get zsh to show you the current git branch as your prompt. Here's my new ~/.zlogin:

alias ls="ls -F"

autoload -Uz vcs_info
precmd() { vcs_info }

# Format the vcs_info_msg_0_ variable
zstyle ':vcs_info:git:*' formats ' 🛰 %b'

# Set up the prompt (with git branch name)
setopt PROMPT_SUBST
PROMPT='${PWD/#$HOME/~}${vcs_info_msg_0_} 🚀'
I like using emoji as concise and obvious at a glance prompt delimiters.

Also I have to be sure to set a default editor I am comfortable with:
git config --global core.editor "nano"
Interesting that emacs doesn't ship with MacOS, but I'm not so enamored of it that I'm going to seek it out. Never got my mind around the modality of vim. nano/pico feel kind of clunky and almost DOS-ish, but for the small number of tasks where it's not worth firing up Visual Studio Code, it's fine.

Saturday, May 30, 2020

for people considering a career in ux

I was contacted on LinkedIn by a person thinking of doing a UX Designer bootcamp. And I have another friend going down the same route.

I know it's easy to think of the career choice as "UI for people who are too intimidated by front end programming" but that's not fair - there are a lot of skills a good fulltime UX designer has that I only have in a rudimentary form (my current job title of "UX Engineer" not withstanding... I do fear they are using the aspirational sense of UX vs UI vs the in the trenches one.)

My partner M. got a bit frustrated with her role as UX Researcher.  She finds Nobody told me UX would be like this to be pretty accurate. It's not meant to scare people off, but to have realistic expectations - many places don't embrace UX expertise as much as they should, since often it can run counters to the "gut knowledge" of developers and business planners.

A Day In The Life Of A UX Designer is a bit more sanguine.

Also M says if you're in Boston, check out some of the meetups (not sure if they are still operating in quarantine times in a virtual form or what) - UXPA BostonBostonCHI, and Ladies That UX Boston.

Friday, May 29, 2020

combining css modules, sass, and context providers for swappable themes with locally scoped css

Esay Silva's How to use Sass and CSS Modules with create-react-app does a great job of setting up Sass with create-react-app and then using them as CSS modules... node-sass does a good job of letting your create-react-app created react app use Sass - if you name a css file Foo.module.css or Foo.module.scss, it gets automagically locally scoped classnames, so your react code can be like

import BrandStyle from "./GreenCo/Theme.module.scss";

and then later 

<button className = {BrandStyle.btn}>Assuming .btn was the original class name</button>
The css sent to the browser will prefix .btn with a unique bit of randomness, so you can safely have lots of components with css code that refers to "btn" and they won't interfere with each other in the browser.

There's nothing too magic about that object you get from the import (the one I'm calling BrandStyle here) - it's just a map from the name as it appears in your original .scss or .css to the name it shows up as in the css that is sent to the browser. (And you can further refer to multiple class names, either with the lightweight classnames utility or just by gluing various parts together with spaces.)

But if you're thinking in terms of a customizable Component Library where you would like developers to be able to override styles of some basic components, but without passing in the overridden styles or CSS to every child, you can do it via context.

I was  rusty on React Contexts - at first I thought by wrapping a segment of JSX/Dom in a Context, each child would get new properties automagically... nope! "Context" is its own beast and doesn't use props to do its thing.

It seems best to make up a trivial custom Context object that can be referenced both by the parent / grandparent app or component as well as the children that will be reading from it...

ThemeContext.js:
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;

and then use it as a Provider in the parent:

App.js
import BrandStyle from "./GreenCo/Theme.module.scss";
import ThemeContext from "./core-ux/ThemeContext.js";
//... 
      <ThemeContext.Provider value={{ brandstyle: BrandStyle }}>
        <header>
          <PushButton>Button by Theme....</PushButton>
        </header>
      </ThemeContext.Provider>

and then refer to it in the child:

PushButton.js:
import styles from "./PushButton.module.scss";

import ThemeContext from "./ThemeContext.js";

const PushButton = (props) => {
  const theme = React.useContext(ThemeContext);

  const comboStyle = `${styles.btn} ${theme.brandstyle.btn}`;

  return (
    <button
      className={comboStyle}
//...

So here we see how it can have its own local styles in PushButton.module.scss, grab an additional style from the ThemeContext, and then combine them in a string. (In the actual code I do more checking to make sure theme.brandstyle exists.)



making a new mac feel like home

When I replaced my 2012-era MacBook Air with one of the new models I used Apple's Migration Assistant - good results in the end.

With my new work laptop (mercifully one of the new MacBook Pros with a proper escape key) I was setting it up from scratch, so here were some notes on the quality of life improvements I make, most of which I've written about before:

Settings I fix up:
  • Add a "Quick Action" for convert to jpg (for HEIC images bumped over from iPhone)
  • Make Paste and Match Style the system wide default for cmd-V - especially noticeable for the Stickies application
  • Change the default Screenshot location to ~/Downloads
  • Arrange the Finder sidebar - I do favor ~/Downloads as my generic "temp" space so it makes sense to make it higher in the shortcut list there.
  • Get all that extra crap out of the Dock and make it automatically hide
  • Make Terminal automatically close when I exit the shell ( Go to Terminal|Preferences|Profiles|Basic/Default and select “When the shell exits:”)
  • Finder I set to always show extensions
  • I don't like most of the "More Gesutres" under Trackpad settings except for Mission Control (3 finger swipe up to see all windows) and I enable App Exposé (3 finger swipe down for just the windows of the current app - not sure why that's disabled by default.)
  • MacOS' default shell is now zsh. I fire up `pico ~/.zlogin` and set the following:
    alias ls="ls -F"
    PROMPT='%~🚀'
    That shows me which directory entries are directories themselves, and then a nice minimalist prompt with a condensed version of the path, and the rocketship (from Edit | Emoji & Symbols) reminds me I'm on my home system.
Some Apps I add:
  • SizeUp and HyperSwitch - I set up opt-cmd-arrows to bounce around windows like a boss with the keyboard in SizeUp, and HyperSwitch restores sanity to switching to Terminal or Finder - opening a window if there aren't any there, just like clicking on the Dock.  
  • Add the convenient menu bar status menu quick note apps Tot and Tyke - (also for the first time I noticed I can use cmd-drag to rearrange that top bar! My employer has a bunch of VPN and file sharing stuff that has to live there but I can shunt it off to the side)
  • Add Haptic Touch Bar, switch over to traditional button like controls, and shove them over to the side where they won't be accidentally brushed... (still so foolish that a finger brush is the same as a click for the touch bar!)
Common Apps I need to tweak:
  • In Chrome I like the "Humble New Page Tab" for getting a view of my bookmarks, and adding the React plug in etc.
  • Install Visual Studio Code... I like the “Quiet Light” Color Theme, and then I've been using plugins Prettier - Code Formatter (making sure format on save is on), ESLint, ES7 React/Redux-Native snippets, Babel JavaScript - and I disable auto-completion of quotes and braces

Anyway, nice to have reference to the little things that make a Mac more comfortable for me.


Sunday, May 24, 2020

interesting post roundup

After this last round of job interviews, I want to be paying more attention to trade articles and what not. And it seems to make sense to post them here, even though part of me says "well shouldn't people just go to sources I got them from?" But this blog can both A. serve as a curation for other people (honestly there's a lot of stuff especially on Medium that feels a little questionable) and B. this blog has always been notes for my future and present self - future self for the obvious "in case I think of it and want to find it" and present in the sense that maybe making a link will help me remember the article in the first place.

So I'll stop apologizing for blogging, and get on with it...

Stop Writing Reusable React Components has a great point, that pre-engineering for reusability is often counter-productive. (It reminds me a bit of my anti-"buy" lean in make vs buy; sometimes using a toolkit just for one part of its featureset is like buying a whole house because you loved the modern kitchen.) Also, I'd say if the choice comes between "reusable but complex enough it well-justifies its unit tests" vs "a one-off simple enough that there's not much that can go wrong", i.e. few moving parts, choose the latter. (And amusing third hand line from the article:  To steal a line from Chantastic over at React Podcast, my code was “so DRY it chaffed.”) (here's sort of a counter-argument, or maybe a case in point; what are components doing where it would be worth handling overrides vs letting people make their own bespoke copy?)

Why You Should Be Storing Remote Data in a Cache (and Not in State) seems a pretty good answer to a question I've been thinking about, where to put data if you're not using a central store ala Redux or MobX... this pattern basically has a key of the ajax request, caches the result, and then has components rerender if the value returned from the server is different.

Learning a bit about tagged templates in this piece on styled components - boy, I am not sure "tagged templates" pull their weight - yet another damn bit of syntactic sugar to learn, with oddly crude implementations - but maybe I just haven't seen their sweet spot yet.

UPDATE:
Other things: Verdaccio is an easy way of running a local npm repository.

How to use Sass and CSS Modules with create-react-app is just what it says on the tin - great when you want to have safe and modular CSS via Sass.


Saturday, May 23, 2020

pretty good video on js most used tricks

I think I'm due for thinking more about querySelector() as well as asynch/await all that goodness.




Also I kind of like the thinking behind this custom hook to manage UI state as status - starting with the UI trope of "loading w/ spinner, then show results, or empty, or error"

Wednesday, May 20, 2020

second-guessing the modern web

Apparently making the rounds, Tom MacWright's Second-guessing the modern web.

I've been talking with many folks doing my job interviewing (mercifully drawing to an end) as well as doing a small pile of mini-projects, and the whole question of what makes a good back end and what makes a good frontend is very much on my mind, and I appreciate this semi-contrarian view.

I wonder if I'm a little insensitive to render performance, or if some people are too uptight about it. Even the level of React's Virtual DOM - my new online card game does something like declarative rendering, but just raw, and for smallish updates there's no sense of flicker, even though the whole UI is being erased and built back up.

(See also Rich Harris' rebuttal)

Tuesday, May 19, 2020

some useful react libraries

5 Awesome React.js Libraries You Should Know About. The toaster popup especially seems useful. Also this one on React Animation Libraries. I still think declarative languages are less friendly towards graceful transitions in general; re-renders natively jump from snapshot to snapshot so it takes some wrangling to think of things as persistent and changing.

Monday, May 18, 2020

#foolish-idea-friends, or how to make company slack culture fun and creative

One of the things I miss most from my old job was a certain slack channel - "#foolish-idea-friends" (channel name changed to protect the guilty.)

The heart of the slack channel was an ever-growing number list of foolish ideas - concept pitches. A few basic rules were established from the outset: no criticism of ideas were permitted... just because an idea was foolish didn't mean it was "bad"... ideas had to be original as far as we knew to get a number (later a habit of bringing in ideas from elsewhere with the tag "#SEFI" (for "someone else's foolish idea") instead of a number)

One of the fellow pioneers of the channel had written bots to scrape the ideas (one Foolish Idea was to make a "best of" book) and sent me a list of my 1000+ contributions. I had done over a quarter of the almost 4,000 the channel was up to upon my departure!

FIF #600 gives an idea of what the channel was most often used for:
  • #600 categorization system for f-i-f; semi-serious but possibly outlandish proposals, less serious proposals just for a laugh, ones added quickly to grab a big number, thinly veiled complaints about stuff in the office, general-joshing on each other, other meta-stuff
So, I read through all my entries and here were my very favorites, in roughly descending order of how much I liked 'em:
  • #1500 new html6 attribute: onlick. Like onclick, but you know, for licking things. Steve Jobs said "We made the buttons on the screen look so good you'll want to lick them." and I think modern web browsers should be ready for this.
  • #321 formation of a committee to determine the plausibility of "aggressive passive" behavior; for example, furiously hammering water
  • #212 A Street Fighter-like game but with the characters from Peanuts (Snoopy, Charlie Brown, etc)
  • #1465 Trying to declutter but Marie Kondo is too pile-centric or mumbo-jumbo-y? Arrange all your possessions in a long straight line ordered by how much you want each item, make a perpendicular line at the cut off point, and discard everything to left. DONE AND DUSTED.(Note, you may still have to dust, especially around those shelves where the cluttering items used to sit.)
  • #1576 If you have a device or thing in your life you really like and use a lot, like a laptop or iPad or video game system or something, have a loved one wrap it up so you can open it christmas day and think about how much you like it.
  • #823 A service where university professors will adopt your child so they can get free tuition at that university
  • #2565 A post-mortem service to excise and preserve specific body parts for rhetorical purposes. For example, a wedding finger for a loved one to keep, or a middle finger to send to a person you despised in life, or maybe your whole butt for a hated organization to kiss. The body part can be cremated, preserved in resin, or bronzed.
  • #2226 Life in a zero-G or microgravity environment (like on an orbiting station or a spaceship that is not manuevering) offers many challenges. When you're exercising on the treadmill or just sitting at a work console, you need to strap yourself down with elastics and velcro. Exhaled CO2 silently pooling around your head is a constant threat if the air circulation system isn't perfect. And if you lose momentum in a large open area, like thanks to air resistance, it can be nearly impossible to get moving again. The solution to all of these is clear: astronauts should always wear old-school propeller beanies at all times when not in their helmets.
Some of my ideas I'd like to see for real:
  • #1368 every damn smoke and carbon monoxide detector should have a small lcd or e-ink screen that will you tell you its status. no more of this stupid "let me communicate through infuriatingly intermittent chirps". i mean seriously
  • #1474 a film crew/biography service that parents can reserve for their young kids. Every year for your unbirthday (6 months opposite your birthday) they come and do a "day in the life" taping, as well as have their writers talk to you and write up what's on your mind and what your life is like
  • #3470 make tombstones out of wet cement and let people at the funeral scratch in their final messages to the deceased
  • #887 All light switches should have a tiny LED to show if it's on or not. (In some rooms it's obvious, but when the light switch is on the other side of the closed door...)
  • #1471 an app to help remind you to keep in contact with friends you don't see regularly. Enter your friends names, and how important they are to you, and it will create a queue of people and nudge you when you should send a "just saying hi" message
  • #1588 First Class Deluxe Junk Retirement. Trying to declutter, but stuck with stuff with sentimental value, and/or with no second-hand value? First Class Deluxe Junk Retirement will come to your house to pick it up, take a photo and send it to you, and then put it in a special mausoleum landfill. For example, my "Euclid High School English Departmental Award" medal with ribbon, from 1992. I will never do ANYTHING with this, right? And yet it's weirdly hard to get rid of. Ditto my heavy duty Varsity Jacket with built in cape/hood.
  • #1438 One of my best FIFs ever - ok - so our cat has a "food puzzle" where you put kibble in a bunch of little plastic obstacles so the cat can't just chow down, but has to work a bit for each piece. It's meant for exercise, I guess, besides the mental stimulation factor, but it would be MUCH better if you could pour the kibble into some kind of little home base thing and then have little robo mice, each carrying a single platter that could hold just about one piece of kibble, and the cat could chase each bit, knock it to get the kibble, and then it would go back to the home base to get another piece...
  • #355 see-through lids for toilets so you can ensure all the material was whisked away instead of leaving it as a gross surprise for the next person, and without aerosolizing the gross stuff either. (Or possibly a sophisticated sensor system to take of reflushes automagically)
Of course, some FIFs I ended up doing for real:
  • #1073 learn that little 'waiting' step b-boy dancers do right before they launch into something truly impressive. but never do a fancy move, just do the step over and over
  • #768 Make an MP3 of silence or someone going "that's the end!" and name the tune early in the alphabet, so when iOS has decided it has run out of audio to play and for some reason starts playing "all songs alphabetically" you don't get blasted by Michael Jackson going "A B C, easy a 1 2 3" ALL THE DAMN TIME
  • #1515 out of churros? try this delicious salty, sweet, crispy, chewy dessert: take a chocolate from the front desk (preferably dark or choc w/ caramel) and put it between two tortilla chips!
  • #2758 new drink: Apple X-Cider -- take one cup of company cider, drink while sucking on an Atomic Fireball candy
Some of my thinly-veiled complaints:
  • #270 default slack avatars that are flash GIFs that trigger epileptic seizures so users have a moral and possibly legal obligation to change them
  • #391 gamify gamification! every scoring rule you invent for whatever you are gamifying gets you a G.G. Star!
  • #485 Start postfixing updated versions of functions etc with "New". This is super great for sites that have "New" and "Used" cars, so people get to enjoy making up heuristics like "if the New is a prefix, it's probably about new cars, but if New is a postfix, it's probably just a later version of a previously existing function"
Sometimes I just went for the gag or pun:
  • #2718 Luggage with face detection that is also delighted to see you as it swings around the baggage carousel and can express that- makes you feel loved after a rough flight and helps you locate your bag. The name of this wonder-product? "emotional baggage"
  • #432 pave a road with bad intentions, see where it gets you
  • #2190 market an extra-rough brand of kleenex called "grindstone"
  • #2793 football uniforms made out of really stretchy material so if a defender grabs you by the uniform you can just keep on running. Bonus: if defender is really strong and heavy and manages to hold on, comedy as you get flung back to him like a rubber band.
  • #2567 Along with surgery to reduce snoring, surgery to increase snoring but it comic ways - giant long snort on the inhale, descending whistling tone on the exhale.
  • #38 alcoholic drinks mixed with aspirin and gatorade to get a jump on your hangover the next day
  • #250 a bumper sticker that wards off cops by saying "don't worry i've driven MUCH drinker than this"
  • #2560 combine "Now & Laters" candies with "Atomic Warheads" and call them "Apocalypse Now & Laters"
  • #2714 make a 60s/70s mashup cover group called "Earth, Blood, Wind, Sweat, Fire, and Tears."
  • #711 Find that butterfly whose wing flapping is causing tornadoes on the other side of the world and STOP IT, FFS
And finally, a few I sort of liked but didn't make the other lists:
  • #235 phone cases marketed by how they feel- texture, weight, etc- more than how they look after all you are mostly just looking at the glass screen, but how they feel to your hand whether out or in your pocket is important all the time
  • #413 A Todo App that indicates items have been there too long by overlaying them with subtle cobwebs... you can even swipe them away to indicate progress on the task or just out of frustration
  • #193 conduct a social engineering campaign to change social mores so it's ok to react when people are in the bathroom stall next to you: cheering them on if they make a particularly impressive sound, sympathizing if it sounds like they're having problems, etc
  • #1055 Micro-Time-Zones. All clocks in a timezone are set to the nearest minute based on the current Longitude. No more stupid bumps when you cross certain state borders!!!
Anyway. This is the single piece of company culture I'll most miss from my old place, and I think I have a FIF in there about launching new colonies. I'd really recommend it for any big slack organization.

Oh one bonus I almost missed:
  • #1593 Make years start on March 1. This will have 3 big advantages:
    1. meteorological seasons now line up year - starting with March/April/May spring, June/July/August summer, the school year starts with Sep/Oct/Nov Fall, and then Dec/Jan/Feb Winter 2. September and October now fall on their appropriate Latin numbers (7 and 8)
    3. NFL season is no longer this weird ambiguity springing from regular seasons and playoffs of one "season" being in different years

Sunday, May 17, 2020

node/shell mashup to get stuff done

Once upon a time I used Perl for everything - shell-script type stuff as well as Web CGI.

For a while PHP became a similar go to for everything- it's a little unusual to do shell-script stuff in it, but it's pretty handy.

Now, I've grown some comfortable with JS/ECMAScript for handling arrays and filtering and what not I'd like to use it, but I'm a little lazy about looking up the syntax for the actual file operations - so I treat it as a text manipulation exercise, and go back and forth copy and pasting with a terminal window.

For example, for a big PDF conversion, I did an `ls` in Terminal (sometimes piping it to cat to make sure it was a single column, and then pasted that as a big quote in a .js file:

const raw = `some file.pdf
someo therfile.pdf
yet another_file.pdf`;

then something like

let c = 1;
const origs = raw.split('\n');
for (orig of origs) {
    console.log(`mv 'orig/${orig}' convert/${c}.pdf`);
    c++;
}

running that in node gives me a list of shell operations I can review and tweak if needed, and then copy and paste and run.

It ain't pretty but one off tasks don't have to be :-D

Friday, May 15, 2020

safely shuffling an associative array in php

I'm making game server endpoints in PHP because it's convenient to deploy, but I'm sort of regretting it. I should really get my node mojo working...

Anyway, I thought I had a problem with json encoding / decoding because of PHP's ambiguity of regular arrays and associative arrays, because what I wanted to be a map of keys to values was coming across as a regular array in javascript land. 

After some cursing and debugging, I realized it was because I was calling "shuffle()" on the PHP array. (Leaving aside the meh-ness of hoping to get an order of a javascript map). Anyways, shuffle() doesn't respect string keys, it just drops the keys and treats it as an ordered array. Which sort of makes sense but you think there would be a warning or something...

Anyway, this function lets you shuffle the keys of an associative array (I assume without the shuffle it's usually insertion order?)

function shuffle_assoc_array($orig) {
    $shuffled = array();
    $keys = array_keys($orig);
    shuffle($keys);
    foreach ($keys as $key) {
    $shuffled[$key] = $orig[$key];
    }
    return $shuffled;
}

Eh, good enough.

UPDATE: The above was needed for shuffling a collection of player objects (so as to not bias the judge). The main deck is a regular array... for reference here is some code that regenerates the deck (each card is a number from 1-350) after removing the cards that are already in the players hands:

#do a reshuffle if we have less than ten players per deck... 
$playercount = sizeof($game["players"]);
if(sizeof($game["deck"]) < ($playercount * 10)){
    #all cards but those currently in players' hands
    $cardsinhands = array();
    foreach($game["players"] as $player){
        $cardsinhands = array_merge($cardsinhands,$player["cards"]);
    }
    #remake entire deck, but take out the ones in players hands...
    $deck = array();
    for($i = 1; $i <= $DECKSIZE; $i++){
        array_push($deck,$i);
    }
    $deck = array_values(array_diff( $deck,$cardsinhands ));
    shuffle($deck);
    $game["deck"] = $deck;
}

Wednesday, May 13, 2020

little baby json server for testing react against

I had a few at-home programming tests and one of the better ones started with a simple create-react-app-style bit of boilerplate including clever us of json-server which gives you a baby server that applies REST-ful requests to a json file, all on your file system.

Reminds me a little of getput a tiny node-based server that I made 5 years ago, though I used my preferred method of separate files for the each "table row", which helps make sure any screw ups minimize damage...

react hooks, updating 'initial state' for repeated renders of a modal

Hooks really feel like the right thing for React and for small to medium-sized components they make it easy to bundle all your state right there in what is otherwise a pure functional component

The paradigm for tying in an input field to the state is pretty clean-

First you get the local variable and a way of changing it:
const [name, setName] = useState('');
Then you render an input field like this:
<input value={name} onChange={(e) => setName(e.target.value)} />

I ran into a gotcha with a react-modal component, one that is effectively reused across the life of the parent component. Using something like
const [name, setName] = useState(props.name);
wouldn't reset things so to speak - name was being reset to the initial value from the first render even as the props were updated and the entire component was being re-rendered.

The solution is to combine it with the useEffect hook to get that side effect action going:
Once you've called useState, do something like
useEffect(() => {
   setName(props.name ? props.name : '');
}, [props]);

That let the inputs have the right initial value while still updating the local state as the user typed.

Sunday, May 10, 2020

factor of duh - reading JSON post data

Heh. So I realized one of the reasons I shanked that tech take home, besides the weirdness of JS date transform is I had a one letter type (header not headers) in the JSON fetch code I used. I really should have sucked it up and used jQuery or some such. Talk about premature optimization...

But I stumbled over that when realizing I was behind the curve in my "use PHP for JSON endpoints... to read a JSON post, you can't rely on $_POST, you need something like:
 $POSTJSON = json_decode(file_get_contents('php://input'),true);
which will then be the associative array you might expect...


php file locking for multiuser games

So I'm messing around with making quarantine-friendly version of the like-Cards-Against-Humanity-But-With-Comics game Joking Hazard. I'm thinking each game will just be a single .json file on the server, each client will be a SPA in the browser, the endpoints will be humble PHP scripts that update the file - the clients will poll and get an updated version of the whole game state, and then modify it according to the rules.

It's surprisingly tricky to teach a computer to referee even a medium complexity board or card game (It reminds me I need to go back and update Score-Matic for Dixit, another lovely boardgame, but it's casual-friendly creative/artsy mojo is marred by a fiddly scoring system).

I think I am basically making a state machine: not counting the games red cards (a slight fork) the core game loop is something like

vvv
[create-game(username)] /* put all cards in deck */
vvv
GAME_SIGNUP (add username)  <<< [join-game(username)] /* assign 7 cards from deck */
vvv
[start-game]
vvv
NEW_ROUND <<< next judge assigned, deck-picks-card
v
v
REG_ROUND 
vvv
[judge-picks-card(cardoff, judgepos)
vvv
REG_PLAYERS_PICK <<< [reg-player-pick(cardoff)
vvv
(all players_pick)
vvv
REG_JUDGE_PICK <<< [reg-judge-pick(player)]  /*shows all picks to everyone */
vvv
END_ROUND
vvv
[judge-ends-turn]
vvv

So one challenge will be making sure each client can update the gamestate without stomping on other people's play- PHP supports filelocking, though you have to start using syntax more complicated than good ol' file_put_contents() - since there's a lot of boilerplate, I'm going to use a callbacks to a shared function:

function updateGame($gamename, $function){
    if(! preg_match('/^[A-Z][A-Z][A-Z][A-Z]$/',$gamename)) {
        echo "shenanigans!";
        return;
    }
    $filename = "games/$gamename.json";
    //Open the File Stream
    $handle = fopen($filename,"r+");
    //Lock File, error if unable to lock
    if(flock($handle, LOCK_EX)) {
        $oldguts = fread($handle, filesize($filename)); //get current state
        $newguts = call_user_func($function,$oldguts); //update state
        ftruncate($handle, 0);    //Truncate the file to 0
        rewind($handle);           //Set write pointer to beginning of file
        fwrite($handle, $newguts);    //Write the new Hit Count
        flock($handle, LOCK_UN);    //Unlock File
} else {
    echo "Could not Lock File!";
}
//Close Stream
fclose($handle);    
}
Heh, this is extremely FP! Get a copy of the state, modify it, replace the old state.

So my test code for a call back for this was like:
function addSomething($oldraw){
    $content = json_decode($oldraw,true);
    $content["foo"] = array();
    $content["foo"]["bar"] = "baz2";
    $content["foo"]["bat"] = "bag2";
    return json_encode($content);
}
It feels a little odd to pass in the function as a string, but whatevs.