Spec-ulation Keynote - Rich Hickey
646 15 51010
By appleflaxen 2017-09-20
Someone on HN posted the spec-ulation talk by Rich Hickey recently . I found it really persuasive, with the fundamental point being: when you update your software in an incompatible way, you shouldn't bump the "major version" number; you should rename it.
I hope the firefox devs consider this approach. Firefox has great name recognition, but it will be a deficit if users learn that it is a name that means breakage.
By appleflaxen 2017-09-20
the very first slides talk about the deprecation and removal of old APIs. if there are any HN readers who influence go, consider Rich Hickey's argument  regarding deprecation and code removal.
Bottom line: he proposes that one should never take away a function/API (particularly when you are a library or programming language).
edit: superficial word choice
By gavinpc 2017-09-20
See this talk  about this addition to Clojure called core.spec . I read the paper first, and it isn't until the end of the presentation that I understood how it was related to the feature at all. Basically, core.spec is a kind of formal verification tool designed to deal with the growth of software. It is not a type system, though it resembles one in some ways. The objective is to support comparisons between the signatures of a function at two different points and say, are these compatible? Is this a breaking change? You have to design for growth: make no assumptions about unspecified keys and always assume that later versions may return more than they used to. And so on.
If you're a fan of semver, be warned.
By bad_user 2017-09-26
> I have a hard time being too impressed because more modern languages are doing this out of the gates
The problem with Java is that it's an already established and very popular platform and it's been so for the past decade at least. When starting from scratch, it's easy to just throw it all away and start fresh, it's easy to fix mistakes that were made in the past.
The irony though is that we still have a hard time learning from history. Just look at Go. Sometimes this industry feels like Groundhog Day, the movie.
Also, no platform or language that I know of has gotten "modules" right, with Java being one of the platforms that has gotten closest to fixing the problem actually (by means of OSGi). To see why modules are still a big problem and why we won't have a fix for the foreseeable future, I invite you to watch this keynote by Rich Hickey: https://www.youtube.com/watch?v=oyLBGkS5ICk
By pjmlp 2017-11-04
Rich Hickey has a wonderful talk about it.
"Spec-ulation" - https://www.youtube.com/watch?v=oyLBGkS5ICk
Which I fully agree with, basically there are no major, minor, patch level changes, in reality every change is a possible breaking changes, because we don't control what downstream is doing with our software.
By akkartik 2017-11-13
I wasn't aware of greenkeeper, thanks. Can you give some examples of "Semver-based package managers"?
I'm curious what you think of the two posts I was basing mine on:
"Spec-ulation" by Rich Hickey: https://www.youtube.com/watch?v=oyLBGkS5ICk
"Volatile Software" by Steve Losh: http://stevelosh.com/blog/2012/04/volatile-software
I think there may partly be a "universes colliding" effect here, and partly just the future being non-uniformly distributed.
By anonymous 2018-02-05
TL;DR: use something like clojure.set/rename or clojure.set/rename-keys.
It's my impression (mostly based on https://www.youtube.com/watch?v=oyLBGkS5ICk) that the "clojure way" is to think about your design thoroughly enough up-front that you're willing to stick with it. (c.f. "hammock-driven development").
If you do wind up needing to make this sort of change, create another set of functions (maybe use the same names in a different ns) that use the new keyword names. Now have these call your originals, or your originals call the new ones (whichever makes more sense). Update your docs to recommend that people use the new version.
Spend more time in the hammock.
More generally (and hopefully helpfully):
Try to keep your functions small and decoupled enough that you're just passing around a few values anyway. If you're calling something that needs a :body, how much of the rest of the associated values in that map does it really need?
Can you refactor those parts into their own functions to reduce the coupling? Can you supply/return higher-order functions to isolate functionality that seems like it needs to be all snarled up with your :content handling? (The "partial" function is your friend here).
Full-blown explanation (complete with personal whining):
These days, a big part of this involves using maps with namespaced keywords, along with spec. Since you can alias your namespaces, this actually seems to make the particular problem you're addressing worse: you can't even reliably do a simple search/replace over your project.
I'm going through a lot of pain in this regard right now, revisiting some code I wrote while I was figuring this out. I realized that I got the namespaces wrong.
If anyone else were actually using my library, the real answer would be to just accept that what I started with is ugly, broken, and poorly planned. I could write new functions that are more expressive than what I have now (so, in your example, they'd use a map that contains :bar/content rather than :foo/body). Maybe mark the old functions deprecated, but accept that I can never, ever eliminate them.
Or possibly I should just deprecate that library and point existing/potential users to a new one that more closely matches what I actually want.
Actually, it's enough of a mess that the latter option is tempting. Even though I'm the only user. Renaming keys like this seems almost deliberately painful.
Based on my experience with the rest of the language, I suspect that was the case, because breaking your API is a terrible thing to do.
On the other hand, there's at least one more piece to this.
What about black-box, undocumented data that you want to be able to change at the drop of a hat? (Say you have a value that you treat like a handle, which happens to be implemented as a map). The whole OOP private undocumented implementation details stuff.
This part of your API will have functions with names like "establish-database-connection!" and "run-database-command!". The rest of it really should be pure functions that set up sequences of pending side-effects that you pass to the ones that actually change the world.
The Pedestal library is a great example of this approach. Its context maps are pretty much the exact opposite of the approach I recommended above about just using as few decoupled values as possible for any given function call...these opinions are definitely and merely my own.
Your end-user is supposed to call your functions and get back...call it a gray box. They are responsible for supplying it (without modifications) to your other functions that rely on it (which, honestly, should be pretty rare: these are really for system-boundary code that causes side-effects). If they look inside, that's their business, but I think it's fair for you to change those details.
Changing those details under the hood takes us back to your original problem: doing so is still painful.
That's another reason to be very stingy about writing code that needs this sort of thing.
Hope that helps!