Thursday, March 30, 2023

programming via ChatGPT

I was laughing at the javascript  code I made in 2005 to show you what day of the week a date fell on for a series of years. That was before jQuery, but I'm not sure I was following best practices then...

I thought I'd rewrite with a better visual display, giving a sense of how the day of the week changes. And I thought I would see if ChatGPT was up for the challenge.

At first I thought I'd just recreate the old UI:

please give me the html and js with a select for month, and a selector for day of month, and an input for starting year and an input for ending year, and a button the selectors are prepopulated with today's date the starting year is 50 years ago and the ending year is 50 years in the future. when you click the button a div is populated with that date for each year in the range and what day of the week the day is for that year

And frankly, ChatGPT pretty much nailed it - I immediately had a better version of my 2005 code. 

But for some reason the inputs were hardcoded in based on right now, when the page is written, so I asked

great work! could you make it so that the starting and ending year fields are populated with 50 years before and 50 years after the date when the page is loaded?

And that was an easy enough fix. So I programmed via describing what I envisioned for the new version:

great work again! could you change it so that "date-container" is actually a table. The top row should be a row of header elements. The firsts header column should say "Year". There should be 7 more columns, each with the three letter version of the day of the week. Then each row beneath, the left column should be the year, and the corresponding column for what day of the week that date is on should be marked with the first initial of that day of the week and the background color should be green
I am truly impressed with the output of that. There were some quirks; the script part got cut off so I had to ask for it to finish (not sure if that's just a quirk of the free version or what), not sure why it went with 100% width for the table or made the "Year" header element left aligned, etc.

I asked for a few more changes, but was getting the "cut off" problem a bit more (despite it electing to start putting the script into a separate file) and decided to make the finishing touches on my own, including highlighting the current year, and automatically filling the table on load...

I even asked it for some aesthetic help when "cyan" wasn't quite what I wanted for the current year highlight:
for the css color "green", what would be the hex code for softer shade of blue that would complement it well?

A softer shade of blue that would complement green could be a pastel or muted blue color, such as a light or medium shade of sky blue. One possible hex code for this color is #87CEEB, which is a pale blue color that could work well with green. However, color choice is subjective and dependent on the specific design and context, so you may want to experiment with different shades of blue to find the one that best complements your specific shade of green.
Yup!

Stephen Wolfram has a pretty good explanation about how ChatGPT works. And it's amazing to think that this is just hyperfancy "markov chains" thinking of what the a likely next word to say might be.  I feel there is true intelligence in embodying those conceptual connections that must be there for it to be making the minor changes requested - like most often it's not ripping off any one other program. 

On the other hand, sometimes the fact that it's not doing proper full mental modeling of things will come up... but, wow. Impressive and alarming! Both in terms of what it can do and what that means for people who have made their living programming, and where it will have some surprising limitations, like how it started hardcoding the start and end years.

Wednesday, March 29, 2023

pure CSS recreating a focus box (that doesn't touch the content)

Sigh. One of those times when maybe if my googling mojo had been better I could have saved myself some time. Here's the codepen I made to learn about the following...

We are messing around with divs including some that might be able to have focus, and I got to wondering what options were for making a focus box, or something similar for hover.

One option is to make a border:
.card.border:hover {
  border:  8px solid blue;
}

the trouble is that might mess up your alignment, cause some shifting, unless it has a border in its non-active mode as well, ala
.card.border {
  border:  8px solid blue;
}

But that might distort things anyway. So it might be safer to use a boxshadow, possibly making sure the fuzz ratio is 0 (or not, if you want a less harsh look)

.card.boxshadow:hover {
 box-shadow: 0 0 0 8px red;
}

 But what if you don't a frame, rather than a border per se? Like one that isn't touching the content, yet doesn't require changes to the content in the layout, or risk moving things around?

I came up with this to give a nice such frame on hover:

.card.before {
  position:relative;
}
.card.before:hover::before {
  border:  4px solid red;
  content:"";
  position: absolute;
  top:-20%;
  bottom:-20%;
  left:-20%;
  right:-20%;
}

Position:relative was a little awkard...

But there is of course a simpler solution - I had missed the simple "outline" property, which when combined with "outline-offset" gave me just the look I was thinking of:

.card.outline:hover{
  outline: 4px solid blue;
  outline-offset:8px;
}

(outline-offset supported in most things but IE)



Monday, March 27, 2023

timezone madness

I live in Boston, MA - I have one coworker in Houston, and then others in Amsterdam and Belgium (same timezone) Recently I've been enjoying Steve Foster's Menu World Time, which can place 2 economical clocks (along with daylight icons) a polite distance from my personal time:

So for the last 2 weeks, USA went to DST but Europe hadn't, so the daily morning standup was a blesséd hour later.

It got me thinking how Menu World Time had to track that kind of shift, and by coincidence a Slack community I'm on John C wrote:

things i've started seeing now that i'm deeper into the horror of open source distro world:
the absolute chaos that is the `tzdata` package during the twice yearly time transitions. For instance, Lebanon appears to have reinstated Daylight Saving Time after transitioning

Lebanon's government reinstates daylight saving time effective midnight on Wednesday-Thursday


What a mess! A lot of assumptions a programmer might make - like "a day has 24 hours" - definitely will be challenged at some point or another. (Shades of the old Y2K problem...)

Wednesday, March 22, 2023

the software engineer is dead! (?) long live the software developer!

On a Slack community I frequent, someone linked The Death of Software Engineering. Here was my response:

  1. I'm trying to think about where my struggle with learning and finding a new deployment paradigm for web apps fits in. Like my flow hasn't changed much since the late 90s, a quarter century - make interactive website/apps by writing scripts that run under apache on a server I pay someone else to admin. Its gone from Perl CGI to PHP, the server is now a private VPS, and the front ends might have more JS flavoring but the core is the same. I do feel there's a small legion of folks more fluent in deployment... though at some point (and this might be what keeps me stuck) it's a business thing. I have fixed costs with my setup in a way I might not if I experimented with more modern approaches
  2. The way that article conflates "OOP" and "Reusable Code" is weird. Maybe I'm channeling the old Object-Oriented Programming Oversold guy - but I don't see why the two conflated. At least in the UI world, the more interesting form of reusable code is the tendency to say "there's an npm module for that!" and taking on lots and lots of libraries even when in some of the cases it might be more expedient to roll a bit more of your own functionality...


Friday, March 17, 2023

typescript, plus and minuses

 I'm trying to make more peace with TypeScript, since that where things seem to be moving. Learning and Using TypeScript as an App Dev and a Library Maintainer was a good piece. Definitely pro-TS, but admitting some of the challenges, and not worth true fanaticism.

From that page:

  • Pros 👍:
    • Documentation: static types tell devs what variables look like quickly - especially valuable when working with unfamiliar code
    • Compile-time errors: common issues like typos or undefined values can be caught immediately, rather than at runtime; compiler prevents passing invalid values
    • Intellisense: type declarations allow IDEs to provide proper autocompletion and type information when writing code
    • Refactoring: can confidently rename / delete / extract code, rather than searching and "hope I found all the uses"
    • Long-term maintainability: better codebase information for future developers who may rotate on and off the project
    • Code Quality: doesn't replace unit tests, but can help minimize errors
    • Library Support: most common 3rd-party libs either ship typings, or community has created their own
  • Cons 👎:
    • Learning Curve: additional syntax and concepts take time to understand, on top of knowing plain JS by itself
    • Time to Write Code: literally more code to write out than just plain JS
    • Difficulties Typing Dynamic JS: can be difficult to come up with good static types for highly dynamic JS behavior
    • Inconsistent/Missing Library Types: not all libs have typings, and quality can vary
    • Compilation Time: TS usage can slow down build times
    • Over-Emphasis on Type Coverage: some TS users spend too much time trying to achieve "100% perfect static type coverage" of an entire codebase, leading to bizarrely complex types

Wednesday, March 15, 2023

safely walking down a tree structure via reduce

 At work we have theme files, so you might have a button or something that will look for its color, say in something like this: 

theme["button"]["large"]["primary"]["backgroundColor"]; 

so if you codify that as 

theme[componentName][size][type].backgroundColor 

it might blow up if part is missing... so you can defensively code it like 

theme?.[componentName]?.[size]?.[type]?.backgroundColor

But I wanted to print out more diagnostic information, not just safely null out... here's the content of the  codepen I came up with, which lets you call something like

getRootNode(theme,componentName,size,type,backgroundColor);

Here's the codepen code:

const getRootNode = (theme,...keys) => {
    const foundNode = keys.reduce(
      (node, key)=>{
        return node ? node[key] : null;
      }, theme);
    if(! foundNode) {
      console.log(`Could not find rootNode for ${keys}`);
      console.log(theme);
    }
    return foundNode;
}

const tree = {
  apple:{
    red:{},
    green:
      { taste: 'tart'}
  },
  banana:{
  },
  pear:{
    
  }
};
console.log('got');
console.log(getRootNode(tree,'apple','green', 'taste'));

It walks down the theme tree, but if there's no content anywhere along the line it calmly complains and returns null.

FOLLOWUP: I'm having some trouble selling my coworkers on this, they like the elegance/transparency of the chain syntax vs an arbitrary helper function. They also questioned the efficiency, so I wrote up a stopwatch function:

console.time();
for (let i = 0; i < 100000; i++) {
  const foo = getNodeInTheme(props.theme,"Badge",props.variant,props.size,props.color);
}
console.timeEnd();
console.time();
for (let i = 0; i < 100000; i++) {
  const bar = props.theme.Badge![props.variant!][props.size!][props.color!]
}
console.timeEnd();

Results: 

default: 18.383056640625 ms default: 1.559814453125 ms

And yeah, technically it's like 10 times slower, but 10,000 calls is still only 20 milliseconds, which is 0.02 seconds.  And that's for a LOT of calls.

Heh. Reminds me of BASIC that lacked a "SLEEP" command so you'd write "do-nothing" FOR...NEXT loops. And they weren't superfast!




javascripts sans build systems

Great (and by great I mean good and agrees with my biases) article Writing Javascript without a build system - Julia Evans writes

I make a lot of small simple websites, I have approximately 0 maintenance energy for any of them, and I change them very infrequently.

My goal is that if I have a site that I made 3 or 5 years ago, I’d like to be able to, in 20 minutes:

  • get the source from github on a new computer
  • make some changes
  • put it on the internet

But my experience with build systems (not just Javascript build systems!), is that if you have a 5-year-old site, often it’s a huge pain to get the site built again.

And because most of my websites are pretty small, the advantage of using a build system is pretty small – I don’t really need Typescript or JSX. I can just have one 400-line script.js file and call it a day.

That meets my workflow (though "ashamedly" I often skip the git step and just adjust things on the server).

Someone one said (and I wish I could find the quote, this is a very rough paraphrase) that the Internet just has one big trick, getting information onto and off of someone else's server, and you really can do that with conceptually lightweight technologies! 

(Also see her list of things that used to be hard and are now easy - thank heavens for Let's Encrypt)    

---

Other unlrelated JS articles I'm catching up on:

use maps moreand objects less seems like a good idea though - like with typescript - I think many coders don't get how important syntactic sugar can be.

A personal history with React is interesting...  thinking about how Contexts now solve the props drilling problem.

JS/TS changes of the last 3 years


Tuesday, March 14, 2023

tweaking vs code and some plugins I like

 So first, a disclaimer: I have no idea who or what vets VS Code plugins-  like it feels like the wild west a bit, and you have to have the same kind of trust you have for npm packages...

(Tangent to the disclaimer... does anyone else pronounce it "versus code"? No? Just me? Must be the early Nintendo influence)

Anyway, "Error Lens" seems like a nicer form of error display (and honestly it's the errors that make TypeScript such a slog... allegedly it makes up for the time spent early on in the long run, but I have my doubts.)

Like here is the inline warning: 


 GitLens seems to be a popular way of doing "git blame" and the like.

"Peacock" lets you "subtly" change the color of your worksplace - like mostly the frame, so you don't have to adjust your eyes to new colors for code.

Finally, here's a guide to change the VS code app icon. Frankly, that weird "fish in a tank" icon, with its default mid-blue on white, looks too much like half a dozen other icons, and the lack of connection of the icon to"V" or "S" or "Code" is just bizarre, and was providing my brain with no hooks for it. 

(The VS Code icon - here's its history, which only touches on the "fish" look that has (allegedly) offended at least one person as Christian imagery...)

For what it's worth I think I like the icon shown on the left here: I use a lighter background so I don't want the black icon, and some how googly eyes (making it look a bit like Clippy I guess?) provide the mental hook I was craving to quickly find the icon on the dock or cmd-tab list.


Thursday, March 9, 2023

the propped up web

A friend pointed out this mastodon post: https://jawns.club/@lou/109973651127997348

 Which talks about a Denis Pushkarev, maintainer of core-js, trying to make things work financially

He makes a great case that core-js (used to transpile code and make sure even older browsers can run code written in the new paradigms) is used ALL OVER the place, in much the same way jQuery was back in the day.

The obvious model is this famous xkcd comic:

It reminds me of "You are not buying from a supplier, you are a raccoon digging through dumpsters for free code." So many place I've worked - everywhere that's not a Microsoft house, really - you just start using stuff because it's cool and useful, everyone else is using it, and you don't have to setup budget approval.  (And then coders start getting massively entitled. "Software should be free!" and they mean "as in beer" not just as in speech)

Also for UI folks - the tendency to just have these mammoth piles of code npm'd in for every little task - it's a lot of trust! Or even the plethora of VS Code plugins. They tend to have a lot of access to your filesystem... I'm reminded of Dietzler's Law, how all these abstractions allow things to flow so much more easily, but you can still caught if you need to change something the abstraction doesn't allow for.

I've definitely grown a preference for systems where trust is just a few organizations. On my OS, I try to minimize clever plugins that I would miss if sitting down to a "fresh" install (though I do like SizeUp and HyperSwitch) - for my light server stuff, I like PHP's monolithic set of "here are all the fiddly functions you probably need" vs NPM's giant library... and for my own projects I still gravitate to not needing a build system and just trusting what ECMAScript the browser supplies...

Wednesday, March 8, 2023

iphone tip on alarms

 iPhone tip: if you have a giant pile of old one time use alarms set up on an iPhone it's easier to ask Siri to "delete all my alarms" than remove them one by one in the UI...

Sunday, March 5, 2023

trivial php directory of images to image gallery

 I feel like I must have written this already half a dozen times, but I couldn't find quite the equivalent posted here: a trivial script to dump every file that looks like an image based on extension into an img tag, with a link/filename before it.


<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {
    font-family: sans-serif;    
    margin: 80px;
    font-size:24px;
}
img {
 width: 100%;   
}

</style>
</head>
<body>

<? $files = array_values(array_diff(scandir('.'), array('.', '..')));

$imageendings = array(".jpg",".jpeg",".png",".gif",".webp", ".svg");
foreach ($files as $file) {
        $lowercaseFile = strtolower($file);
       if(endsWithOneOf($lowercaseFile,$imageendings)) {
            print "<p>";
            print "<a href='$file'>$file</a><br>";
            print "<img src='$file'>";
            print "</p>";
       } 
}
function endsWithOneOf($haystack, $needles){
    foreach($needles as $needle) {
        if(endsWith($haystack, $needle)) return true;   
    }
    return false;
}

function endsWith($haystack, $needle) {
    $length = strlen($needle);
    return $length === 0 || 
    (substr($haystack, -$length) === $needle);
}


?>
</body>
</html>

Friday, March 3, 2023

programmers and musicians

Heh, just had a thought that seems so blatantly obvious in retrospect.  

Like I'd long heard of the overlap between programmers and musicians.

And with programmers, there are coders who are very into precision and isolation: unit tests and formal typing. And there are other coders who are more interested in context and are comfortable with duck-typing.

And with musicians, there are many players who love the precision, and aren't comfortable without sheet music in front of them. And there are group musicians who, while usually following forms (not talking jam bands, more like street bands) are comfortable doing more by ear, and emphasize interaction.

It's probably not a coincidence that I'm in the latter category of both, and I think the spectrums tend to run parallel. 

As always, the best answers are somewhere between, but probably more on one side than the other.

Thursday, March 2, 2023

debugger beware! objects in console.log() are dynamic

TL/DR: if you blast an object to console.log(), like an array or map, that is likely to be a "live" display of the value of the array, not what was present at the moment you called console.log. One work around is to use console.log(JSON.stringify(thingy, null, ' '));

One of the silver linings of being an old gray beard is this kind of problem just made me stumble for a minute, but then the "wait-a-minute" factor kicked in and I came up with a workaround...

So at work I'm doing a project that's a wrapper for google chart - there was some code here that read values from a table, and I console.log() the results.

this.sourceData = this.parseData(sourceTable,calculateAsPercentage);
console.log(this.sourceData);
let data = google.visualization.arrayToDataTable(this.sourceData);

The thing is when I did some further log() of what was becoming the return value of parseData() inside that function, it looked like the "header" data was being generated and pushed onto the array, but then it disappeared. 

But then I figured out something in Google chart (or maybe processing we do, I dunno) was consuming the first entry with the header data, probably array.pop().) But console.log was always showing me the final version, not the snapshot of what it was at the moment the function was called.

So I realized JSON.stringify() (with the usual (thing, null, ' ') to format it properly ... how many times have I typed that null, ' ' ...) would give me the snapshot in time" I was actually thinking of:

this.sourceData = this.parseData(sourceTable,calculateAsPercentage);
console.log(JSON.stringify(this.sourceData, null,' '));
let data = google.visualization.arrayToDataTable(this.sourceData);

BONUS: remember if you are dumping a regular variable to console and want to see it labeled with its name you can stuff it in a map-like object, just two characters more:
console.log({variableName});