Hacker News new | past | comments | ask | show | jobs | submit login
Microsoft Orleans – An approach to building distributed applications in .NET (dotnet.github.io)
175 points by hitr on July 16, 2016 | hide | past | web | favorite | 65 comments



"actors are called ‘grains’,"

If you can write a sentence "X are called Y", and X is more well-known, drop Y.

"You can then send messages to the grain by creating a proxy object, and calling the methods: var grain = GrainClient.GrainFactory.GetGrain<IMyGrain>("grain1"); await grain.SayHello("World");"

var brain = BrainClient.BrainFactory.GetBrain<IMyBrain>("brain1"); await brain.Say("WTF");


I share your sentiment.

I'd been away from .NET/C# for a few years and came back to find that they dialed the abstraction level to 11.

I adore C# as a language but I find myself increasingly alienated by its generally accepted coding style.

I find that Microsoft's products have extremely unintuitive naming schemes at both a low level (language, standard libraries) and a high level (.NET product word salad naming schemes, Office 365 referring to a diverse and inconsistent range of products...).

The skeptic in me thinks that this may be an attempt at educational lock-in.

The lines between marketing and technology have definitely been blurred.


Seems to me all big software houses are affected of this in their long standing products. You start a new thing and come up with a good name. 15 years with 17 product cycles down the line and you have a whole forest of names that have some relation to this thing.

See also:

iTunes (OSX), iTunes (iOS), "Music" (iOS), Apple Music, iTunes Match, Genius and the iCloud Music tab. Podcasts and videos are also all in there somewhere, know what dear user, you figure it out k?


They brought in very highly paid, smart engineers. Which have periodic performance reviews. If they don't we "we designed and implemnted X, Y, Z awesome new abstractions / features" everyone in the room bosses, employees, higher ups, marking it going to feel let down. So, we have ever more features.

"Say, Steve, what have you been doing last year?" - "Welp, just making sure things work, fixed some bugs, documentation, took customer calls. The product essentially works, people love it". "Wait, so we haven't shipped any new features, hmm, ok...".

vs the response of "We implemented fizz, bar, quux features. We tore down old zig and added zag instead. It is really the same as old zig, but now look green and re-written with latest framework we saw in HN headlines". "Oh great, you get a promotion and a raise".

I am being a bit silly, but it is only half-joking, it is how software industry often works.


Try using F# if you don't like the verbosity and over-OO-abstraction. It's fantastic.


I'll be sure to give that a shot, thanks for the tip. You've made me realize I've somehow been subconsciously avoiding F# for whatever reason.


Agreed. Subconscious reasoning is the worst.


It's not just Microsoft, though I agree they are really bad at naming. There are plenty of examples of similarly obtuse naming in open source. Storm, with its spouts and bolts, comes to mind.


> abstraction level to 11.

Let's break the problem down.

You have a language that doesn't natively support actors or message passing. You can solve this by having the developer stub each method (`this.DispatchActorMessage(...)`) or you can implement the interface on behalf of the developer (`Factory.CreateProxy<T>()`). Microsoft doesn't always use the runtime emit approach and, as someone who has used both approaches[1][2], runtime emit is far preferable. This means that something in your code has a responsibility to create actor proxies. That's the first concept: the responsibility to create actor proxies. Not only that, but so far as Reliable Actors go the proxy needs to do quite a bit of work: actors can be rescheduled to another machine and the proxy needs to continue representing that single durable instance.

You also have context: "which cluster controls this actor?" Depending on your scenario you might be able to assume that there is no context. Microsoft cannot make these assumptions because federation is quite important in the enterprise. In fact, the ability for Reliable Actors to have context [will] allow our customers to extend our product without us worrying about noisy neighbors (they are in charge of their own actor cluster, we simply federate to it). Additionally, there are scenarios where the consumption of an actor occurs outside of the context. For example: calling an actor from a GUI app.

In order to create the actor, you're going to have to use the object with that responsibility (unless you fancy doing the emit yourself): `ActorFactory.Create<IBrainActor>()`. You then need to pass in the context. Orleans uses a `Client` instance (which should make sense to .Net developers), while Reliable Actors pass the context into the `Create` method. So either: `Context.Factory.Create()` or `Factory.Create(Context)`. Nothing more than a stylistic choice necessitated by the requirements that Orleans and Reliable Actors don't share.

The goal here is not to replicate Erlang. It is to make a framework where developers can write distributed systems with a low amount of ceremony. Actors so happen to be the best candidate as a primitive but are most certainly not the be-all and end-all of Reliable Actors (which were inspired by Orleans, so I assume the goal is the same for Orleans). In that way, it makes some things far simpler than Erlang[3] but there's always a cost to that. If distributed systems is the primary goal, then you're going to have overhead if you are not creating a distributed system.

If you're talking about terrible naming, that outright I can agree with. Orleans, however, is no more and no less abstracted than it needs to be.

[1]: https://msdn.microsoft.com/en-us/library/system.diagnostics.... [2]: https://azure.microsoft.com/en-us/documentation/articles/ser... [3]: http://erlang.org/doc/reference_manual/distributed.html


Apologies for the late reply. I appreciate the in-depth explanation of what's going on with that code, as I've been under too much pressure to delve into it. Thanks for putting in the effort.

I must confess that I sort of lumped several criticisms together there, conflating API nomenclature, with product nomenclature, with abstraction, as one tends to do when speaking semi-casually.


I suspect the F# interface will not only be more to your liking, and probably be trivial to tie in with MBrace which is a pretty damn great library.

All C#/Java style static typing code not only looks like that, but often calls it "best practice."

Worth noting that "await" use is quite elegant in what it does here.


I think that because its a virtual actor with different characteristics that regular well known actors it might be a good idea to call or differently to avoid confusion.


'X are called Y' normally means X is mostly like Y, but differs in some key fundamental ways. Anyone who doesn't know about X doesn't care of X/Y. But if you call it X, anyone who knows about X, will have to regularly have WTF moments, because even though it is called X, it is not behaving like one.

e.g. javascript classes/inheritance/OOPs in general.


> "You can then send messages to the grain by creating a proxy object, and calling the methods:

  var grain = GrainClient.GrainFactory.
    GetGrain<IMyGrain("grain1")
  await grain.SayHello("World");

  var brain = BrainClient.BrainFactory.
    GetBrain<IMyBrain>("brain1");
  await brain.Say("WTF");

Heh, Erlang:

  GrainPid ! "HelloWorld"

  BrainPid ! "WTF"


   do! GrainPid <! "HelloWorld"
via Orleankka F# https://github.com/OrleansContrib/Orleankka/blob/master/Sour...

stilll a bit more verbose than erlang though


You left out the code that gets the Pids, which is what the c# version is doing.

Otherwise it's just

await grain.SayHello("World");


Ah good point! It is even simpler then ;-)

  grain1 ! "HelloWorld"

  brain1 ! "WTF"


Nope.. grain1 is not defined in that sample ;-)


Neither is IMyGrain and IMyBrain in the original. grain1 is a perfectly valid name for a registered process. When using OTP's gen_server abstraction, it will even auto-register the the process during initialization.


They are not traditional scores. They are virtual and the terminology changes to reflect that


That's just bading coding style, most C# code is not that verbose and crazy.


Many people like C# because compared to Java it's about half the verbosity - C# is still a very limited language with plenty of verbosity and tedium built in, something like F# just blows it away in comparison (even more than C# does Java).

Not to mention that the standard OO cult of unit test / mock everything and make everything "reusable" leads to such shitty designs that almost fall out naturally from the language/paradigm. Oh and the one class per file with 3 method interfaces and 10 ceremony lines with namespaces and import definitions/braces.

I prefer C# over Java, and in some cases even over F# (it's slightly lover level and therefore it's simpler to control for things like heap allocation) but it usually is that verbose and crazy in the real world from my experience.


> Not to mention that the standard OO cult of unit test / mock everything and make everything "reusable" leads to such shitty designs that almost fall out naturally from the language/paradigm.

Not sure I'd call it a cult. From an F# perspective I do it this way:

* REPL-driven work to get it up and running

* Unit tests to protect what needs to be correct against change

* Mock the service boundaries

* Expose object-oriented layer to C#/VB consumers

Unit tests, mocking, and reusability are good things. Overuse (e.g., mocking to make sure that X calls Y in some business logic engine) is just what it is - overuse. Users of functional languages have their own problems, like suffering from code golf and over-using partial application. I wouldn't call one any worse than the other, it's just the functional crowd is smaller so you see it less.


There are a bunch of "preachers" who advocate "best practices" which are rarely presented as "we had A and B problems and X worked out better than Y", instead it's "X gives you 1/2/3/4 over Y and therefore X is better", and the community follows along - cult like. Limited nature of language helps promote these "patterns" and "best practices" because it's often hard to find a better solution and much simpler to just apply them indiscriminately, and you end up with verbose and crazy code that the C# ecosystem is full of.

I agree that both have their own issues but I do think one is better than the other, F# is more succinct (without turning in to code golf) and (actually) being multi paradigm avoids cases where OO just doesn't fit well. With micro services, actors, distributed computing, etc. those cases are expanding.


> Not to mention that the standard OO cult of unit test / mock everything and make everything "reusable" leads to such shitty designs that almost fall out naturally from the language/paradigm. Oh and the one class per file with 3 method interfaces and 10 ceremony lines with namespaces and import definitions/braces.

This is the bad coding style I'm talking about... C# is pretty great but it cant stop people from just writing more for no reason.


You haven't seen a lot of C# code then... in my experience, as the sibling comment points out, it's slightly better than Java, but what I've noticed is that C# is gradually becoming more abstract and "enterprisey" while Java is actually getting better, moving in the other direction.


Not sure what you expect to happen here though. Just like Akka or Erlang named services, what's happening here is you're asking the runtime to find (or in this case perhaps instantiate) an instance and proxy for said instance of the class.

You're calling the global reference, asking it to give you a proxy to that object, and you need to mention somewhere in the line what type you expect. Without a stronger type system or a complete abandonment of type safety, the most you could do is shorten this by 1 term and move the type from the template term to the left (something has to assert the programmer expects IBrainStuff).

The only other way to do this is explicit code generation (ugh) or implicit code generation (e.g., F# type providers). Which is why in a sibling comment I mentioned I think that an F# binding to this library would be generally more acceptable for people who dislike that kind of abstraction, because the type system can do a lot more to help.

Erlang's model of actors and messages isn't "enterprisey" and this isn't "enterprisey" code, this is just "sufficiently complex OO code." If you like strongly typed OO languages, this style of coding is your nemesis and your hero at the same time.


Rule number one of the distributed systems academic circus it to introduce at least one new term in an effort to create a new buzzword (because as we all now, a lack of buzzword is holding back breakthrough of concepts).

Preferably, all established terms should be replaced by buzzword candidates.


In the same vein, I have not yet found anyone who knows why after 30 years or so of use, Microsoft decided to rename "locale" as "culture".


Orleans calls them grains to differentiate them from actors in the Akka/Erlang sense - because they are Virtual Actors, rather than traditional actors.


Orleans is just fantastic.

343 Industries famously used Orleans for Halo 4 backend services infrastructure. Caitie McCaffrey's presentation can be found here: https://www.infoq.com/presentations/halo-4-orleans

You may be interested in Obit ( https://github.com/orbit/orbit ). It is inspired and based on Orleans, except it's written in Java. Similar concepts and semantics. ( a BioWare project )


Why not Akka/Akka.net? It looks more mature framework with bigger community and you can find much more resources about it.


I've experimented with both; I've done some Akka.net training. My thoughts:

1. Orleans is very clean but highly opionated and this results in what I see as operational shortcomings, e.g. I prefer running discrete Windows services that I can start/shutdown to provide fault isolation and safe upgrades, but this doesn't seem to be directly supported in Orleans (the documentation speaks about "restrictive placement strategies" to ensure certain grains are located in certain silos, but I could never figure out how to achieve that, and it also seems against the design to have such a level of control). If it fits what you need, it's really a nice solution.

2. Akka.net's API is very messy and out-dated, in my opinion; I'll give some examples. You have to inherit from Akka.net classes, which makes me very nervous from a testing standpoint. Messages are untyped. There is no easy way to understand the interface (sequence of valid message flows) to an actor. This suggests maintenance will be tricky after some time away from the code unless you carefully design your actors (yes, arguably this could be said of any code). Documentation for fundamental topics is still incomplete in places (e.g. http://getakka.net/docs/working-with-actors/handling-message...). Persistence still confuses me after reading it 5 times. That all being said, it's a straightforward API clone of something that is proven and accommodating to the different development styles required for a broad range of back-end services.


In Akka you can have typed actors, however you're missing the point.

In the actor model you often end up modeling state machines, and especially in the presence of asynchrony, it is impossible to meaningfully add types to such state machines. Because you see, the full set of messages that an actor recognizes at some point is much less interesting than the set of messages an actor accepts right now.

Another problem is that actors often communicate with multiple other actors at the same time, possibly aggregating data from multiple sources, outputting data on multiple channels. Thus a single actor can expose different APIs, depending on whom it is taking to.

And yet another problem is that often actors act as proxies or supervisors, simply forwarding messages around.

Basically people complaining about the untyped nature of actors are terribly misunderstanding the actor model. Or distributed systems.


You don't add types to state machines, however you can add typed ports and channels to actors. There is no requirement for a single inbox for messages. See kompics http://www.springer.com/la/book/9783642450648


There's a project called Orleankka which lets you use Orleans and virtual actors with Akka style messaging:

https://github.com/OrleansContrib/Orleankka


What do you mean by messages being untyped in Akka.NET? You can inherit from ReceiveActor and register handlers for specific types easily.


Your comment on Akka.NET is spot on. That was precisely my experience with it.


> You have to inherit from Akka.net classes, which makes me very nervous from a testing standpoint.

How do classes make you nervous? Testing support is one of the strongest parts of akka (see Akka.TestKit) - you can even simulate things like networks delays or VM shutdowns.

> Persistence still confuses me after reading it 5 times.

Yes for people not familiar with concepts of eventsourcing, Akka.Persistence can be enigmatic indeed. But you're not forced to do eventsourcing when using Akka.


Orleans is a similar the same thing to Akka.NET, but its design goals are kind of reversed from Akka's in that it's designed first for non-expert users to build distributed systems. Akka gives you the whole toolbox, and you figure it out from there. Orleans is rather more opinionated and, while it has similar features and concepts to Akka, it has an easier "happy path" for building scalable systems using it.

I'm not sure claims to Akka.NET's maturity hold water relative to Orleans. Akka proper has a lot of miles on it, but so does Orleans, and I'm not sure Akka.NET is as heavily tested and stressed as Orleans.


Can non expert users actually build distributed systems? I mean they can start it, but will it actually give correct results and scale and handle concurrency concerns?


I can't speak to it at Very Large Scales, but I've seen non-experts do pretty well with Akka when strong guardrails are put in place by seasoned developers. No reason to think that Orleans (which I've studied but not used heavily, though that might change with CoreCLR) couldn't pre-bake that a bit. I mean, eventually that sort of thing will fall down, but almost anything will.


Why do people ask questions like this here? let's turn this around for illustrative purposes....why do you use Akka instead of Orleans? Why don't you use Go?

These questions add nothing to the conversation beyond a veiled promotion of someone's pet technology


I'm not sure that's really the purpose. Akka.NET is the incumbent technology. Orleans might be older, but since Microsoft Research is historically bad at popularizing (or even being willing to share) its products, so Akka.NET is the one most people already know about.

Whenever you're seeing a new technology that seems to do the same thing as a pre-existing technology, I think it's perfectly sane and reasonable to ask, "What does $NEW_THING do differently from $THING_I_ALREADY_USE?" For starters, it lets you get up to speed on its merits much more quickly. You only need to go over the memetic equivalent of a patch file rather than having to read the entire spec.


"memetic equivalent of a patch file"

Ooohh i love this sentence ;)

And yes - it is only sane and reasonable to ask.. but should be mandatory !!


For those interested in distributed, high-scale computing on .NET, I'd also recommend having a look at MBrace: http://mbrace.io/

MBrace supports F# and C# and is designed to work well in interactive scripting scenarios, which lets you develop scalable systems gradually using REPL. I think it is complementary to Orleans/Akka.Net, so it is worth knowing it exists!


Comparison of Orleans with Erlang and Riak Core:

http://christophermeiklejohn.com/papers/2015/05/03/orleans.h...


I did not know about this until I looked at the awsome-dotnet list[1] .This project is based on Microsoft research[2] and is heavily used internally and externally at Microsoft (Halo and Skype project). I think the Microsoft Azure Service Fabric is cloud version of the orleans might be originated from this framework(I may be wrong).I have done some sample applications and i think this is a good alternative to AKKA.NET

[1]https://github.com/quozd/awesome-dotnet https://www.microsoft.com/en-us/research/project/orleans-vir...


> I think the Microsoft Azure Service Fabric is cloud version of the orleans might be originated from this framework(I may be wrong)

Service Fabric is a confusing beast. It includes a Virtual Actor runtime which is indeed very heavily inspired from Orleans, but it is a reimplementation. Orleans is built for "cloud" scenarios. You can run Orleans on top of Service Fabric using a host I wrote: https://github.com/OrleansContrib/OrleansFabricSilo


Why does Microsoft keep doing this, over and over again a technology becomes big, and Microsoft says "learning x is hard, we developed Y so you can do X without learning it". Which sounds good on the surface, but the trade off is 1. You can't leave the platform and reapply the concepts... you're stuck in Microsoft, but even more importantly 2. The process of abstracting away the thing you're trying to avoid learning means that you're probably doing it less efficiently.


In this case you can: Orbit (by Bioware/EA) for the JVM also implements the Virtual Actor model. Hopefully other frameworks will adopt the model, too. Orbit: https://github.com/orbit/orbit


I myself am mostly aquainted with Akka for Scala. So I was wondering what different design decisions they made, if any. After all a second implementation of a framework is often better than the first.

They do go into that in the research paper [1].

"Actor platforms such as Erlang [3] and Akka [2] are a step forward in simplifying distributed system programming. However, they still burden developers with many distributed system complexities because of the relatively low level of provided abstractions and system services. The key challenges are the need to manage the lifecycle of actors in the application code and deal with inherent distributed races, the responsibility to handl e failures and recovery of actors , the placement of actors, and thus distributed resource management. To build a correct solution to such problems in the application, the developer must be a distributed systems expert. To avoid these complexities, we built the Orleans programming model and runtime, which raises the level of the actor abstraction."

It's an interesting question how hard it would be to offer such a often-good-enough option in Akka for the cases when you don't have the need or the time or the team to develop a custom distributed computing model.

Edit: maybe Lagom is meant to fit that space. I think it's wider in scope than 'easy actors' though.


For posterity's sake: I just noticed this thorough comparison between Akka and Orleans from the Akka team. [1]

https://github.com/akka/akka-meta/blob/master/ComparisonWith...


I saw a talk about how this was used in Halo. Seems very impressive but I haven't had a project that needed this sort of scale since then. They are working on supporting .NET Core, which is promising: https://anclafs.com/#other

Shameless plug: I wrote about this in chapter ten of my recent book (https://www.packtpub.com/packtlib/book/Application%20Develop...). You'll need to have bought it for that chapter, but the first one is free.


Talk from Build 2014: "Using Orleans to Build Halo 4’s Distributed Cloud Services in Azure" https://channel9.msdn.com/Events/Build/2014/3-641


Service Fabric is a system that came out of this research. It's in use now by some game companies and Microsoft uses it as the platform that they build their offerings for Azure on.

https://azure.microsoft.com/en-us/services/service-fabric/

It's really slick. Persistent distributed .Net collections. Actor model support.

https://channel9.msdn.com/Events/Build/2015/3-618 Service Fabric stuff starts at ~38 minutes in...

https://channel9.msdn.com/Events/Build/2016/KEY02 Scott Hanslemann demos its use for a game called Age of Ascent? (Something like that.)

In addition to being in production use in Azure for several years it also runs on Linux.


It's been a couple years since the last time I looked at Orleans. I must say though that even in the early days the documentation was pretty good; it's even more impressive now.


Why this name ? As someone who has family in this town I'm wondering. Historical reasons ? Some character in a game I don't know about ? Random chosen french city ?


Back when this was an internal MS project (and I was working there, on another team), I believe the icon for the Orleans (internal) nugets and the demo apps was the Mardi Gras flag, which suggests that it's named after New Orleans. I might be misremembering.


French? Orleans is right down the street here in Massachusetts. ;)

Still, the name makes searching for help and information difficult.


I thought MS Nancy was firstname based, but I'm starting to wonder if they're revisiting "USofA oldest ally".


The latest episode of Scott Hanselman's podcast covered Orleans in an interview with Richard Astbury.

http://hanselminutes.com/536/exploring-the-orleans-distribut...


Whats the difference between service fabric and this?


Service fabric is a different distributed runtime with its own complex semantics. Orleans is conceptually simpler, with (virtual) actors running on "silos"; it's much closer to erlang.


What's up with the string identifiers? Don't break refactoring, that's just Java-esque.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: