Counterpoint: k8s is a bad orchestration system with bad scaling properties compared to the state machine versions (Borg, Tupperware/Twine, and presumably others). I say this as someone who has both managed k8s at scale and was a core engineer of one of the proprietary schedulers.
HN user
kernelbandwidth
OpenAI Supercomputing Orchestration TLM
Assertions don't actually have to kill the program. They send an abort signal, which means you can catch them with a signal handler.
I similarly wrote a simple C testing framework for a little project I was working on, based on assertions. The framework uses signal handlers for aborts and segfaults, and then setjmp/longjmp to handle resuming the test suite at the next test case. This has the particularly nice effect of turning segfaults into (marked as such) test failures, instead of just terminating everything. It probably wouldn't be too hard to fit custom messages in too, but I hadn't felt the need yet.
Missing Stephenson's The Diamond Age was a bit of an oversight as well, considering that Snow Crash is one of the canonical Cyberpunk novels, while The Diamond Age is (IMO) a defining Post-Cyberpunk novel. The Diamond Age opens with a Cyberpunk fake protagonist written with every Cyberpunk trope in mind, and then the fake protagonist is killed off before the end of the Prologue and the real protagonist, the slain punk's baby daughter, is revealed. Stephenson's intent is clear: "This is not a cyberpunk novel."
I'd also argue that Cyberpunk does not mean "everything is terrible", nor does Post-Cyberpunk have a softer and lighter view where "not everything is terrible." Rather, the difference is whether social control is rooted in 1984 or Brave New World.
From this point of view, Ghost in the Shell and Minority Report are still Cyberpunk (edit: settings); the viewer is just seeing things from a point of view other than the completely marginalized. Shadowrun is a Cyberpunk setting whether you work for a corporate power or in the streets.
It's funny to consider that one of the canonically great philosophers in history is known essentially by the equivalent of his WWE wrestling name. It's like if in the future there were classes taught on the philosophical ideas of "The Rock".
As an adventure game lover, I think this is a great little game! I love dark, macabre adventure games and I'm really digging the art style here. The mood is very consistent and the creepiness really comes across. Your daughter has done a great job!
This is supposedly a feature and not a bug of CAPTCHA, at least according to the apocryphal story John Lafferty told me. IIRC, this was at CMU so he must have been referring to the 2003 CAPTCHA claim by von Ahn et al. The idea was primarily to stop spammers, but also secondarily to make them more useful. The argument was that if spammers managed to "break" CAPTCHA, then whatever technology was used to break it would necessarily be a useful (compared to 2003 knowledge) advance in AI, so it was a win-win whether it stopped spammers or just made them do free out-of-band research.
I'm not saying it was all bad, just, you know, mistakes were made.
I had not really considered the design patterns of the culture vs the design patterns of the language; this is a very good point.
I can pretty much prove that they don't: https://github.com/thejerf/suture It's the process that needs monitoring, and that process may have 0-n ways to communicate. But that's not a criticism of Erlang, as I think that's actually what it does and it just happens to have a fused message box per process.
One, very neat library. Two, while I agree this proves the point that the actor model is not needed in the language to build a process supervisor, I think that your Go Supervisor looks a lot like an actor, at least in the way Erlang/Elixir uses them. From what I can see, the Supervisor itself works by looping over channel receives and acts on it. The behavior of the Supervisor lives in a separate goroutine, and you pass around an object that can send messages to this inner behavior loop via some held channels. So basically the object methods provide a client API and the inner goroutine plays the role of a server, in the same separate of responsibilities that gen_* uses.
If we squint a little bit, actors actually look a lot like regular objects with a couple of specific restrictions: all method calls are automatically synchronized at the call/return boundaries (in Go, this is handled explicitly by the channel boundaries instead), no shared memory is allowed, and data fields are always private. I'm sure this wouldn't pass a formal description, but this seems like a pragmatically useful form.
I agree that Go is less actor-oriented than Erlang/Elixir, but given how often I've seen that pattern you used in the Supervisor (and it's one I have also naturally used when writing Go) I'd argue that "Actor" is a major Go design pattern, even if it doesn't go by that name. The difference then, is the degree to how often one pulls out the design pattern. I think the FP aspect pushes Erlang/Elixir in that direction more, as this "Actor" pattern has a second function there -- providing mutable state -- that Go allows more freely.
This discussion has really made me think, thanks. I think you're right that actor-like features are valuable and that the Actor Model in the everything-is-an-actor is not itself the value (or even a positive).
This is pretty funny.
"Did Millennials kill fashion?" one of those headlines reads.
No, I've seen what y'all did in the 80's and 90's. If Millennials killed fashion, it was a merciful death after that.
Would you call Erlang/Elixir actor-based or just having actor-like features?
Actors in Erlang seem more emergent to me than fundamental. To first order, Go and Erlang use similar concurrency strategies with cheap green threads and channels for communication. The main difference being that Go has channels as separates objects that can be passed around (leaving the goroutine anonymous), while Erlang fuses the channels into the process. In this respect, they both have similar levels of "actor-ness" in my mind. The biggest upside that I can see to channels being separate is that a goroutine can have multiple channels, they can be sent around (though so can PIDs), etc. This matters a lot because the channels in Go are statically typed, while Erlang/Elixir's dynamic typing makes this less meaningful since you can send anything on the same channel.
Of course, I supposed if one defines an actor as a sequential threaded process with a built in (dynamically-typed) channel, then Erlang is actor-based, so maybe I contradicted myself. In Erlang/OTP, the actor part is important to the supervision tree error handling strategy, which I think is the biggest upside, but it's not obvious to me that you need the channel and the process totally fused together to handle that.
Specifically in response to your "cheap concurrency good, actors bad" thought, my hypothesis is that actors are at least the more natural strategy in a dynamically typed language, which is why they seem to work well in Erlange/Elixir, but don't see much use in languages like Haskell (or Scala, it seems, where I at least though the Akka actors were kind of awful). Meanwhile, channels seem to fit better with static typing, though I can't quite put my finger on why.
The request for use cases in Go seems a bit like begging the question to me. Since Go doesn't have generics, anything designed in Go will necessarily take this into account and design around this lack. So it's relatively easy to show that Go doesn't have a compelling use case for generics, since the designs implemented in Go wouldn't (usually) benefit from generics!
Rust has generics and traits/typeclasses, and the result is my Rust code uses those features extensively and the presence of those features greatly influences the designs. Similarly, when I write Java, I design with inheritance in mind. I would have trouble showing real world use cases for inheritance in my Rust code, because Rust doesn't have inheritance and so the designs don't use inheritance-based patterns.
Essentially, how does one provide real world evidence for the utility of something that's only hypothetical? You can't write working programs in hypothetical Go 2-with-generics, so examples are always going to be hypothetical or drawn from other languages where those tools do exist.
This is so very true. I find Scala tends toward the classic "read-only" joke. You can write very powerful code, but it's often hard to debug and it tends to be quite difficult to read down the line. We have a Scala application that is being slowly replaced, but which I maintain in the meantime, and it is by far my least favorite job duty, despite that I theoretically like Scala more than, say, Java.
Probably my biggest disappointment with Scala is really the type system. It's incredibly powerful, but it's unwieldy to use, and it's still full of footguns. "object" is great and useful until someone accidentally turns it into a giant race condition (true story). Traits can easily turn into a maintenance nightmare (ever seen an 8-way multiple inheritance scheme that fans out into 23 separate ancestor classes? I have!) Exceptions end up in a strange territory. There's ways to handle all of this (much of it involves "don't do that!"), but the point is that for all the type system's powers, it's not actually buying you that much except in comparison to Java 6/7. If I want powerful type magic, I can use Rust or Haskell or similar and get stronger guarantees from my compiler. If you're writing "better Java", which is traditionally one of the more common Scala uses, it's harder to justify over Java 8 or Kotlin these days.
All of which is to say, Scala is a really cool language, but I wouldn't write new projects in it if I didn't have to.
Bonus round: We had a Scala iOS app via RoboVM before RoboVM support was yanked. It still gives me nightmares.
This is my neo-Luddite response to a lot of "there should be an app for that" kind of comments: "Have you tried using a pencil?"
There's lot of reasons to use computers, but there's also a large problem space where it's really hard to beat pencil and paper. They even usually come pre-installed in most offices and homes.
Strictly technical? Determining the existence of metastable states for the T-cell receptor protein in solution (PhD Dissertation topic). Sort of difficult science, though it seems quite easy in retrospect now; the project wasn't so much hard, as it just cut across a lot of disciplines. Poor developer interview answer though, as it didn't involve a lot of software development (lots of TCL scripting for data extraction and ML with Python instead).
The answer I used to use was a problem I had working as an R&D intern: determine when the speed limits posted on a street have changed from measurements of driver behavior. Interesting and fairly tricky ML problem (weather is a big confounder). Ended up writing a lot of C to get high enough performance to make the solution reasonable which was educational (I didn't know a lot of C at the time), but almost certainly not the right approach to the performance problem. Still more science than development, so it depends on who's asking.
Probably the hardest business-type technical problem I've encountered is database restructuring. We moved (a subset of our data) from a NoSQL database to SQL as part of larger architectural changes, and mapping, migrating, and maintaining compatibility has been non-trivial.
The hardest problem I've encountered has been helping to rescue a project with a severely dysfunctional development history. Much more project management and people than technical (it was just a CRUD app) but I came into a project that had been in development for a year or so and stalled out. The development was outsourced and I fell into a position as a liaison between the internal folks at the university that wanted the product and the dev team that had been hired to build it. Sort of a classic issue where the dev team and the stakeholders would talk right past one another. It drove me crazy at the time, but an excellent experience in retrospect. And it has a happy ending; the project went on to be successful after that, at least when I last heard.
Well, one major advantage for the Rust compiler is that it compiles Rust code, which I happen to have a decent bit of.
Joking aside, I'm not arguing that the Rust compiler is "better" than any other compiler. The Rust team seems to have done a great job with it, but I'm neither a PLT guy nor a compiler writer so I can't profess an informed opinion there. What I am interested in though is the Rust language semantics (which the compiler enforces, just as every correct compiler enforces the semantics of the language it compiles). Rust-the-language provides benefits that we (my company's engineering team) finds to be valuable for writing our software -- a strong, flexible, static type system; Option/Result types; the ownership model that promotes good practices and prevents a lot of concurrency bugs that a GC would not help with; drop semantics which allow interesting and powerful techniques with smart pointers. As a bonus, Rust-the-ecosystem includes some excellent and ever growing tooling that lets us focus more on solving development and business problems.
As for Rust-the-compiler, others have already done a better job than I think I can, so I'll let those comments speak to the issue.
Other people accomplish great things with other tools. Rust works really well for us though, and I like to share that.
This is true if you're agnostic to or prefer dynamic typing. If you're using Node, that's probably true, but at the high level I tend to think of Haskell, OCaml, F#, and Scala as the comparisons.
As someone who likes neither dynamic typing or Ruby's syntax, I do agree that Elixir looks very cool, and have considered it for jobs that favor development speed over compile-time correctness.
Sure! This is us: http://www.litmushealth.com/
Our APIs are JSON and Avro based, if that's what you're asking.
The company does two major things: connect to sensor systems and collect data, and provide ML/Data Science/(other buzzwords for math) tools for clinical trials and medical studies. In many ways this means Rust is a "reasonable" but not necessarily "ideal" fit -- we could certainly afford the overhead of a GC, so the no-GC aspect of Rust doesn't really buy us anything major, though it does provide some nice performance and memory usage in the parts below us in the stack (Iron/Hyper, soon Tokio). That said, the more we get into the "big data" and ML stuff, the more value there is in having a good C FFI and good performance profiles.
We get a lot of value from the other aspects of Rust though. Traits (typeclasses) are powerful and flexible. More importantly, they promote that old, but good, Java ideal of "programming to interfaces" without all the other baggage. Rust's support for FP is quite good (though the lack of HKTs means there's no monads, at least not "actual" monads ala the Haskell Monad typeclass). The fact that Rust closures are actually traits means you can make some really smooth interfaces that transition from just a static function to a closure and finally to a 'proper' object.
The Macros 1.1 release recently and the Serde library hitting 1.0 have been a big deal. JSON APIs are trivial to write and get all the benefits of strong typing and Option/Result on the deserialization side.
One mistake I think people make with Rust is thinking that because you can do things in a really efficient style, you should. This leads to thinking that Rust isn't as good for "applications" work because you have to think about heap vs. stack allocations and lifetimes and such. But if you were going to use a GC, you can probably afford dynamic dispatch and some extra allocations anyway. Relax, clone the data/box the trait, and come back later if the performance matters. If you wrote the thing in Python, you weren't going to get a choice about boxing things and optimizing would be way harder anyway. Basically, if you treat Rust like an impure (and strict) Haskell or OCaml/F#, it'll actually work pretty well once you learn some idiosyncrasies.
Sorry, bit of a long tangent, but yes, like I said in the last comment, Rust asks a little more up front and in return you get better stability, correctness, and refactoring ability. Testing is easy, especially with unit testing built into the compiler flags and Cargo. Cargo really helps with the "works on my machine" issue and deployments. Pulling in libraries is painless, and while the ecosystem is still small compared to (for example) Java, it's growing, enthusiastic, and so far has covered what we need most of the time.
Ah, okay, that makes sense, particularly with the cross-platform aspect. Personally, my plan had generally been to just go with a client-server architecture. At least to start I'd only be targeting macOS in my hypothetical projects, so I had planned to just write the UI in Swift and Cocoa, and application logic in Rust. Unnecessarily complicated, but fun for a hobby project.
A lot of people describe Rust as a systems language (and it is!) and often that's followed up as a "better C". But it's also more than that!
Despite Rust looking a lot like C++ and often occupying a similar role as C, it's heritage is just as much that of an ML, and it shows in the semantics and type system. So while a lot of people do use it as a safer C, I often find it to be a "pragmatic Haskell".
My company does much of our back-end in Rust, and we've found it to be an excellent application language. A lot of this is the type system and the tooling. Cargo, the package manager and build system is excellent, builds are far more reproducible and I've spent far less time debugging builds (as opposed to code) than just about any other language I've used. Rust's type system is great if you like that kind of thing, and I find Rust to be particularly easy to debug and refactor. RAII and destructors/drop semantics come in handy more often than you'd think, and the "fearless concurrency" thing is real.
That said, lifetimes do occasionally cause some pain, the learning curve isn't the kindest, and the patterns are different from a lot of other languages. Personally though, I've found Rust to be very productive after getting over the initial learning hump and understanding the borrow checker more. This is gets more true the larger the project gets, as Rust tends (in my experience) toward the trade off of putting a fair bit of complexity up front in exchange for a slower accumulation of complexity as the project increases in size and scope. It's a trade off that I'm often happy to make, but is always a judgement call.
Have you tried Conrad? (https://github.com/PistonDevelopers/conrod)
I've not delved much into GUI programming in Rust myself, so I'm just interested to hear any arguments for/against. As a more general point, I suspect a good Rust GUI framework will end up looking more in the spirit of React and the FRP approach, as ownership and the tendency towards immutable data have less friction with that approach.
It's entirely possible I don't know what I'm missing and/or my React usage so far mostly falls in the "toy" scale, but I've not yet felt a need for Redux or another state management system. Our strategy so far involves very little use of component state (nearly all usage is for form fields and showing/hiding modals). Everything else is in the props, and all 'app state' lives in a collection of modules that get DI'd into the components via their props. It seems like it's probably not too far from what Redux is going for at a conceptual level, but so far it's worked well and been easy to work with.
We also use TypeScript though, so this more OO-style approach felt more natural. It's not particularly verbose (in the context of interfaces and static types, so YMMV) and it's been extremely easy to work with so far.
In Academia, it's not necessarily a Burmese Python. If you write a better dissertation, you'll get a smaller snake to face off with.
https://www.mcsweeneys.net/articles/faq-the-snake-fight-port...
In the same way that we're really only starting to learn patterns that make good use of affine typing, I think this will get easier as we discover better (for Rust) design patterns. Which is basically what you're asking for; I think we're still in a mixture of discovering and documenting said patterns because some standard approaches don't work the same.
So far, it seems to me that a lot of 'textbook' data structures require unsafe, at least to translate in a mostly 1:1 manner. I think more novel patterns will emerge around non-1:1 translations in safe code, which may push at least some data structures out of the 'advanced Rust' territory.
I recently ran into this myself while implementing an order statistic red-black tree in (safe) Rust, which shouldn't be particularly complicated, but has been a good bit more verbose than C++ or Java would have been, primarily because I did a lot of manual bookkeeping to avoid unsafe. Still, it was enlightening and I very much enjoy using Rust.
The very same trie code that I tried to write in Rust I wrote in one & half evenings in C++
Use unsafe. No, really, just use unsafe.
Clearly a big value of Rust is that it's a safe language, and the design patterns around safety and affine typing are emerging and good. We should want people to write and use safe code as much as possible. But the trie example seems, to me, to be very much the sort of thing unsafe is for. Writing in C++ is essentially doing everything in unsafe. Unsafe is not evil; it's an important part of the language and when it's called for, it's called for.
I could absolutely be atypical; prior to using Go and Rust as my main tools, I primarily wrote Scala, and I'm sure the functional and type-driven approaches have left deep grooves. But that would still be a way of approaching working with Rust, wouldn't it?
None of that is to make a value judgement, just an observation; but I would still argue that the language can be used in a highly productive manner. Nonetheless, it's perfectly reasonable to argue it's not worth adapting to it, especially if Go is already solving your problems and keeping you productive. I switched because Go's design doesn't seem to fit me very well, and I continually tripped on issues that I don't encounter in Rust. (So yes, perhaps I'm quite odd.)
I do understand the want for a Rust-lite; the thought has crossed my mind more than once. So far, Swift seems closest in many ways and may get close once the Linux/cross-platform story starts looking good.
I wonder if there's a cognitive anchoring effect. I've found Android Studio to be the best part of Android development, while Java and particularly Android itself being quite painful. XCode, on the other hand, I've found to be particularly painful, while iOS is much easier to work with, and Swift is one of the most pleasant languages I've used, so XCode looks bad in context, while AS looks much better.
I think this might depend a lot on how you approach Rust. I find the functional/procedural mixture to work nicely, and find I'm much more productive in Rust than Go (or Python or Java, modulo available libraries). I'm writing web services and code generators, so not particularly low-level code.
I've written a decent bit of Go, and I understand why a lot of people like it, but I don't think it's inherently better for application development.
Absolutely. A brief story on tech debt from the top:
One of the more frustrating things I've experienced is when I got push-back for implementing more project management process (we have a very light process, but when I took over it was sticky-notes-on-the-desk level). The complaint was "we can't slow down development to do more process". Very through-the-looking-glass, as I, the Engineer, was arguing for more management process and Leadership wanted less.
But of course, accurate estimates were needed, just, you know, without making measurements. I implemented some process anyway. We actually increased development speed from less churn and lowered communicated (consult docs before breaking someone's flow), improved estimates, and we've been able to better contain our tech debt.
Yes, this. One of the big things I talk about with sales is the difference between changing a priority for a customer vs. adding distinct new things. As a recent example, a client wants better and faster feedback on the trial they're conducting (we're in the med-tech space), and we've already got a new dashboard designed and on our product roadmap. I'm more than happy to prioritize that over other product pieces if it'll get us the contract, because we're already going to do it, we're only changing the 'when'.
On the other hand, when they ask for something off the roadmap, we get into more complex issues (is this market-demand data, or custom work?) Particularly for grunt-level custom work (say, adding a support for tracking data on a niche wearable device that we don't currently support) there's a lot more questions that follow.
One of the most insidious of the latter, IMO, is that if it's just for one contract, then we're either hiring contractors/outsources (expensive, high management overhead), hiring new engineers (risky to grow headcount on a whim), or redirecting resources to tasks that are likely to have both lower ROI and provide lower growth for the re-tasked engineer. At our small size and need for high-quality people, I consider this to be a real cost too.
Sure, but the answer is pretty trivial: If you spend more than half your time on customization, you're a professional services shop.
He also added that if you're a product shop doing less than 70% off-the-shelf, you're probably screwed, while 90% off the shelf is really the ideal (again, enterprise software).
I think the more interesting question is "what counts as professional services?" This gets much trickier, for example when you start building out APIs to make second- or third-party integrations easier, is that "product" or "professional services"? It certainly seems like product building, but if you're doing for a customer's use, it gets real blurry real fast. If you're not using that API internally, you're almost certainly on the professional services side. If you do use it internally, is it rock solid enough that you can support and expose it without that support becoming professional services?
Drawing sharp lines aside, this all probably seems kind of trivial, but the first time I ran through our product design with him and we discussed this, I went back and radically re-thought a lot of our strategy, particularly at the customer interfaces.