Sunday, March 03, 2024
Thursday, February 01, 2024
Java date time literal
The simplest way to do a modern datetime literal in java is with Instant, e.g.:
Instant.parse("2024-01-28T23:00:00Z")
And has useful methods for getting its low level equivalent:
Instant.parse("2024-01-28T23:00:00Z").toEpochMilli()
And which can easily be converted to a LocalDateTime with:
LocalDateTime.ofInstant(Instant.parse("2024-01-28T23:00:00Z"), ZoneId.systemDefault())
Sunday, November 12, 2023
City college (CCNY) undergraduate computer science sequences
The sequences are important to understand for CCNY CS students, because they need to be taken strictly in order across several semesters. Without good planning, it's easy to need more than four years to complete the degree. It's also very easy to get closed out of a full class in any given semester.
The most important sequence is:
- CSc 10300 Intro to Computing for Majors
- CSc 10400 Discrete Math Structures (this also needs Calculus I, so that should be taken ASAP)
- CSc 21200 Data Structures
- CSc 22000 Algorithms
- Engl 11000 Freshman Composition
- Engl 21007 Writing for Engineering
- CSc 22100 Software Design Lab
- Math 20100 Calculus I
- Math 21200 Calculus II
- Math 21300 Calculus III, Math 34600 Linear Algebra, CSc 21700 Prob & Statistics
- CSc 30100 Numerical Issues in Scientific Prog
- CSc 30400 Theoretical Computer Sci
- CSc 33200 Operating Systems
- CSc 32200 Software Engineering
- CSc 21100 Fund. of Computer Systems
- CSc 34200 Computer Organization & CSc 34300 Computer Organ. Lab
Friday, August 25, 2023
Simple reactive language idea
Here's my idea for a high level programming language in case I never get around to implementing...
Start with a really simple subset of a boring procedural language. I like python syntax, but it's not important.
Support reactive variables, aka cells aka FRP signals. Forbid reassigning globals except using a repl. Make that statically checkable.
a = 1
b = a + 2
//changing a to 4 automatically changes b from 3 to 6
Make functions use Mutable Value Semantics, for all parameters and return values. That is, have all values be semantically "pass by value", not just primitive values. So changing things inside a function has no affect on things outside of the function except for what the function explicitly returns. Make it relatively fast using persistent data structures.
Support working with individual members of a collection reactively. So, in addition to:
fuSprite = mouse.position + 2
//for a single sprite which follows the mousealso support:
a barSprite = mouse.position + 2 on mouse.click
//multiple stationary sprites, with a new one created every time the mouse is clicked(I haven't thought too much about the best syntax here. The word "a" or "an" in beginning is cute and english-y, but may be too much. I also don't know whether the trigger ("on mouse.click") should be before or after the expression. Also please forgive my handwavy introduction of events.)
Though the last pair of examples are GUI oriented, I'm dreaming of this language for general purpose use, including traditional server side code. I can't help thinking this is the "holy grail", a major step towards liberating programming from the von Neumann style. It's not an especially original idea, just a rejiggering of push-pull FRP for all non-local mutation, but I can't see why it wouldn't make programming dramatically simpler.
The major advantages are:
- Referential transparency - like in haskell but simpler
- Enhanced "view source" - anything you see on a computer, you could click and find out why, following the declarative trail all the way back to the first triggering events from outside
- True separation of concerns - this is only a hunch so far! I'm hoping that the more declarative approach could allow orthogonal implementation of genuinely useful features, like persistence or distributed consistency.
Tuesday, July 04, 2023
Trunk based dev and merging
The unfortunate reality is that new code contains new bugs. Unless you want to stop all feature development while a release candidate is being tested and fixed, you're going to need a mechanism for selectively including code in releases.
There are two different ways to do this: trunk based development and release branch merging.
If you can get away with having only a single version of your software running live at a time, you can use trunk based development very simply: Have only a single release branch live at any time. Always add changes to trunk, and never directly into the release branch. Cherry pick bug fixes from trunk to the release branch. Manually test bug fixes in the release branch.
If you need to support different groups of users using different versions at the same time, trunk based development gets a little trickier. For example, Stakeholder A desperately want a new feature, but delivering that feature risks destabilizing the the product for Stakeholder B. You'll need multiple release branches that include different sets of changes. There are only two known solutions: feature toggles and release branch merging.
Feature toggles involve guarding new code with a runtime flag, such that the risky new code can be disabled for stakeholders that don't care about it. One additional advantage of feature toggles is that, if the new code ends up having a major bug which is discovered in production, it can even be easily disabled for everyone. The two big disadvantages are: 1) feature toggles open up a brand new category of technical debt, and 2) you need to have whole new mechanisms for managing them. For example, how do features get toggled based on testing? How do you handle feature combinations and interactions?
The alternative is to leverage the merge support in modern revision control systems like git. Instead of trunk based development, fix bugs directly against the release branch. Then always merge all changes from more stable branches to less stable branches, from release branch to mainline. There is a bit written about this under the name "gitflow", but the approach existed before gitflow, and gitflow really describes a larger standard. Some things are not complicated: if you're doing code reviews, you should be using "topic" branches. Many web pages just confuse matters in their comparisons of gitflow, github flow, gitlab flow, and trunk based development. The real question is: would you prefer to use feature toggles to enable trunk based development, or would you prefer to merge from release branches?
Release branch merging is not a panacea, and it can be a pain. Arguably it is simpler than feature toggles though; it is trivial to understand whether master is caught up with all of the bug fixes from release branches. The installed version number tells you exactly which code is in your system, and you easily compare it with other versions of the code that were or will be running at any other time.
Quotes:
Raymond Chen, long time Microsoft developer: “Cherry-picking is a common operation in git, and it’s not a good idea. Sometimes it’s a neutral idea, but I haven’t yet found a case where it’s actually good.”
Google according to Winter, Manshreck, and Wright: “A key to reliable continuous releases is to make sure engineers "flag guard" all changes.” (emphasis mine)
Wednesday, March 22, 2023
Friday, February 03, 2023
Messaging notifications
- make the UI more clear, perhaps automatically labeling each thread with an automatically generated subject
- make it possible to change the thread that a message is in, after the message was already "sent"
- changing the thread is too late for sounds triggered by notifications, but they could update the "keep up-to-date" style interface of feature 2 above.
- if notifications are actually working like they should, people will be more motivated to get the thread right in order to get the notification right.
Thursday, December 15, 2022
Nostr
Nostr is a really lovely development in social networking. It's certainly not ready for people who don't have dedicated followings, but it's almost already a good additional place to publish. It's simple! I'm jealous; I was trying to come up with something like this.
Otherwise, I just want to mention a couple of points regarding "incentives" to run a nostr server (which they call a "relay", and for which the mandatory functionality is quite simple). It's kind of funny that in the README Fiatjaf doesn't really answer the question about why you might want to run a server. Here's a few possibilities, besides just thinking it's cool:
- the obvious incentive: you want to give particular people a platform.
- even with just the mandatory functionality, users can query for all the posts related to a post. Servers can promote some of those posts over others.
- only servers can see the level of interest for different authors, topics, etc, by logging the requests that they get.
Monday, November 21, 2022
Amazon front page search
Amazon should set the focus to the search field on their front page, so that you can immediately start typing when you hit the page.
I'll bet it's because nobody could demonstrate that it would make them more money.
Monday, September 05, 2022
Crowdsourcing programming language
With the embarrassment of riches in the low level programming language space (Zig, Jai, Odin, Beef, V, Jakt, Val, Rust?), I was thinking about what the next high level programming language might look like...
It's got to be open source and have super support for the web. IMHO it should support regular programming as well as interactive (i.e. shell) use. It ought to be fully reactive!
Simply, "reactivity" makes programming more like spreadsheets. Though the flapjax project did this with javascript many years ago, all the hot new javascript frameworks are finally adopting this kind of approach (svelte, solidjs, vue). It's good for GUIs, and it could be great for programming in the general. Imagine View Source for all of programming!
As long as we're talking "high level", it could have all sorts of cool features thrown in, like transparent persistence, CALM consistency support, easily querying JSON and other formats. Implementing features takes a lot of engineering effort however. That's a big lesson from Zig's increasing success: engineering matters a lot. Tangentially, here're a few links in praise of Zig engineering:
- It compiles c better than traditional c compilers do, for a while now actually.
- It's easier to debug than c++, in nerdy ways.
- It will be able to do fancy fast compilation, by virtue of careful use of its complexity budget. If you're curious, see here.
Querying JSON
The state of the art in querying JSON outside of a full program:
- simple, specified, multipy-implemented: jsonpath
- more powerful: jq
- more interactive: fx
- for UNIX afficionados: gron
- which might make you ask how to grep across lines
Friday, April 29, 2022
Lisp Disappointment
Once, I was really excited about "code as data". If you enjoy the power of code, you should love code that works on code, right?
Problem is, almost anything interesting about code working on code isn't about syntax.
Compilers have been optimizing code forever, and there's no indication that it's any easier to optimize lisp.
Static types help to reason about, navigate, and refactor code, and those are not part of traditional lisp. The same goes for referential transparency.
And bidirectional programming provides other amenities that having nothing to do with lisp.
Thursday, April 28, 2022
Peer to peer social
Of the communication modes discussed in the previous post, "perusal" is the one that needs the most love right now. We're talking Twitter territory, so this post is timely. Remember "perusal" refers to communication which is both asynchronous and involves broadcasting to many people.
The wonderful thing about Twitter is that, when you reada something interesting anywhere, you can speak directly to the author about it on Twitter, and they'll respond, as often as not. This feature springs from the famous social media "network effect"; Twitter is where all the authors hang out now, so it's where everyone goes to talk to authors, creating a self-reinforcing cycle. People say that only a paradigm shift can beat an existing network. If new competitors try to compete on features, they'll get squashed by the existing network, which can relatively easily copy those features.
So let's talk about what peer to peer social might look like. That is, a system for perusal-type communication which doesn't depend on any central authority. People agree this is a hard problem. So we'll talk about it in avowedly handwavy manner.
1) It should be http based. Among other advantages, this will help with ramp up and network effects: even before our system takes over the world, its posts will be no worse than blog entries.
2) Its scope should include direct messaging, partly because that'd be nice to have too, but mostly because we can use the relationships between people to bootstrap some kind of trust graph. Much of the social graph is already available in people's phone's Contacts app.
3) It'll have two different roles in the system, which I'll uncreatively refer to as "people" and "servers"b. Both roles have public-private key pairs. People's apps record each others' public keys, so the system is local first that way. I don't need Facebook to manage my electronic contact for my brother. His app signs his posts, so any server can send them to me, and I'll know that they're really from him.c
Even for perusal, I don't really need Facebook fanciness to highly rank posts from my brother, or from my favorite musician. It's now easy to communicate with anybody in the world; the hard part is preventing enough of that communication to keep it useful.
4) So servers differentiate by recommending new posts that people want to read, that is, posts from strangers. Continuing the spirit of search engine and social media companies, there's a tension between what I want to read, and what other people want me to read. "Advertising" is when intermediaries get paid to sacrifice the former for the latter. If people know the public keys of all the people that they're already interested in, and those keys are used to sign all posts, there's no longer any robust way to insert advertising into those posts. The natural place for advertising then becomes the feed of new recommended posts.
5) People's apps should employ multiple servers. People can rate posts, and those ratings will be automatically shared and used to pick the best servers, forming a kind of market place for servers. Depending on how expensive it is to run a server, the market will efficiently price the fraction of the recommendations that will be advertising. Now we're really getting handwavy. Who says this can work? Well, we can talk about it more; first let's finish the sketch. :)
6) We also need to support a way for ratings to flow from readers to publishers. Partly because this is something that publishers like, but it needs to be supported natively so that servers can demonstrate to advertisers how effective they are. It's the trust graph which defeats sybil attacks. Attackers can create as many fake people as they like, and those won't matter because the rest of the world doesn't connect to them.
7) So everybody's rating everything, does that mean that all ratings have to be copied everywhere? Distributed consensus and trust algorithms appear to assume so. And of course, there's blockchain. But I hope we can do better. We don't need any of this to be precise, we just need it to more expensive for spammers to game the system than it would be for them to simply run a competing server. Therefore, we ought to have a protocol that enables participants to exchange ratings in a sparse, just in time fashion. We're talking about a kind of guerilla PageRank. Unfortunately, the term "gossip protocol" is already taken, so once we actually figure out his protocol, we'll need a new catchy term for it.
OK, that's about enough speculation for now. There are some major ideas that'll I'd like to talk about in the future: How do we support decentralized topics or groups? How can multiple independent parties evolve the software and the protocol? And of course, how would all of this effort make a system much better than existing centralized networks?
a When I say "read", I mean "read, listen to, watch, or otherwise experience".↩
b Once I say "server", many readers will immediately think "oh, that's federated, not peer to peer". Well I'm still hoping this'll be a bit more dynamic than your typical federated system like email. We'll see :).↩
c There are a lot of details to get right here, for example post-compromise security ↩
Thursday, April 14, 2022
Communication modes
Nobody answers the phone anymore. 😁
Seriously, nowadays there are three distinct modes of communication:
Synchronous | One to one | |
Waiting for your call | yes | yes |
Direct messaging | no | yes |
Perusal | no | no |
"Waiting for your call" means picking up or responding immediately. Nowadays it's restricted to: enjoying real conversations, getting to know somebody, when you're paid to be available, and failures of direct messaging.
"Direct messaging" means that somebody sent a message just to you. I believe the etiquette is that these deserve some response within a day or so, lacking any other clear time constraints. Assuming you're not famous.
Of course asynchronous messaging tools can also be used for synchronous communication. The three dots that indicate the other part is "typing" help distinguish a little.
What we want for "perusal" is a ranked list of items that we can check as infrequently as we want. The things that we are most likely to want should be at the top. Timeliness could certainly be a factor.
From the technical point of view, we want this stuff to be more standardized and unified. For example, it'd be nice to initiate a message to somebody from their Contact in my phone, via Whatsapp because that's their favorite, without me having to remember it. It'd also be nice to have a conversation with two friends at the same time without having to think about compatibility.
We also want our communication to be local first software, and that's what the next post is about.
Monday, March 21, 2022
Zig open interfaces issues
Friday, February 25, 2022
SBE Repeating Group Gotchas
- There is very little documentation in general, and for repeating groups it's incomplete. A big omission: you must always explicitly decode every member of every repeating group, in the same order as they are defined in your schema. If you do not do this, your results could be mysteriously corrupted. Alternatively, you could explicitly "skip" the ones you are not interested in, with the relatively new sbeSkip() call. E.g.
weWantSerialNumber(carDecoder.serialNumber());
weWantModelYear(carDecoder.modelYear());
FuelFiguresDecoder fuelFigures = fuelFigures(); //we don't want fuelfiguresif (fuelFigures.count() > 0) //but if it was encoded...
{ //we must iterate over it anyway
while (fuelFigures.hasNext())
{
fuelFigures.next();
fuelFigures.sbeSkip();
}
}
PerformanceFiguresDecoder performanceFigures = performanceFigures();
if (performanceFigures.count() > 0)
{
while (performanceFigures.hasNext())
{
performanceFigures.next();
weWantOctaneRating(performanceFigures.octaneRating());
performanceFigures.sbeSkip(); //actually needed in the sample} //because there's a nested repeating group!
}
- If you're working with code that does not use repeating groups, and you add one, lots of things might break unexpectedly. Because wrapping a decoder with an incorrect blockLength will mostly work if you don't need to decode repeating groups or variable length data fields. You need to use the blockLength on a header message, which in turn needs to be the BLOCK_LENGTH of the encoder. This excludes the length of the repeating groups. On the bright side, nowadays there are wrapAndApplyHeader() convenience methods on both the encoder and decoder objects.
- If you want to read repeating groups from the same decoder more than once, you need to call sbeRewind().
- There's currently a bug in which toString can break repeating groups
Thursday, February 17, 2022
Bookmarks and Full Text Search
They suck because they don't actually work for their primary use cases:
1. where did I read about that cool thing X?
2. where was that cool article about Y that I didn't have to time to read, but would like to read now?
Heck, at some point I found it easier to google for pages instead of trying to find them in my bookmarks.
Other use cases should be handled slightly differently:3. "Bookmarks Bar", "Pin a tab", and "Save a shortcut" features are all useful for commonly-used pages or web apps.
4. "Manage Search Engines" feature is useful for sites that you want to search often.
4. I'll bet Chrome soon adds support for saving tab groups, which will be useful for gathering lots of pages for a particular project, e.g. a bibliography.
Practically speaking, labels and categorization are annoying to add, and don't really help find things later. The titles that maintainers give to web pages are also often unhelpful for retrieval.
The solution is automatic full text search of all bookmarked pages.
Worldbrain's Memex supports full text search of bookmarks well, and for free. I have mixed feelings about it. On the one hand, this feature is implemented by an open source plugin, and the maintainers support local first software. On the other hand, they have a much bigger vision, and it's unclear how much they want to support the free part of it. It currently sports a non-dismissible reddish prompt to register for the cloud support.
Friday, January 28, 2022
iPhone Shul Shush
Now it's finally possible to silence iPhones in shul (or church or whatever)!
- Settings / Focus / Do Not Disturb / Add Schedule or Automation / Location
- enter something to identify your shul, e.g. part of the name
- select the right one
- touch Done
Monday, January 03, 2022
Vim plugin idea
When working with verbose logs, you want to suppress uninteresting lines.
So, wouldn't it be cool if you could select two lines, and vim would hide all lines that are similar to them.
1237 boring is blah, all good
1238 boring is foo, all good
1238 WARNING
1240 boring is blah, again
When the user selects the first two lines above, vim would hide lines matching the pattern \d+ boring is \w+, all good.
It'd need the ability to unhide the next or previous line.
We could also get fancy, and support generalizing previous patterns. In the example above, you could later choose the fourth line, and vim would amend the previous pattern to \d+ boring is \w+, [ a-z]*. We'd have to document some decisions about how general to be, e.g. it's not obvious above that we should use \d+ instead of 123\d.
Closest existing thing I could find: https://www.vim.org/scripts/script.php?script_id=2302