OS X Spaces and TotalSpaces not cutting it for me
tl;dr You have two options. You can toggle some highlights, or you can skip to Here is my wishlist.
I got a new MacBook a few months back. Before this, I was using exclusively Arch Linux, most recently with wmii [1]. Actually, I have to admit, I’m one of the people who only got my MacBook because it represents a nice intersection between non-free software (mostly for graphics and video editing), various other free—and often open-source—software, much of which has come from the land of Linux et al., which is enabled by OS X’s reasonable POSIXishness. That last characteristic, and the comfy, clicky keyboard (albeit missing some of my favorite keys) are the final benefit I’ll list. I am not an Apple lover. I have always hated the Apple “my windows are fucking everywhere” philosophy to window management, which has not changed in any meaningful way since the first Apple I ever used almost 20 years ago (an Apple II). No, the fullscreen button is not usable. Thanks SizeUp for letting me at least fullscreen my windows without patiently dragging them to the top left and then dragging their corner to the bottom right.
For a while after I got my MacBook, I was really dissatisfied with the Mountain Lion Spaces implementation, chiefly because of the not-optional-anymore transition animations [2], and, to a lesser degree, because the desktop layout is one-dimensional, which is stupid and wasteful. I’ve used HyperSpaces a few times in the past, but, of course, HyperSpaces wasn’t (and isn’t) compatible with Lion or Mountain Lion.
Then I found TotalSpaces. At the time it was in beta and freely available, and worked well, other than some odd bugs involving going to a totally unexpected part of the grid when transitioning from fullscreen windows. I had instant transitions and one additional dimension (that’s two whole dimensions, folks) to play with. The fullscreen window handling was a bit brittle, but then I’d pretty much given up on trying to use fullscreen windows in OS X anyways. I still wished TotalSpaces had done a bit more than cloning HyperSpaces (giving me a graph of desktops to play with instead of a grid would have been cool), but just having the transition animation gone was a major improvement.
The other shoe dropped once I got an external monitor. I haven’t had one for a while, but there was a time that I was very used to having one or several [3]. I was pretty happy when I found out how easy it was to attach and detach my monitor, and how easy it was to set up its layout relative to my primary (the laptop’s built-in panel). This was not to last. I was appalled to see that the nice, easy layout I’d created was now the shape of each of my desktops, and that it was completely impossible to transition the desktop displayed on each monitor individually. So far as I can tell, the blame for this probably does not deserve to be placed on TotalSpaces, but it would probably be better if it did, since I’m sure this is just another part of Apple’s “we know best for you” song and dance and will be fixed only if, in their infinite wisdom, they deem it to be good and right. How long now before I will have to jailbreak my laptop before I can install TotalSpaces? SizeUp? MiddleClick? [4]
Hey Apple, have you considered the possibility that I might like to have a monitor or two for watching pretty graphs of some stuff and entertaining me while I work? Have you considered that, with my 12 desktops that have consoles, VMs, file browsers, web browsers, graphics editors, and other miscellania that I might occasionally want to switch the desktop on one monitor without switching (all) the other(s)? Have you considered that your notebook customers, who make up a majority of your OS X userbase, might be frequently in the situation to move between environments alternatively with and without external displays, and that dumping all the damn windows that use to live on now-unplugged external monitors into random places and making me move the bastards back by hand every time I plug in might not be desirable behavior?
The only challenge—and not an enormously difficult one—is dealing with desktops not having the same resolution. I could see many possible ways of dealing with this, including elastic layouts, having each display merely be a viewport onto some single high-resolution space, or whatever. Take your pick; any of them would be better than the current situation.
Here is my wishlist:
- Let me switch the desktop displayed on one monitor without switching what is displayed on every other monitor.
- More specifically, separate monitors and desktops, so that big chunks of my oddly-shaped desktops, with their variously-sized external monitor appendages, don’t disappear and shit their former residents everywhere upon monitor disconnection.
- If you’d like, let me have monitor layouts, optionally lock several monitors together, or something else, so that I can transition several monitors simultaneously.
- It’s been 20 years. Can we have window edge snapping to the boundaries of the display and other windows? Dear third-party-developer, I will pay you $10 for an app that does only this.
[1] Although wmii doesn’t directly support gestures (I like gestures), you can transition to numbered desktops by pressing Meta+N, where N is the desktop number, a style that OS X also supports.
[2] The biggest issue by far with these animations is not even the animation itself, but the fact that the focused window in the desktop being transitioned from remains focused until the next desktop has completed its transition in.
[3] One of the reasons I use multiple desktops, and am so conscious of the shortcomings I’ve outlined, is because I’m somewhat accustomed to having multiple monitors, and am expecting a similarly seamless experience from multiple desktops. This similarity has natural boundaries, but they are significantly less than the software boundaries that are currently extant.
[4] Yes, yes, Apple fanboys and fangirls, I know all the many reasons why Apple is wonderful, and that they know best for you and me. Move along.
Why optimizing compilers aren’t good enough
Optimizing compilers fail to answer one question: “How will your program be used?” This question is essential and yet elusive. For some problems, no amount of work is able to create a unified benefit for all use cases. For some problems, the number of possible use cases to individually optimize for represents a cost outweighing its reward. For some problems, sufficient information to generate appropriate tests is not known. The list goes on. For these cases, we turn to the profiling JIT.
Note: “Optimizing compilers” could easily be exchanged for “Assembly” with identical accuracy; the only difference is that, in current times, users of optimizing compilers have supplanted users of assembly as the majority by a vast margin.
Scaling and Hot Spot Prevention in Order-preserving Sharding
Many modern databases support order-preserving sharding. This type of sharding has desirable properties, particularly query isolation. Unfortunately, this type of sharding in real-world scenarios often creates some very serious problems that result in hot spots and limit scaling. This document presents a possible solution to these issues.
Note: In order to maintain some basis in the real world, the example material I will be using is based on the MongoDB documentation for choosing a shard key, which presents an order-preserving shard key function that is based on a “state of residence” attribute (“state” in this case means, e.g., New York, not “residing”/”not residing”, etc.) I consider in my examples a hypothetical database wherein the documents stored describe persons, each of whom has a state of residence.
When using order-preserving partitioning, there are frequently attributes for which certain types of queries—chiefly range queries—benefit enormously from having an order-preserving shard key function. That said, these attributes often exhibit two problems: they themselves may not provide sufficient granularity to allow effective rebalancing and/or the workloads associated with each key are naturally unbalanced. State of residence in our hypothetical database is an excellent example of both of these properties; given that the set of states is (semi-)fixed, at a fairly small number, one can not expand beyond 50 shards by using a naive order-preserving function that is merely the value of the state, and, given (as might be expected) the prior probability of a person existing in the database is sufficiently independent of their state of residence, the natural population discrepancies between states leads hot spots to form naturally in highly populous states such as New York and California.
Both of the issues described can be overcome in many applications with reasonable ease. One might choose, e.g., another attribute to append to the state of residence in the shard key that has more bits of variation, such as the user’s full name, ZIP code, etc. It is not necessary to know this attribute while querying in order to gain the query isolation benefits for range queries, we just set the shard key boundaries such that they encompass all objects that exist in the entire range of the given prefixes (perhaps by using a high-value non-printable character that is not allowed in the additional attribute being used; a delimiter that is not used in the state name may also be required, were there to be state names with prefixes that overlapped one another). The additional attributes are simply used to establish a more granular order between records and allow for rebalancing boundaries to occur within a single attribute value.
Though the above solution can likely be achieved in MongoDB by the client, with no change to the database code itself, if we are willing to write new code we can achieve the same properties with no finangling from the user. All that is required is a slight change in our philosophy about the treatment of shard keys. Let us merely release the requirement that every node needs to have a range which starts and ends on a unique shard key.
We have now opened up a whole new world of possibilities. The system is free to allow multiple shards to have their range begin and end on the same shard key, internally allowing nodes to renegotiate their burden for that shard key based on, for example, an artificial ordering based on unique object id. Boundaries are now independent of the lacking granularity of the attribute to be queried, while maintaining the system’s ability to perform query isolation over ranges. We are similarly able to scale our system beyond what it was before, where certain attribute values might have overwhelmed the capacity of a single node, and where there was no way to divide the load.
So, what are the downsides? The standout concern is that we are now less able to do without a means in the system for clients/client routers to dynamically update their knowledge of partition boundaries. This is the natural cost of wishing to support dynamic rebalancing, and without dynamic rebalancing there is no point in implementing these changes. WIthout support for such rebalancing, the system is highly susceptible to hot spot formation anyway, due to the characteristics of order-preserving partitioning over attributes whose value probability distribution is inequal. Thus, dynamic rebalancing being part and parcel of implementing the type of system we wish to create, we can discard it as a downside for practical purposes.
I recently had a conversation about a (possibly imaginary, but nonetheless humorous and reasonable) problem with a software product helping you map your family’s lineage. The issue in question was that some folks needed to be able to have relationships that involved their mother being their sister. Of course, the smart programmers who made the genealogy mapper wanted to make sure that their system constantly checked itself for valid data and had built in a constraint that no such unreasonable relationship could occur. Reading some docs about iOS’ Core Data, specifically:
For example, in a Person entity you might implement validation method to ensure that a hasDriversLicense property cannot be true if the age property is less than 17
I was reminded of this strange fallacy, and thought it deserved a few words.
Don’t validate things that do not represent absolute limits. There are many reasons that a person who is less than 17 can’t have a driver’s license, and many reasons why someone’s sister can’t be their mother, but none of them are absolute. Perhaps the minimum age for a license changes (up OR down). Perhaps your product expands to a country where the licensing requirements are different. Perhaps you’re not an expert with the law and don’t know that, at least in the US, there are cases where people can get driver’s licenses as young as 14. Perhaps your mother was seperated from your family at a very young age and then fell in love unknowingly with her father, shortly thereafter also your father.
The validation of such constraints is not a job for your data model. Let your data model validate things about your data that ARE absolute; let it validate that a date is a date in a certain format, that an email address is an email address, that a boolean is a boolean. There is a line that can be drawn between validating what you need to ensure your application operates correctly (like not trying to send email to addresses that aren’t emails), and things beyond that. Going past this line will only bring pain and turmoil. Maybe discovering these anomalies is the job of bulk heuristics. Maybe it’s the job of human operators to perform additional verification on such records. But it’s not the job of your data model. Know where to draw the line: unusual doesn’t mean invalid, and often the bar is a lot lower than you think.
Update: @matolucina has pointed out that, since version 3.x, the half-assed pub/sub has been converted to full-assed pub/sub with publisher-side filtering. @sustrik has pointed out that ZMQ_PAIR does (sort of) what I want, though according to the docs:
ZMQ_PAIR sockets are designed for inter-thread communication across the zmq_inproc(7) transport and do not implement functionality such as auto-reconnection. ZMQ_PAIR sockets are considered experimental and may have other missing or broken aspects.
Seems like ZMQ_PAIR is indeed close to what I’m looking for, though I’d rather see it be the thing on which all the other items are built, rather than an (apparently recent) afterthought.
Original: It has been countless times that I have looked for a toolkit to use for simple networking and stumbled upon ZeroMQ. And, every one of the countless times, I have walked away. That really annoys me, because every time I think I want to use ZMQ it seems like it should be awesome, but then it isn’t. I thought I’d share why.
ZeroMQ does a whole bunch of super cool stuff, but it doesn’t do a great job of bidirectionality. What’s silly is that every transport that ZMQ proports to support is natively bidirectional or easily made so. The developers throw this away, and then proceed to build a variety of “specialized” socket types, from sockets that do routing of messages to half-assed pub/sub (filtering done client-side). OK, ZeroMQ, it’s awesome that you’re written in C with a really simple API, have bindings to everything known to man, and are non-blocking and fast courtesy of a modern event loop. Let me tell you what I really want.
Give me a general message-oriented bidirectional transport. That is, I want ZeroMQ to be a lot of what it already is now, but to throw away all its stupid socket types and just give me a bidirectional message transport where I can send any buffer of bytes I want. If I need to handshake to figure out what protocols or features a remote supports, I can build it on top (try handshaking with a unidirectional socket). If I need to make a stupid client-side-filtering pub/sub, I can do that too! All the many socket types with specialized behavior can be built atop this, whether or not they are included as part of the library. And don’t tell me that you can’t do broadcast! Broadcast operations are just as easily defined in terms of sets of bidirectional pipes as they are in terms of sets of unidirectional pipes. If the library wants to understand aspects of the underlying transports that allow it to, for example, leverage IP broadcast when sending messages, I’m all for it. Do it on top of a bidirectional abstraction.