Another ex-VMware here (9 years on the Workstation team). It's so very sad to see... I grew up there from a career standpoint and I was proud to be there, loved being there, and I just don't recognize it anymore.
I agree with your point about "winning was the default state." I joined during the Diane Greene era and left in the Pat Gelsinger era, spoke to all three CEOs at different points in one-on-ones, and learned a lot about how different people approach the challenges of running a company and listening to employees.
Pre-Broadcom, sort of toward the end of my time there, there was a lot of unintended self-sabotage that didn't need to happen. We lost people that we shouldn't and shot ourselves in the foot for some really dumb reasons, which just a bit more coordination could have prevented. There were some innovative ideas that got lost in all this, and I believe could have fueled VMware's product line and put it in the right positions for where the sector ultimately went. Alas.
It made a lot of money with its core virtualization tech, which gave it excellent market momentum in datacenters. But the ever growing cloud lanscape was a shift that eventually became an all-hands-on-deck (sort of, and all too late) moment, hence the sudden interest in cloud-based offerings.
IMHO, I think it was never going to be an easy shift. But after Pat left for Intel, leadership never seemed to recover.
No single root cause, but I'd say a combination of rapid growth, a changing market with no obvious (at-the-time) answers, some resource issues, and some missteps by some people.
The company began to grow fast in the years after I joined. VMware's early culture was amazing (a template for any company, imho), but it's hard to maintain that with fast growth. Not a unique situation, but I feel it had an impact on how we addressed certain challenges.
ESX was big, and we wanted to figure out the next big thing. There were a few initiatives, some gambles. Reorgs didn't always match and some initiatives got starved, others over-fed.
Let me take the opportunity to say that we did have a lot of freedom in engineering to build and experiment, which I always loved. This was a strength of the company. Personally, I got to figure out and build Unity in our Workstation product (it let you pop windws out of a VM into the host -- SUPER challenging), the whole remote VM infrastructure for Workstation (took 3 years with a major rewrite), WSX (early-days HTML5 client for accessing VMs using just a native browser and a network connection), amongst others.
But the world changed and we didn't really nail this. Case in point, The Cloud. (And later Docker.)
In early Cloud days, we were trying to figure out what that all this really should look like, how we fit in. We had things in the works that didn't get released or got restarted, we had some really useful bits that got spun out. What we should have built was more obvious in retrospect, but not so much at the time.
I think we had a lot of really good people in the management chain, and overall people were trying to do the right things there. But we did have a few high-impact bone-headed decisions (some short-term cost savings at the expense of longer-term strategy in parts of some departments) and some people who shouldn't have had the responsibilities they did (in my opinion). Some of these decisions may have made sense at those levels at the time due to factors they were dealing with that I don't know about, but these did damage.
Bear in mind, it was a big company in a quickly-evolving industry, and it's not always easy to get things right. I would NOT say "corporate greed" or "screwing over customers" or anything like that. Not while I was there. But missteps and hard questions to answer about the future.
All that said, I enjoyed working there. I left to work on Review Board (https://www.reviewboard.org) full time in 2013, and then my old team disbanded in 2016, but much of the team still gets dinner every month, 10 years later. Still sees movies, still hangs out in a Discord. I wouldn't trade working there for anything.
About a year ago, I started working on disassembling the NES game Faxanadu. The goal was to fully understand and document the game, and to produce the most thorough understanding of the game yet. It's been fascinating. The game has a two binary scripting languages (one for interactions with items and NPCs, one for NPC/enemy behaviors) and a very interesting graphics rendering layer. At this point pretty much the entire game is well-understood.
Based on this work, there's now a new suite of tools for producing games under the Faxanadu engine, new major mods built with all this, and some work on a modified ROM better built for porting and modding.
Building a universal web-based retro game modding tool along with that work called Nostalgia Studio. The idea is that there's a core foundation for representing game state and building editors, a platform-specific layer for representing things like the NES APU and PPU state, and then game-specific implementations that populate state for two layers below.
Those are the hobbies.
Day job, I work on Review Board (https://www.reviewboard.org), one of the original code review products. We just released Review Board 8, which was a pretty large project (we built Office document review, browser-native spell checking in CodeMirror, a new interdiff filtering algorithm, Forgejo integration, and a bunch of other things).
So now I'm working on plans for Review Board 9, with a goal of releasing within the next 4-6 months. Got some thoughts on how the review process can be rethought for this current era of development, so starting work on that.
Maybe AI was involved, maybe it wasn't. I don't know. But the author seems to know what he's doing, rather than someone just giving Claude a task and posting the result to GitHub. He talks through some of the challenges in building this, some of the different implementations he tried, the kinds of bugs and crashes he hit, and ultimately what worked and what didn't.
This is exactly the kind of stuff I love. Another comment said Claude has killed interest in crazy projects, but for me, as someone who likes to hand-craft some "why would you even think of that?" projects from time to time, discovering his repositories and YouTube has made my day.
We're still using it for our stuff (via our @beanbag/spina TypeScript wrapper for Backbone that has a few additional niceties), and I feel the same way. We can be as close to the DOM as we need (or let something manage it for our view for us), we can be smart about where data lives and how things interact with it/listen for changes, and we get a decent little object model that doesn't dictate how we think about everything.
Very happy still with the Backbone way of building webapps.
I'm pretty happy to see this, as conditionals can really help keep code manageable when trying to define CSS variables or other properties based on combinations of light mode, dark mode, high-contrast, contextual state in a document or component, etc.
if() isn't the only way to do this, though. We've been using a technique in Review Board that's roughly equivalent to if(), but compatible with any browser supporting CSS variables. It involves:
1. Defining your conditions based on selectors/media queries (say, a dark mode media selector, light mode, some data attribute on a component, etc.).
2. Defining a set of related CSS variables within those to mark which are TRUE (using an empty value) and which are FALSE (`initial`).
3. Using those CSS variables with fallback syntax to choose a value based on which is TRUE (using `var(--my-state, fallback)` syntax).
I recently implemented dark/light mode for the first time and was really surprised to find that in order to add a toggle I had to duplicate a both of vars/styles and use JavaScript. I'm looking forward to not having to deal with that cruft in the future.
Love seeing this one. My uncle was co-founder of Quarterdeck, and I grew up in a world of DESQview and QEMM. It was a big influence on me as a child.
Got a good family story about that whole acquisition attempt, but I don't want to speak publicly on behalf of my uncle. I know we've talked at length about the what-ifs of that moment.
I do have a scattering of some neat Quarterdeck memorabilia I can share, though:
This is a great feature for those who want a mix of positional and keyword-only arguments.
I should have mentioned originally (and I've since updated my post) that this and the kw_only= flag both require Python 3.10 and higher, so code that works with older versions can't opt into it yet.
That's annoying for sure. Though a different problem.
All the kw_only=True argument for dataclasses does is require that you pass any fields you want to provide as keyword arguments instead of positional arguments when instantiating a dataclass. So:
obj = MyDataclass(a=1, b=2, c=3)
Instead of:
obj = MyDataclass(1, 2, 3) # This would be an error with kw_only=True
The problem you're describing in boto3 (and a lot of other API bindings, and a lot of more layered Python code) is that methods often take in **kwargs and pass them down to a common function that's handling them. From the caller's perspective, **kwargs is a black box with no details on what's in there. Without a docstring or an understanding of the call chain, it's not helpful.
Python sort of has a fix for this now, which is to use a TypedDict to define all the possible values in the **kwargs, like so:
from typing import TypedDict, Unpack
class MyFuncKwargs(TypedDict):
arg1: str
arg2: str
arg3: int | None
def my_outer_func(
**kwargs: Unpack[MyFuncKwargs],
) -> None:
_my_inner_func(**kwargs)
def _my_inner_func(
*,
arg1: str,
arg2: str,
arg3: int | None,
) -> None:
...
By defining a TypedDict and typing **kwargs, the IDE and docs can do a better job of showing what arguments the function really takes, and validating them.
Also useful when the function is just a wrapper around serializing **kwargs to JSON for an API, or something.
But this feature is far from free to use. The more functions you have, the more of these you need to create and maintain.
Ideally, a function could type **kwargs as something like:
And then the IDEs and other tooling can just reference that function. This would help make the problem go away for many of the cases where **kwargs is used and passed around.
I don't see a point in using them in new code when I could just use a dataclass (or Pydantic in certain contexts). I've only found them useful when interfacing with older code that uses dicts for structured data.
That's always the challenge when iterating on interfaces that other people depend on.
What we do is go through a deprecation phase. Our process is:
* We provide compatibility with the old signature for 2 major releases.
* We document the change and the timeline clearly in the docstring.
* The function gets decorated with a helper that checks the call, and if any keyword-only arguments are provided as positional, it warns and converts them to keyword-only.
* After 2 major releases, we move fully to the new signature.
We buit a Python library called housekeeping (https://github.com/beanbaginc/housekeeping) to help with this. One of the things it contains is a decorator called `@deprecate_non_keyword_only_args`, which takes a deprecation warning class and a function using the signature we're moving to. That decorator handles the check logic and generates a suitable, consistent deprecation message.
That normally looks like:
@deprecate_non_keyword_only_args(MyDeprecationWarning)
def my_func(*, a, b, c):
...
But this is a bit more tricky with dataclasses, since `__init__()` is generated automatically. Fortunately, it can be patched after the fact. A bit less clean, but doable.
So here's how we'd handle this case with dataclasses:
from dataclasses import dataclass
from housekeeping import BaseRemovedInWarning, deprecate_non_keyword_only_args
class RemovedInMyProject20Warning(BaseRemovedInWarning):
product = 'MyProject'
version = '2.0'
@dataclass(kw_only=True)
class MyDataclass:
a: int
b: int
c: str
MyDataclass.__init__ = deprecate_non_keyword_only_args(
RemovedInMyProject20Warning
)(MyDataclass.__init__)
Call it with some positional arguments:
dc = MyDataclass(1, 2, c='hi')
and you'd get:
testdataclass.py:26: RemovedInMyProject20Warning: Positional arguments `a`, `b` must be passed as keyword arguments when calling `__main__.MyDataclass.__init__()`. Passing as positional arguments will be required in MyProject 2.0.
dc = MyDataclass(1, 2, c='hi')
We'll probably add explicit dataclass support to this soon, since we're starting to move to kw_only=True for dataclasses.
Generally-speaking, you probably shouldn't have to deal with these problems unless you're writing a tool that has to interface with certain SCMs or SCMs used in certain environments. I'll give you some examples for each of these points:
1. There are two important areas where encoding can matter: The filename and the diff content.
Git pays attention to filename encoding, but most SCMs don't, so when a diff is generated, it's based on the local encoding. If there are any non-ASCII characters in that filename, a diff generated in one environment with one encoding set can end up not applying to another (or, in our case, not being able to be looked up from a repository). This isn't common but it can happen (we've seen this on Perforce and Subversion).
Then there's the content. Many SCMs will actually give you a representation of a text file and not the raw contents itself. That text file will be re-encoded for your local/preferred encoding, and newlines may be adjusted as well (`\r\n`, `\n`). The text file is then re-encoded back when pushing the change. This allows people in different environments to operate on the same file regardless of what encoding they're working with.
This doesn't necessarily make its way into the diff, though. So when you send a diff from a less-common encoding to a tool to process it, and that tries to apply it to the file checked out with its encoding, it can fail to patch.
The solution is to either know the encoding of the file you're processing, or try to guess it (some tools, like ours, let you specify a list of preferred encodings to try).
It's best if you can know it up-front.
Bonus Fun Fact: On some SCMs (Perforce comes to mind), checking out a file on Windows and then diffing it Linux via a shared mount can get you a diff with `\r\r\n` newlines. It's a bad time and breaks patching. And it used to come up a lot, until we worked around it.
Also, Perforce for a while would sometimes normalize encodings incorrectly and you'd end up with BOMs in the diff, breaking GNU patch.
2. It does when you're working with them directly for applying and patching. If you're handing them off to a tool for processing, if there's any risk of one file in a sequence not being included, you can end up with breakages that maybe you don't see until later processing.
It's also just really nice having all the state and metadata up-front so we can process it in one go in a consistent way without having to sanity-check all the diffs against each other.
When working locally, it also depends on your tooling. `git format-patch` and `git am` are great, but are for Git. If I'm working with (let's just say) Subversion, I need to do my own thing or find another tool.
3. It's critical for the kind of information needed to locate files in a repository. Some systems need a commit-wide identifier. Some need per-file identifiers. Some need a combination of the two. Some need those plus additional data not otherwise represented in the path or revision (generally more enterprise SCMs targeting certain use cases).
It's also critical for representing information that isn't in the Unified Diff format (namely, anything but the filename). So, symlink information, file modes, SCM-specific properties on a file or directory, to name a few. This information needs to live somewhere if a SCM provides it, and it's up to every SCM to choose how and where to store that data (and then how it's encoded, etc.).
> Then there's the content. Many SCMs will actually give you a representation of a text file and not the raw contents itself. That text file will be re-encoded for your local/preferred encoding, and newlines may be adjusted as well (`\r\n`, `\n`). The text file is then re-encoded back when pushing the change.
Yeah, don't do that.
> This allows people in different environments to operate on the same file regardless of what encoding they're working with.
No it causes hard to understand bugs because now what people see on their device and what is tracked in source control differs, defeating the entire purpose of having source control in the first place. This isn't theoretical at all btw.
> The solution is to either know the encoding of the file you're processing
In general, there is no such encoding - source control tools need to be able to deal with files not valid in any single encoding.
I agree with your point about "winning was the default state." I joined during the Diane Greene era and left in the Pat Gelsinger era, spoke to all three CEOs at different points in one-on-ones, and learned a lot about how different people approach the challenges of running a company and listening to employees.
Pre-Broadcom, sort of toward the end of my time there, there was a lot of unintended self-sabotage that didn't need to happen. We lost people that we shouldn't and shot ourselves in the foot for some really dumb reasons, which just a bit more coordination could have prevented. There were some innovative ideas that got lost in all this, and I believe could have fueled VMware's product line and put it in the right positions for where the sector ultimately went. Alas.
reply