2,814 karma · joined August 2, 2019
Consider me skeptical.
It's also amazing what a "sorry, x,y, and z are very hard for me, I'm doing my best and still learning to do better" will go. Of course, not everyone receives that with grace, but that speaks to their character.
...you do know you can reject the position, correct? You're not obligated to take the job once the interviewing process has started.
There's the pitch.
Most of the time people aren't trying to be jerks. They're just not having a need met. They may or may not know about the need, or may or may not be working to address it. It may be something that you're responsible for that you're not acknowledging.
Don't underestimate how far a little humility, open ears, and boundary setting might get you. Writing the person off as a jerk just makes the problem worse.
Not to say you're responsible for anyone elses bad behavior, but it's also not ok to pin all the problems of team dynamics on one person. Having a emotionally healthy productive team is a lot of work, and it's a group effort.
I'm not saying it's right/wrong, just that no evidence was presented.
Second, I felt a lot of empathy for this, having gone through a similar situation, ultimately the company getting acquired during the pandemic.
I've learned many things, but I think I can share one takeaway that might resonate in this conversation:
Know thy users.
Keep the people that are directly using the software in mind. In times of corporate strife: remember the users. Let their happiness be your guiding light.
There are real people that depend on the software we write. Regardless of how any corporate decision turns out, those people will always be thankful that you made their day to day lives a bit easier.
Find the disproportionate pain points. That one preference that were it defaulted differently would save 90% of users a one time frustration when on boarding. That one janky error message that no one understands. Fix that sort of stuff, the stuff that users are interacting with regularly.
At the end of the day, unless you're contractually entrenched at oracle levels, if the users aren't happy, then whatever corporate structure that puts food on your table probably wont do well. They may not do well if users are happy, but very likely wont if users are angry.
Any given change might not matter to your executives, but they matter to your users, keep them in mind and heart and you'll know what to do. And periods of corporate strife like in the article are a great time to actually get that sort of stuff prioritized, because no one can say anything else is more important.
This is what lifetime appointments were intended to address. There's no incentive to rule in the president's favor. Of course, now there's the prospect of gratuity for services rendered.
I looked into what it would take to tackle it from the source code, There were some barriers, like the jars not really being published to maven, but the biggest just being the time & energy investment to pick up java again.
I'll definitely be looking into this project and seeing if there's anything I can contribute back.
It's more geared towards the static elements of the system, and writing a spec feels quite like writing a relational database schema -- mostly because they're both expressions of relationships.
It seems like a pretty natural path to write a spec in alloy before building out some crud interface.
I think there's a huge tooling gap though. Alloy, TLA+ and friends all seem to be very jvm/UI centric, really targeting a user who is working in the editors the language ships with.
I'd really love to see more tooling to run model checkers in a CI pipeline, or generate stubs and test cases for various languages. If that were in place, I think there would be more stickiness to formal methods.
I've started writing a Go parser for alloy, in part to learn it better, in part because I know go and want to write some tooling that I think go would be a good implementation language for. I don't know if anything will come of it, but at least having a parser would allow for things like a formatter or code generator. If I were feeling ambitious, I might try to implement a model checker.
Given that methods sets are...sets. I'd be interested at a language level, what it would look like to add some notion of set difference or expressing disjointedness in some way, e.g.,
type ReadOnly retraction {
Write([]byte) (int, error)
}
type ReadOnlyFile struct {
ReadOnly
*File
}
where `ReadOnlyFile` would have all of `*File`'s methods minus the methods defined in `ReadOnly`restriction probably isn't a good term, I could see it easily being misinterpreted, but I haven't all day to ponder it :)
(edit: after publishing I realized `retract` might be more clear)
I don't know if it would ultimately simplify the problem or not, but I agree that having some way to easily mask or hide a method subset could be quite nice.
Edit:
I want to add that the idiomatic thing to do now would be
type ReadOnlyFile File
/ *proceed to implement every method you want accessible */
maybe something like the following could be possible type ReadOnlyFile retracts *File {
Write([]byte) (int, error)
}I think another other route is to provide lots of tooling to inspect the object graph -- include a pretty print function in the interface or something to that effect.
There's equivalency between the two, the struct with pointers to implementation functions can implement an interface. Likewise, the implementation functions may call other implementations, so you haven't exactly solved the proxy problem, the state controlling which implementations becomes function local instead of on a struct. Unless you start to provide a struct with all of the context, at which point you've actually re-invented interfaces. I've grown wary of having too much of the details as function local like this because it hinders making more advanced tooling by hiding intermediate state from reflection.
The interface provides the means to give other representations, and allows for embedding one within another, and gives runtime tooling to inspect underlying types. It gives more elegance and flexibility to the problem at language and standard library scale.
One of the nice things is that it gives a sort of bidirectional refactoring path. If someone chose struct-of-pointers and it's at it's breaking point, those structs can stay as is and start to implement the interface with minimal effort. Likewise, if I need to boil down a hodgepodge of implementations into a really simple control flow, struct methods capture the struct and can be passed around as ordinary function pointers, so I can built a struct out of existing interface implementations.
There's no real way around the complexity -- leaky abstractions are a thing. I think the author got it right: use interface upgrades and proxies sparingly. If they are the right tool for the job, then it's probably a good idea to go the extra mile to provide good documentation and instrumentation with extra attention to caller/callee expectations.
It's in the category of "you better have a damn good probable cause" if you want to forcibly intervene with publishing.
The point was that no, you wont (necessarily) get some "average" shakespeare. A sampler may introduce bias and look for the "above average" shakespeare in the distribution.
I'm curious how you see the project evolving as you add those things. How do you see it differentiating itself from rails or django?
They're the worst. A noise pollution posterchild.
It's in a better situation now than it was. I hope.
...So what color is their gopher?
it really enabled end to end level testing as well as being able to stand up development instances quickly.
It's a fairly fractal pattern in distributing computing. Move the high throughput heavy computation bits away from the low latency responsive bits ("low latency" here is relative to the total computation). Use an event loop for the reactive bits. Eventually someone will invert the event loop to use coroutines so everything looks synchronous (Go, anyone? python's gevent?).
After it seems to me that the only real question is if takes too long or costs too much to move the data to the storage location the heavy computation hardware uses. There's really not much of a conceptual difference between airflow driving snowflake and c++ running on a cpu driving cuda kernels. It takes a certain scale to make going from a OLTP database to an OLAP database worth it, just like it takes a certain scale to make a GPU worth it over simd instructions on the local processor.
I imagine we'll get to a point where CPUs are actually just pretty dumb drivers for issuing gpu commands.