Friday, April 19, 2019

use your words, gadgets!

For a few year I've been partial to BeatsX headphones - honestly all wireless audio solutions lack gravitas - the Borg look of oldschool Bluetooth handsfree things, the double Uhura of Airpods - even over-the-ear big headphones look like earmuffs, or maybe Lobot from Empire Strikes Back. The "librarian eyeglass holder strap" look of BeatsX weren't so bad by comparison, and I liked how they use the same Apple W1 chip as Airpods - but you can take one out for a bit without having to hold it or put it away or have your music stop.

But I'd been through too many pairs - lost one, misplaced another, and then my main ones started losing sound on one side. (The build-quality / feel of them is great, but the durability just so-so.) So I went to Best Buy and discovered cheapish (~$30) earbuds of decent quality are now a thing! I bought a pair of Sony's WI-C300. This review agrees the sound quality is pretty decent, which is all I need - I tend to use other things for music, and have these for walking around to podcasts, and despite being a musician I'm not much of an audiophile.

Overall they aren't as comfortable as the BeatsX - the wire is a bit short, and that wire's skinniness is much less appealing than the Beats ribbon, and the buds don't have magnets (in theory useful to complete and secure the "necklace" feel when not in use, in practice it's just pleasing to have magnets to play with) but in one simple way it's much more comfortable - when you power them up, a chime plays and you hear a voice say "power on". As the things connect to your phone, another chime plays and it says "bluetooth connected".

That is SO much better than the little musical blurbles BeatsX play. There's kind of one that goes up to say "on" or something, and another to say "powering down", and maybe some chirp when it connected to the phone but I was always having to yank the control bit around to look and see if the little light on it was shining or not, because it was pretty ambiguous. (This is not helped on modern iPhones, where they don't have display area to spare to always show you if you're in headphones mode or not.)

Good old Bluetooth plus a voice explaining the status is way better than anything I thought I was getting from Apple's W1 chip plus nearly meaningless musical ditties! I think there's a simple UX takeaway here - just use words! (Ideally with an option to change languages, but I'd rather have a human language I didn't know than try to decode the musical language of Beats designers.)


Sunday, April 14, 2019

really old web design

I was looking at the late-90s rendition of my website, back when they were called "homepages" (Hooray for the Internet Archive Wayback machine! That site,along with the original versions of Google, Youtube, and Shazam, are things where the magnitude of what they were doing just flabbergasted me and still impresses.)

Anyway, I had to pull up the devtools inspector, because it wasn't clear at a glance how I achieved the layout of my photos page - it has a kind of pleasing irregularity to it. I knew it was tables, of course - turns out it's a rough two-column layout, with on-again-off-again use of the img align tag - I may have just been playing around with how to sort-of-align a set with portrait, landscape, and square cropped photos.

I'm thinking of this time in part because of the 25th anniversary of Tufts sQ!, my college acapella group. And I remembered that my early web designer self was strongly influenced by my camrade Erica's sQ Official Homepage - both the "columns but not rows design" and the use of transparent-background photo icons (in particular, the airplane on that page) were strong influences on my early sites.

Sometimes when I'm looking at my old raw HTML I'm delighted to see it all in caps - a habit I believe I got from Perl and other technical documentation at the time. )It's not clear if I had outgrown the habit when I designed that page)  These days it's unacceptably uncool (probably even deprecated, since xhtml-stuff was in all lower case, I think by mandate) - on par with using tables for simple flexible layouts - but honestly, in an age before fancy highlight editors, it made it very easy to discern what was content and what was markup...

Wednesday, April 10, 2019

the underbrush

As I go through and groom old blog entries and see just how many broken links predominate, how the old geek vision that "urls can be forever" is almost completely unrealized, but sometimes I can use a search engine to find a replacement for a yanked Youtube video, I realize that one purpose of Google is weeding out the underbrush of fallen sites, if search wasn't a constantly renewed process and we relied on old archives we'd be choked in a forest of dead wood.

Tuesday, April 9, 2019

UI hall of shame: Samsung NU8000 onscreen keyboard

Last December I bought myself a Christmas gift, a lovely 65" Samsung NU8000 television. (I miss my old projector, but given my space, this is the smallest size that still feels like a billboard, and Wirecutter likes the low-lag mode of these for videogames)

Overall its UI is pretty grand - much better than the older Samsung my mom has - all the apps are easy to get to and most are of good quality, and the shortcuts from the main screen generally make sense (and I'm not TOO worried about the data collection I'm sure this beast is running on me.) But the onscreen keyboard they use for some of their setup/config is THE #&$#(*$@& WORST, especially for entering a password. 

It's kind of a standard "use the cursor up/down/left/right, select the letters via an onscreen keyboard" (laid out like a normal typing keyboard) that video game console owners have put up with for a decade BUT -- 8 letters or so into typing a minium-length-8-character password, say -- once you select a letter, the space immediately to the left of the character you just typed becomes a checkbox, a short cut to "I'm all done".... so if you're bopping along, trying to efficiently enter your password, and it starts with "ireallyreally" in it... you enter the r of second really, that's the eighth character - meaning you've meant the minimal wifi password length, so then when you go to move the cursor to the left, you're not over the "e", you're about to select the "I'm all done" checkbox.

And you hit the center of the button thinking you're on the e, and the thing thinks you're done, and takes away the screen to try out your (of course incomplete) password, and you have no idea what is going on, but you're on a totally different screen entirely, and you don't know what the hell happened, so then maybe you repeat this dance two or three times, because it's such #$#(*@ STUPID HALF-BAKED DUMB@#$#@ INCOMPETENCE in trying to make a "helpful" - yet fundamentally unpredictable -User Interface

A core of "Tao of Programming" is the "Law of Least Astonishment", i.e. a program should always do that which surprises the user least - and this is a FLAGRANT violation of that very simple principle.

Of course, even once the user has overcome the surprise of a barely-useful shortcut showing up where there wasn't one before, to REMOVE the "helpful" checkbox you simply go select another letter and the checkbox goes away- but it comes back, so for the rest of the text entry if the next letter you wish to type happens to be to the left of the one you just entered, you have to wiggle the cursor around to shake off the dang uselessly premature checkbox.

Programmers. They need to learn the difference between "can" and "should"

(Mercifully, the searches on the various apps like Netflix and Amazon Prime implement their own keyboards, free of this half-bakerd crap.)

Monday, April 8, 2019

ecmascript 6 is fire. i mean, it should be burned. (safely destructure nested js objects)

ECMAscript 6 has a lot of features. One of them is Destructuring Assignment with Deep Matching which you can combine with Shorthand Notation... so you can do something like

var { foo, bar: { baz} } = someCall();
which is the same as 
var tmp = someCall();
var foo = tmp.foo;
var baz = tmp.bar.baz;
 
One interesting note when you use that kind of destructuring is that the intermediate variables aren't defined - e.g. you don't get a "bar" in this case - "bar" is just a signpost to the structure
 
The problem is, things are very unhappy if "bar" is undefined.

I'm not sure if there's any cool syntax that might say "please destructure this, and just give me back an undefined for nodes I am implying should exists even if they having missing parent" (Because "is not defined" errors are so much harsher than mere "undefined" variables despite the superficial similarity.) 

So the boring way is to break the destructuring into steps and use object matching default values:
var {foo, bar = {}} = someCall();
var {baz} = bar;

As I ask about this at work, it's interesting how many devs I hear express some dislike for all the new synactic hotness. And I agree, things (especially curly braces) are weirdly context dependent and then there are tricks like destructuring with renaming
var { foo : bar } = someCall(); 
//same as var bar = someCall()['foo'];
that feel like a weird mix up of left operand and right operands - as if the meaning of the : has done a 180 relative to a "normal" object creation (e.g. var foo = { bar : 123 })

Saturday, April 6, 2019

eric was right - sometimes declarative rendering is better

I had a great tech manager Eric last year. He shared some of my inexperience with React and Redux and the concepts that underlie them, but he attacked the learning curve with gusto.

He told me how he made a learning/side project for a trello-like system, and for grins he implemented it with React (or maybe one of those Build Your Own Baby React systems) and then with more traditional methods. And he said, the declarative rendering system was miles ahead in speed and ease of use.

I didn't believe him.

Woe is me!

For my Porchfests side project, I needed to redo the Hourtron - as you can see with the (fairly simplistic but clean) 2015 prototype for it, the idea is you have a bunch of rows representing porches, and columns that represent performance times, and then you can drag and drop bands unto performance times / locations.

So for the first real implementation (2015-2018), I had it save all the performances on the page (aka "gigs") at once as a giant blob of JSON. I wanted to better support one band having multiple gigs, as well as be a bit more robust and be able to save each gig as it was set - I did a from-scratch rewrite (also figuring I was too pure of heart for JQuery, which was ok-ish for the drag and drop but was weirdly infeasible for the Ajax POST)

It was harder than it looked. In particular, these DOM blocks I had sometimes representing an unplaced band, sometimes showing a band at its gig - the IDs for gigs were server generated, and linking that gig id with the block in such a way that moving the gig time or place didn't generate a duplicate gig, was way tougher than I expected, and I realized the declarative method of saying "this bit of memory represents state, and the DOM can just reflect that as quickly as possible would have been great"... also the jQuery-free version of drag and drop reminded me that the "ghost" I use to show where a band will be dropped could still be handled as plain old javascript, so kind of a hybrid where the main block schedule was React-or-similar but the drag and drop was separate would have been fine.

Ah well, live and learn. I need to rethink my side project setup... I still like renting a cheap VPS and putting everything there, but I need to build up tools so that I can use tech that plays better with some kind of build system, rather than being spoiled by the "I save the raw file, reload, and run". Stuff with watchers and what not can get that feel pretty speedily, tbh, and then I have more options about the babel-ization and what not I use.

Friday, April 5, 2019

you may need jquery after all

Grrrr. Just blew like an hour on a pressing project, thinking I was too pure for jQuery--
You Might Not Need JQuery claims that
$.ajax({
  type: 'POST',
  url: '/my/url',
  data: data
});

can be replaced with

var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send(data);

On firefox and chrome, this does not seem to be the case

My test script was
<?
$res = array();
$res['msg'] = $_REQUEST['bandid'];
print_r($_REQUEST);
print json_encode($res);
?>
and looking at the network panel, the jQuery version does what I expect (using the print_r to mirror what I passed in (i.e. the 'data' parameter in both cases is a simple JS object) and the XMLHttpRequest version seems to send nothing. Probably missing something "obvious" but too tired and stressed to deal with it now.