Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Choral: Choreographic Programming for Java (choral-lang.org)
33 points by dplyukhin 12 hours ago | hide | past | favorite | 13 comments
 help



Since HN is discovering choreographic programming today [1], I thought I’d share the compiler we’ve been working on for a few years now. Feel free to ask questions below and I’ll answer as best I can :)

[1]: https://news.ycombinator.com/item?id=49209385


Hey Dan, nice to run into you on the internet. How are you? :)

For those curious, there are a lot of neat ways to implement choreographic programming! Choral uses a custom compiler which gives it very powerful analysis techniques. Some are libraries and have to rely more strongly on host language features to work. My library uses macros to embed the language directly into Elixir which gets you a bit of the advantages of both: https://github.com/utahplt/chorex


I only skimmed the page and it looks like a really cool idea, but I have a question about this:

  types to let you express things like “the Client communicates this to Service, then Service communicates that to the Login Provider, then […]”
If the client needs to know about all that stuff that happens after its call to Service, isn't Service a leaky abstraction? My idea of OO, which I got from GOOS[1], is that each object talks only to its neighbors and it shouldn't have to know about their neighbors' neighbors or their neighbors' implementation details because the messages sent between objects are at the level of the domain. Same with microservices, in principle. The benefit is that you can reason about each object/microservice in isolation. If you must know that A then B then C then D, why split the code/services in the first place?

Sorry if the docs already answer this, I'll have a closer look later.

[1]: https://growing-object-oriented-software.com/


That's wishful OO thinking.

It's led to Mockito-style testing (some people call it 'unit', others call it 'integration'). You decide that the behaviour of file.read() is that it returns a string of its contents. You judge your software correct on the basis of how it processes the returned string. Then you launch, and in the real world, the behaviour of file.read() is to return a FileHandleNotOpen exception, so you fix your code, improve your mocks to cover the opening/closing scenario, and re-release it. Next time you run it, it throws a FileNotFound exception. So you fix your code, then extend your mocks to cover that scenario too. Later still, you call read() twice in prod, and hit a FileHandleAlreadyClosed exception (apparently the first read closed the file for you). Fix the mocks again.

You wanted Mockito to lead reality, but it lags it. Rather than Mockito being a useful tool to get your prod system working well, your prod system is actually a useful tool to get your Mockito mocks working well.

Choreographic programming lets you specify this protocol in one place. "The file will be opened, the file will be read, the file will be closed, etc." Then the different parties can't guess/assume or come up with their own half of the protocol incorrectly.


Two things:

* Unit testing is different from integration testing. They aren't interchangeable. Mainstream languages offer units of code s.a. a function, a class, a module and so on. Unit testing refers to testing the functionality implemented by a single such unit. There's no expectation that it will prove the entire program is correct, but it helps the developer to identify errors on the smallest testable level. Integration is a kind of testing that involves multiple testable units. In the ultimate case, it becomes end-to-end testing when the number of units tested are enough to cover functionality expected from the entire application rather than its individual parts. Even at this point, there's no expectation that the testing will prove the program is correct (unless the test can be made exhaustive), but it can prove that the program is correct sometimes.

* Encoding desired sequence of behaviors into a type doesn't prevent errors, s.a. in your example: FileNotFound. It's either a bad example, or there's little value in encoding the entire chain of expected events into a type.

I think that what parent referred to is what's also known as https://en.wikipedia.org/wiki/Law_of_Demeter . The reason for it you can gleam from the Advantages section of the linked page: in short, less knowledge of the unrelated components makes the replacement of individual components easier, therefore decreasing maintenance efforts. It also implies benefits in creating interfaces with simpler / more common types that are less likely to change over time s.a. to minimize the potential need to alter unrelated objects in order to replace / modify the desired one.

You could argue that this leads to loose coupling (same as, eg. the world of microservices) and makes the system more difficult to analyze as a whole. But it seems like that people who embrace this approach are willing to trade system-wide guarantees for their ability to evolve or to patch the system at low cost.


Unit testing:

Well, which is it? Testing a function, a class, or a module?

I didn't give my definitions of testing. I said when you go out into the OO worldview, different people will call it different things, so ignore it, it's not important. Sometimes one person will call it two or three different things. E.g. Unit testing is a function testing vs. unit testing is class testing.

Demeter: That's the thing I called wishful thinking.

Encoding desired sequence of behaviors into a type doesn't prevent errors: That's the value proposition of Choreographic programming. If it's wrong from the outset, simply disregard it.


In order for you to understand what a "unit" is, you need to first consider that there are different languages with different units. The definition of a "unit" doesn't give you a concrete size, it gives you a size relative to the language or even the project you are working on. It will be something the programmers working on the project will have to agree on, when they set to design unit tests.

Other examples of relative units: pixel (they don't have a fixed size in software), portion (as in cooking: it will depend on the place the food is served, intended audience), decibels (they don't measure the absolute volume of sound, they measure how one volume corresponds to another).

But... who am I kidding? If you were intelligent enough to understand the subject of this thread, you were certainly intelligent enough to understand what a "unit" is in unit testing. You are not arguing in good faith.

> Sometimes one person will call it two or three different

This is poor ability to reason: if two people disagree it doesn't follow that everyone is right.

> If it's wrong from the outset, simply disregard it.

This is poor ability to reason: criticism of a concept is just as valid of a way to discuss the subject as is praise. Nobody should be told not to discuss the subject if they think the subject is defective.

> Demeter: That's the thing I called wishful thinking.

While providing no arguments and no evidence.


Define a unit.

I did it in the post you replied to.

No, you defined what you mean by "unit test". What's the unit.

This is from a vaguely interested outsider, I hope an expert chimes in.

My understanding is that in choreographic programming, the protocol/choreography is considered an explicit "thing". That explicit thing is explicitly defined in one place, as opposed to the implementation being divided up across multiple places, like the client, server, etc. This is the explicit opposite of "reason[ing] about each object/microservice in isolation", at least with regards to the protocol. Since the protocol is one "thing", there is no reason for abstraction: Abstraction is for when you combine multiple "things".

In the example, the client's network code may know about internals of the service's network code, but that's not a problem. This doesn't mean that the client's business logic knows about the service's business logic. It's also not a problem that the client knows that there is a separate login provider that could be communicated with. You may be thinking, "oh, if the client knows about the login provider, it might try to talk to it directly". But no, because the entire network code is generated based on the protocol specification, and the protocol specification doesn't include this.

You might take the generated network code and break it by hand. I guess the response to that is, "please don't".

Again, I hope someone can correct this or explain it better.


Thanks for sharing this. I hadn't heard of choreographic programming.

Does it compile straight Java bytecode, or does it generate Java code which is then compiled by javac?


I really thought it was to plan musicals, and I thought it was cool!



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

Search: