I am in the process of writing a special-purpose network stack that runs on bare hardware; no OS at all. It’s remarkable how little code it takes when you don’t have to worry about coordinating between userspace and kernel space, between separate processes, between multiple use cases for the same software. Trying to write the same kind of software for a much faster processor, but in the context of an OS, was so much harder and wasted so much time just doing context switches.
Now, this thing I work on is much simpler than even the simple examples given, but for highly specialized software with tough performance requirements, I really don’t think you get much benefit at all from a Unix-style OS. Isolation between processes is meaningless when there’s only one process, or when “processes” are just cooperatively-scheduled subroutines with their own working memory. There are plenty of things that Unix is great for, but I am very happy to see wider acceptance of using other OS architectures or library-OS “unikernel” applications when they make sense.
I don’t really follow the argument here…it seems to rest on the idea that using a suffix of a string as another string is a common operation in C. I’ve written a lot of C, and other than maybe checking a file extension I don’t remember that being common at all. Stepping through the characters, comparing some characters, sure, but treating a pointer to the middle of a string as a string itself?
On the other hand, I wrote a lot of C using the original Mac OS toolbox, whose APIs all used “Pascal strings” whose first byte was the length count, and don’t remember any major issues other than remembering that fact.
Windows NT APIs (not Win32 but the low level NT calls) use strings with initial 2-byte lengths…again, I don’t remember this being an issue.
I’ve been writing some string manipulation code with C, and I rather liked being able to just move pointers around and insert null characters to manipulate strings in place. Being able to split a longer string into many substrings just by making pointers and nulls is neat.
It may be relevant to consider here that document processing and publication was the first real use of the C/Unix system at Bell Labs. It was the justification that Ken Thompson and Dennis Ritchie used to get the PDP-11 that would give them the room to do more than the proof-of-concept experiments they were trying out on the borrowed PDP-7 they were using. Instead of selling it as an OS development project, which is what Thompson really wanted to do since they dropped out of the Multics project, they sold it as a document processing platform for their patent clerks to use to prepare patent documents. In the context of editing large text documents, this usage of substrings of strings as strings is probably a bit more well-motivated.
There’s now a github repository where a ‘development history’ such as can be reconstructed today from backup tapes captures the development of Unix from its start as PDP-7 assembly to relatively modern SysV and BSD forms. The really early versions, from when Unix was still entirely an internal project to Bell Labs, are pretty interesting. You’ve got the bare bones of a minimalistic multi-user operating system and then a whole bunch of sophisticated document preparation tools (roff and friends, the successors of which still format all our Linux man pages into nicely formatted ASCII text or Postscript) and compiler development stuff.
There is plenty to criticize about C in today’s context; if you look at the amount of change that pre-existing standardized languages like Fortran (or even C++, recently) have gone through over the years, C basically ended up fossilized once it got through the ANSI process in ‘89. There are plenty of design decisions that ought to be revisited in light of the sophistication of today’s compiler technology and developments in programming language theory, but the standardization committee seems content to let C be a legacy platform and have C++ be where all but the bare minimum of new features and fixes get integrated.
But in the context of the late 1960s and early 1970s when the key design points of C were set (most of the semantics were straight from BCPL, and the type structure owes much to Algol 68) C was a remarkably well-designed language for what it was intended to do and how it was used. For contrast, the MUMPS language was developed just a few years before on a PDP-7 as well; take a look at it if you want to see how terrible things could be. People still write MUMPS code to run hospital databases today….
It can be used for more general substrings than just suffixes if you’re willing to stick destructive NULL placeholders in the string during in-place manipulation. Since strtok() dates to an early version of C, that seems to have been, if not a common use, at least a use that the designers had in mind at the time.
Yep, strtok for tokenizing and parsing strings into structures without copying. Not that important on modern computers, but back then …
I don’t want to trash the article, but it sounds like they put blinders over the real problems. Ripping out the retrospective, and removing the goalposts is not the solution to poor estimates. Why would a person think they can handle literally 5 times what they can actually handle, the answer is they were not sufficiently exploring the complexity of the tasks at hand.
It certainly doesn’t fix the poor estimates. But poor estimates are only a problem if the estimates themselves are providing value to the team/company. In my experience, they often aren’t. If you know that Feature X is the highest priority, taking time to estimate that it’s 1 day versus 5 days may be a total waste.
The first couple of chapters of the Kanban book are instructive in this regard. In that situation so much time was being spent estimating that no one was ever able to actually do any real work.
Why are your estimates taking so long and why are they so bad? Until you find the answers you are hiding problems.
IME, it’s pretty common across many ‘agile’ teams to spend a substantial amount of time getting inaccurate estimates.
I’ve met a few people who could accurately produce estimates in little time, but none of them could explain how they did it.
Sounds like your scrum teams are too large, how many people do you have in the room? Working without estimates can mean spending a lot of time doing the wrong solution to the problem.
Perhaps you are right that they have problems yet that they need to deal with. But I would like to invite you to take a look back at the Agile Manifesto, which is supposedly defining the guiding principles behind Scrum, Kanban, XP, etc. Ultimately, all the practices and techniques and tools are meant to be subservient to self-directed teams that are continually examining their progress and changing things to get any perceived roadblocks to their progress out of the way.
There is little value in producing an estimate of the work to be done in some arbitrary amount of time if no one is asking for that particular fact and it’s not providing immediate value to the team in pacing their work. The relationship between developer and customer is different in various situations, and not all customers need precise work estimates at two-week intervals.
Furthermore, placing arbitrary time/size constraints on granularity of estimation can wreak havoc on a developer’s intuition for how long things will take. It could be that they’re, as a team, relatively good at estimation via a continual process like Kanban, but terrible when forced to break things down in ways they’re not used to in Scrum. Could they improve their Scrum estimates over time? Probably. Is it worth it to deal with the demoralization of the team in the mean time? That’s their call to make! That’s the point of the agile manifesto, as I understand it.
I am a firm believer in the value of processes, tools, and procedures. But I also believe just as firmly that there’s no “one size fits all” perfect set of processes, tools, and procedures that will fit every team and project. Ultimately, it’s the responsibility of development teams to be self-aware and self-directed enough to develop a set of these things that make them most effective. Kudos to the author for making an effort to do this!
I think a lot of the commenters here so far are mistaking the intent of the article. It is not so much a complaint about “command-line bullshittery” (although it has some aspects of that) as it is about the value of helping students work through it without becoming completely bewildered and demoralized.
In other words, he’s saying that one of the most effective uses of his time as a research advisor is to take the time to tutor students in how to deal effectively with the command line! And a part of that is not belittling those that have not been steeped in it previous to their school experience, and assuring them that while it’s complex and powerful stuff, it’s not what their research is about and they shouldn’t feel like they’re inadequate because they don’t know it yet.
So this is not about how terrible command line stuff is, it’s about how it’s complex and it’s really valuable to take the time to teach people about it and how to deal with its complexity without making them feel bad that they didn’t know it already. They’ll no doubt end up picking it up, but they’ll do so faster and they’ll be doing productive research faster if you do some work to remove stumbling blocks up front. And doing that work is the “solution” that’s being advocated!
I couldn’t have possibly built this without Software Transactional Memory.
My Haskell is pretty rough, but that doesn’t look all that different from go’s CSP. That’s not a complaint, but I’m curious if anybody would care to compare/contrast approaches.
My intuition (or at least comfort level) is that it’s easier to reason about one process collecting state and drawing when it wants rather than trying to ensure it always sees a consistent view of the world.
It’s hard to tell for sure exactly how the STM composition he shows is working, but it looks to me like the sum type of possible changes is built there in the main display thread. In a CSP-style system, there would be something in each of the threads constructing a value of one of those variants and sending it to the main display thread.
It seems like the threads in this example just directly operate on some shared data structure. The display thread notices the changes by watching the structure and translates them into one of the display update variants, rather than getting a message and doing updates itself.
The trouble with a purely-messaging update system in Haskell, when each of the threads needs to read the shared state as well as update it, is that that without some sort of mutable reference like STM, you have to push the new state to each of the threads via message or have messages that update the state get performed once per thread. These are also valid ways of doing it, but in some ways it’s simpler for the mutator threads to simply each encapsulate their updates to the state in an STM transaction. In this scenario, the thread responsible for updating the display just watches for mutations of the shared state and translates them into screen updates rather than having to collect update requests describing data structure manipulations, perform them, and push out updates to all the other threads as well as the screen.
Describing arbitrary data structure updates via messages also leads to a fairly complex message structure, and possibly even a full embedded DSL for describing them. Haskell is well-equipped to define and interpret that kind of thing, but it’s a lot of heavy machinery for simply doing standard updates to a shared bit of data.
So, I think that when individual threads are interacting with a central thread via a fairly regimented protocol, the CSP approach is probably more efficient and understandable. But when the threads all share a fairly complex piece of state that any of them could potentially make arbitrary reads and updates to, the CSP model starts to be less attractive compared to an explicit shared-state model like STM. I think this particular ‘terminal multiplexing’ example could easily go either way, but some of the author’s design decisions early on (or maybe baked into an underlying library) probably led to the STM approach being the more comfortable one.
You might find this paper on data structures for text editing interesting, which I came across a couple of days ago when I was looking into how text editors manage their data as well.
The “Piece Table” approach was first developed at Xerox PARC for the Bravo editor, which was designed by Butler Lampson and Charles Simonyi (although the idea itself was apparently from J Strother Moore who was also at Xerox; he’s the Moore of Boyer-Moore String Search as well); Simonyi later went on to develop Microsoft Word, which used the same representation. AbiWord uses it as well. In the realm of text editors, Niklaus Wirth’s Lilith project (inspired by the Xerox Alto machines) had an editor named Lara, which also used a piece chain representation. Here’s a nice tutorial on piece chains with some additional links to historical uses.