338 karma · joined July 10, 2019
For example, it could just as easily be the case that adjustments to dysfunctional aspects of the company's internal politics improve both morale and productivity, but the morale change becomes apparent more quickly.
In my neck of the woods, there are departments that have to make do with whole teams of low-skill employees because, while a more skilled person could do the work of at least four lower-skill workers, they would also require two lower-skill workers' worth of salary, and you just can't be paying any one person that much money because that would be Government Waste.
So many people's first instinct to respond by buying more shares of that company, thereby driving its price and market cap higher. That's a reaction that implies that we think that the general trend is toward Buy-n-Large. If we expected regression to the mean to be the driving phenomenon, then we'd be more likely to respond by selling.
(Disclaimer: I'm not suggesting that's actually how things work, just that a lot of us behave as if we think that's how it works, or should work.)
There has only ever been one goal that has actually driven us to push our horizons further out into space, and I think it's the only one that really makes sense: We do it for the challenge and for the adventure.
As John F. Kennedy so famously put it, "We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard; because that goal will serve to organize and measure the best of our energies and skills."
To take the example of support, pre-acquisition, the support team had a reputation for being one of the best and most knowledgeable in the industry. That reputation went up in smoke rather quickly when the acquiring company decided to merge support into their existing support vertical and adopt its existing policies, including things like requiring the support and the product development teams to communicate through JIRA instead of using informal channels like instant messages or (in exceptional cases) pulling a developer into the call.
The end result was that the mean time to find a resolution for the non-routine issues went from hours to days. Ironically, while management claimed this would reduce disruption for the development team, it actually increased the time that developers had to spend on supporting the support team, since it made communication so much more difficult. Which, in turn, means that it slowed down both customer support and product development by bogging them both down with paperwork.
I also can't think of a single large software company that doesn't, in the long run, survive by either endlessly buying and extracting all the value out of smaller software companies, or creating a moat that makes it almost impossible for new competitors to emerge.
Having worked for a small software company that got acquired by a large one that used the former survival strategy, and therefore witnessed firsthand the subsequent doubling of headcount and simultaneous halving of overall productivity, I can offer one of what I assume are several possible answers: Paperwork. And lots of it.
But that requires a very engaged PO who really gets what grooming is really about. Also, I don't know what it is with MBA types, but it really seems like anything that can be turned into a KPI, will be turned into a KPI, without ever pausing to think about whether it makes any sense to do so. And that makes story points radioactive: In the absence of intense and intelligent regulatory oversight, their potential value is more-or-less negated by their potential for abuse and misuse.
Incidentally, this is what fascinates me about the Forth approach: The unflinching dedication to stripping the system down to only the things that you actually need. The problem I see is, the Forth way of doing it seems to assume you're working with an army of one. How do you scale that up to a modern product team that may comprise 10, 50, 100, even 1000 people?
And then, over time, it became clear that, for whatever reason, management just wasn't going for it. So all these different bits and bobs pivoted and morphed and re-scoped into a process by which the stone tries to squeeze more blood out of itself.
IMO, the most valuable bit of Scrum isn't user stories, or story points, or sprinting, or having a Scrum Master, or burndown charts, or anything like that. It's the idea of having a single, designated person whose job is to tell people, "no": The Product Owner.
The dirty secret is, velocity is a crap metric. It unskeptically measures total things implemented, even though we all know that only a portion - I'm guessing often less than half - of those actually needed to be implemented. Meaning that the best way to increase a product team's actual productivity isn't to increase velocity, it's to maximize the average usefulness of features being implemented. Preferably by identifying the useless and less-useful ones ones, and deciding not to implement them. Or, equivalently, identifying the ones that seem most likely to be useful given the currently available information, and making sure those are always the ones at the top of the to-do list.
My suspicion is that, the better your product manager is at that particular job, the less need there is for any of the fancy ceremonies. Because most of those ceremonies aren't there for the developers' benefit; they're really only there to make it easier for the PO to scope and prioritize features.
The difference I'm drawing being, libraries just provide a mess of utility functions. Theoretically, even if your compiler won't strip the library stuff you don't need, you'd be able to take just the bits you need by copy/pasting a relatively small volume of code. And dropping the library would be a small change, that just requires finding replacements for the functions and classes you were using.
Frameworks tend to involve some Grand Unifying Abstraction that you need to inherit from, and that gets imposed on your own code. Things tend to be so tangled together at a conceptual level that it's not really possible to use them in an a la carte manner. Migrating off of a framework tends to require more-or-less a rewrite of all the code that interacts with it.
To take some Web examples: jQuery's more on the library side of things. D3 is more of a framework. React is very much a framework.
I'm inclined to say that, e.g., the modern browser is a cautionary tale that complements the Chuck Moore approach to things: By forever piling thing on top of thing in an evolutionary way, you end up with a system that ultimately feels more and more cobbled together, and less and less like it ever had any sort of an intelligent designer. Perhaps the lesson is that it can be worthwhile to occasionally stop, take a real look at what things you really do need, aggressively discard the ones you don't, and properly re-engineer and re-build the system.
Obviously there are issues of interoperating with the rest of the world to consider there, and Moore has made a career of scrupulously avoiding such encumbrances. But a nerd can dream.
And there is plenty of research demonstrating that this is exactly what they do, and that doctors are indeed swayed by it, because, as you say, they don't have the time to do keep up with it all on their own.
And yes, there is a fundamental difference to consider here: My doctor has a fiduciary responsibility to do what's best for my health, to the best of their ability, and drug marketing compromises that. By contrast, nobody has any fiduciary responsibilities related to which brand of toilet paper I use.
It's great for learning facts, so, if you wanted to, I suppose you could use it for something like memorizing a pile of library functions. But I'm having a hard time seeing that as an efficient thing to do in the age of Google and Stack Overflow and editors with auto-suggestion.
Or if you're a low-level programmer, and want to memorize a new architecture's assembly language, maybe.
Even on the language side: SRS is great for shoehorning a basic vocabulary into your head when you're first getting started with a language. It kind of sucks for learning anything but the most basic grammar, and for getting a feel for how to actually express yourself in a language, or comprehend the language as it would be spoken by a competent speaker. Comprehensible input is still the go-to method for that side of language learning. And once you get to the intermediate or high intermediate stage, SRS isn't even all that great for learning the vocabulary anymore, because it's hard to really internalize the nuances of more advanced vocabulary that way. You'll go farther faster by just watching a lot of TV and reading a lot of books, where you get to encounter the words living in their natural habitat instead of dead and dried and pinned to a notecard.
According to Anki, I'm averaging 10 minutes a day on my language vocabulary deck. It does happen in a series of short, 1-2 minute bursts when I'm sitting on the toilet or whatever.
To that end, another useful thing I've discovered: Reviewing flashcards (and, spaced repetition) is not a good way to learn. It's a good way to reinforce your memory of things you've already learned. The real learning happens when you make the flashcards. The time spent focused on each concept so that you can decide how to break it into a series of smaller factoids that are right-sized for a flashcard, and coming up with whatever mnemonic devices you'll be using to help you remember this concept, is where the learning happens, because that whole process involves a fair amount of turning it over in your head.
Meaning you really shouldn't ever use a pre-made deck. It may not seem like it at first, but it really is normally more efficient to make your own from scratch.
That's impossible with text-based formats like XML and JSON, because everything is fractally variable-length.
Protobuf - or, more specifically, proto files - gives you a central place where you can define and also document your formats. You can throw an ASCII-field UML sequence diagram in there, if you need to. And it's right there in the single file that everyone will use to communicate the protocol, and the protocol at least can't change in any structural way without editing that file, so it's got a much higher chance of being kept up-to-date, and of being read by the people who need to read it, than any of the available options for documenting JSON-based protocols.
All JSON gives you is human readability, and browsers can read it without a library. The 2nd, I don't care about with back-end services. The 1st I don't really care about at all, because command-line utilities and library functions for dumping protobuf datagrams to a text format are a dime a dozen.
But still, given that easy consumption from JavaScript is the ultimate primordial reason for choosing JSON over other formats, it seems like trying to transmit integers with more than 53 bits of precision over JSON is asking for trouble. Because it's only a matter of time until someone will want to do something like write a new service in Node, and the JavaScript parsers for other formats are at least somewhat more likely to guide people toward using BigInt for large integers.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Ultima IV was about as big-budget as a video game got. Here are the credits for the DOS version: https://www.mobygames.com/game/dos/ultima-iv-quest-of-the-av...
19 people, total, for the original development and production on the Apple II version, plus the PC, Atari and Amiga ports.
The economics are just really, really bad. It's not just all the competition driving prices down so low that people will literally consider the price of a coffee to be too much to pay for several hours of entertainment. It's not just that a musician can hold down a day job and do what they love on evenings and weekends. It's also that the the potential payoff on your invested time is really, really crappy. To become a musician, you have to practice a lot when you're a kid, but, once you're there, the time it takes to produce new work is really quite low, especially considering how much replayability it has, especially if you're mostly playing standards and other traditional stuff. And, if people like it, they'll come see you perform it repeatedly.
Indie games, no matter how much I liked that game, I'm gonna play it once, and then, if you want me to be your audience again, you've got to basically go back to square one and start over.
I've worked with people who write messy, tangled code in giant methods, and my experience has been that forcing them to write smaller functions is futile. Satisfying the static analyzer is just too easy: Move all your variables into mutable fields that all the methods fiddle with, break the contents of the method out into smaller methods with cryptic and misleading names, create a master method that calls them all in a row. Voila, with barely any effort you've satisfied the static analyzer and made the code even less maintainable.
Except when I forget to take my daily out of my pencil case before flying. :(
1. Static analysis tools should not generate useless noise. I am already well aware that that function I just edited was 1,000 lines long. If I didn't break it down, it's either because I didn't think doing so would be a good idea, or because I don't perceive that to be a problem in the first place, or because I simply don't care. In any case, there's a 100% chance that I'm going to ignore any advice from the static analysis tool on this one. That means that such a rule is, at best, useless.
2. I'm generally not sure if my feelings about long functions reflect reality. I recently saw a talk about evidence-based software practice where the speaker claimed that nobody's been able to demonstrate a link between average function length and code quality, and not for lack of trying.
The airline's already got "being crappy to the person who's having a crappy day" covered. Don't be the human embodiment of an airline.
I worked at a place where we had to interact with financial exchanges, which nominally talk standard protocols but actually all have their own quirks in their implementations of the protocols, which we had to account for on our own end. They ended up going with the copy/paste approach, and, while I was initially horrified, I came to realize that they're right.
The admonishment against copy/paste is meant to deal with the risk of accidentally forgetting to update one of the copies when there's a new change that needs to be pushed across all of them. It turns out that, for the problem domain we were working in, which sounds quite similar to the one TFI describes, that never happens. Even when the standards body releases a new version of the protocol, each vendor upgrades on their own schedule, and the slowest-moving vendor might stick on the old version for 5 or even 10 years, and when they finally do get around to it, their implementation of that feature will have its own quirks, so just setting a flag saying, "Vendor X is now on version Y" wasn't going to work, anyway. So then you (hypothetically) create a set of flags saying, "Vendor X is using version Y, but with these behaviors that differ from everyone else's version of Y", add a bunch of new if-statements, and the actual logic that might execute at run-time gets even more obfuscated behind a tangle of counterfactual configurations that won't happen in real life but still exist in the code and are supported in the application.
So, to sum up: nominally the same protocol, but everyone does it differently, and upgrades on their own schedule. It really is a horrendous tangle. Dealing with that mess by mirroring it in your code with an equally tangled pile of flags and conditionals is also going to be a mess, no matter how you choose to organize the code.
Don't do that. Alexander the Great was right: Sometimes the best way to deal with these sorts of things is by cutting them into pieces. Then, when you're dealing with one implementation's quirks, you only have to be thinking about that one set of quirks, and not the combinatorial explosion of possible interactions that you get when you try to mix them all together.