HNHacker News
TopNewBestAskShowJobs

fmontesi

87 karma · joined February 3, 2015

Professor of Computer Science. Principal Investigator of Choreographic Programming. Lead Maintainer of CSLib, the Lean Computer Science Library. Maintainer and co-creator of the Jolie programming language.

Twitter: https://twitter.com/famontesi

submissionscomments
fmontesi··on Show HN: Wyzer Programming Language
This question is in fact core to research in the paradigm. Let me first address how it works and then the expressivity question.

A choreographic programming language features programming abstractions for programming communication intent. For example, often they have a primitive like:

Alice.expr -> Bob.x

read 'Alice communicates the evaluation of expr to Bob, which stores the message in its local variable x'. (In fact, we discovered that we can extend any mainstream language to have this kind of high-level primitives by extending data types with locations, see choral-lang.org).

This makes it impossible to write mismatched communication actions, because you're expressing both the send and receive actions in a single atomic instruction: they are well-matched by construction. You then build a compiler (typically called 'projection') that generates distributed programs for Alice and Bob -- the former doing the send to Bob and the latter doing the receive from Alice. We like making formal models of these compilers and mathematically proving them correct. A compiler that respects the choreography then automatically entails deadlock-freedom of the compiled code without the need for complex checks, because the source choreography cannot syntactically express deadlocked terms.

Consequently, there are no deadlocked distributed programs that we can compile from choreographies. It's an application of the neat trick of designing high-level languages for 'guiding' programming: instead of programming a distributed system with low-level primitives and then attempting the generally very hard task of checking for deadlocks, we use a high-level language where deadlocks cannot be written (or are at least easy to check against).

The above hopefully explains the intuition of how choreographic programming works. But then, as you did, one naturally asks: What can we express in choreographic programming languages? Are there fundamental limitations?

We do not know exactly yet; this is an area of very active exploration. Over the years, people have developed more and more clever choreographic programming languages that capture more and more interaction patterns.

What's perhaps surprising is that, for some theories of distributed languages (or interaction patterns, if you like), we know that choreographic programming is complete, in the sense that it can capture all deadlock-free systems that can be modelled in those theories. The first result of this kind was about capturing all interaction behaviours that can be described in linear logic (in the Curry-Howard interpretation of it with process calculi), but there are also works that can deal with recursive behaviour and even process spawning (fork). That's encouraging.

I think that investigating what the paradigm precisely can and cannot do is fascinating (but I'm very biased here..), not least because using a mathematically-modelled compiler lets us optimise the generated code aggressively (e.g., adding more asynchrony, as in Ozone). From the state of the art already out there, it looks like choreographic programming is 'expressive enough' for many different purposes. Hopefully it's gonna be the typical situation with high-level abstractions, whereby for most cases and most people the high-level language is gonna be good and low-level communication actions will be necessary only in niche scenarios. In the meantime, there are choreographic languages that can be integrated with middleware and foreign APIs to cover up for deficiencies (like Choral, HasChor, etc.).

fmontesi··on Jolie, the service-oriented programming language
Indeed, one of the nicest aspects of Jolie is that you can (semi-)automatically extract the definition of the infrastructure that you need from your code.

An example of a preliminary application that you might find interesting: https://arxiv.org/abs/2103.09518

fmontesi··on Jolie, the service-oriented programming language
I was indeed talking about implementation models, in particular models of service-oriented systems. These are usually formulated in terms of services, DTOs, APIs, business logic, etc., hence the value brought by Jolie in giving a direct syntactic representation. The model of an implementation can change often, so it's important to have code that resembles it closely (for readability, editing, etc.).

You're talking about the domain model, which I agree is more abstract and stable. It comes before making the implementation model. In the case of microservices, some concepts overlap and/or are very similar between domain and implementation, but some mapping is required. We started exploring a bit how to relate MDE languages to Jolie in https://arxiv.org/abs/2104.02458 and it looks pretty promising in the sense that they seem easily linkable.

In short: once you get to the implementation model and if this is service-oriented, Jolie gives you a concise and executable syntax to write it. (And there is ongoing work on how some elements of domain models can be mapped automatically to Jolie concepts.)

fmontesi··on Jolie, the service-oriented programming language
In a nutshell: because we want to minimise code <-> model distance. Other languages make you program in terms of functions, objects, etc., and make yourself model services by using these concepts. In Jolie, you write code that maps directly to the concepts that matter. What are the important concepts? APIs, Access Points, and Services (duh..) are examples.

Some more info at:

- https://dzone.com/articles/introduction-to-jolie (a brief introduction to Jolie and some concepts)

- https://hackernoon.com/a-detailed-introduction-to-service-or... (a deeper dive/discussion on some of the concepts)

Our (for now subjective) experience is that people who become familiar with Jolie are much faster at prototyping a service system, which makes it worth pursuing for us. Jolie code requires less boilerplate and state management for interesting scenarios. Two examples: communications can be natively composed in structures, e.g., the code

  open()
  close()
mandates that only the open operation is available at first and then only close is available (in object-oriented languages, you must encode this state with a private data field and manage it with if-then-else, etc.); likewise, streams in Jolie are consumed by writing

  provide
    [next(element)] { ..manage element here.. }
  until
    [end()] // stream ended here
which means "provide the operation next to invokers until operation end is called". A syntactically manifest approach to reactive programming and state machines, if you like.

Another big reason for exploring languages is discipline. Languages discipline how you write code. An example: in Jolie, you decompose software in terms of services. Many of these run locally as libraries, and are optimised by the interpreter by using hidden shared memory. But the language enforces that if you ever decide that a component should become an external, independent services, you can do it by updating a few references (input/output ports, our access points). See also https://fmontesi.github.io/2015/06/09/non-distributed-micros... Another example: Jolie discipline also gives you the ability of reusing the same business logic under multiple access points with different protocols.

This is the tip of the iceberg. In general, programming in terms of service abstractions is showing to be an interesting experience for us.

Phew, that was quite a bit for a "in a nutshell".. I hope that it's clear, otherwise, just write below.

fmontesi··on Jolie, the service-oriented programming language
It's Jolie as in pretty, not as in Angelina.

But I don't wanna stop you from making all these languages... (o:

fmontesi··on Jolie, the service-oriented programming language
IIRC, in industry, there is at least one big system with 50-ish microservices that includes electronic invoices. (See https://www.conf-micro.services/2019/papers/Microservices_20...)

At our place, we have a few websites written in Jolie and a system of services for evaluating software projects (for exams).

Feel free to drop in our chat if you're interested in chatting more about this with others as well: https://discord.gg/yQRTMNX

fmontesi··on Jolie, the service-oriented programming language
Cool project, I'll check it out.
fmontesi··on Jolie, the service-oriented programming language
Thanks for the kind words, I'll share them with the rest of the team.
fmontesi··on Jolie, the service-oriented programming language
Yeah, we have SOAP because... SOAP (just because of interoperability).

Our SOAP is quite palatable at least, because of reduced boilerplate. AFAIK Jolie devs don't typically use it (I don't at least), unless it's really necessary (interoperability with legacy web services, business requirements, etc.).

fmontesi··on Jolie, the service-oriented programming language
PS: We support integration with Java, so you hack your way around this by using some Java code for grpc, but it doesn't feel "native" and require some boilerplate.
fmontesi··on Jolie, the service-oriented programming language
Jolie and SODEP predate grpc, so we don't have grpc just because we had no need for it (we already had a binary protocol with expressive interfaces).

It's definitely something we'll get around doing sooner or later though, since so many people use it, and we do care about interoperability. Contributions towards this would certainly be welcomed warmly.

fmontesi··on Jolie, the service-oriented programming language
Sure does. Jolie applications can be containerised like any other.

See here for Docker and Kubernetes: https://docs.jolie-lang.org/v1.10.x/language-tools-and-stand...

It's also been tested with Azure Functions (serverless): https://mmontesi.blogspot.com/2020/06/jolie-on-azure-functio...

fmontesi··on Jolie, the service-oriented programming language
Woah, so this happened. Maintainer here. I'll do my best to reply to all questions/doubts that get posted about an hour from now, since there is some valid feedback and there are some good questions in here.
fmontesi··on Show HN: Invoking web APIs as if they were JavaScript methods
Here's also Github. It's resource-oriented instead of verb-oriented (like Telegraph), so we use Jor instead of Jo (both are provided by the same library).

Jor["users/fmontesi/repos"].get().then( response => ... );

Notice that using ["users/fmontesi/repos"] is the "alternative" syntax. If the resource path is a valid method name in JavaScript, e.g., "/users", you can just write this:

Jor.users.get().then( response => ... );

I'm still wondering what's the best way of offering resource paths. Using a string is fine, but another option would be to have an extension of JavaScript, like JSX in react, but that would add a dependency (on Babel, for example). So we could do something like:

Jor.users/fmontesi/repos.get().then( response => ... );

Another option could be to use an in-between method, for example:

Jor.users._.fmontesi._.repos.get().then( response => ... );

But this looks a bit clunky. So the design space is a bit larger here. Mumble mumble. :-)

fmontesi··on Show HN: Invoking web APIs as if they were JavaScript methods
By the way, here's the Telegraph API documentation, for reference: https://telegra.ph/api

What I wrote in my reply refers to that.

fmontesi··on Show HN: Invoking web APIs as if they were JavaScript methods
I can give you one by reusing a bit the Telegraph example I have in the Jo tutorial: http://fmontesi.github.io/2018/08/16/jo.html

To create an account:

Jo.createAccount( { shortName: "Homer" } ) .then( response => { alert( response.result.accessToken ); } );

To create a page:

Jo.createPage( { accessToken: token, title: "Title", content: "Content" } ) .then( response => { alert( response.result.url ); } );

This assume that those operations are available at the originating web server. If instead you're offering "Telegraph" as a subservice, then instead of Jo you have to write Jo("Telegraph"), the rest is the same.

I hope this clarifies things a bit.

fmontesi··on Show HN: Invoking web APIs as if they were JavaScript methods
A small library I made for fun. It's very early stage and I wanted to keep things simple, so it does not use any other established libraries (yet).
fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
What we can do right now is having a microservice for input validation and call it when we need to validate something, both from the client and the server parts. In Jolie, adding calls to a validator for all functionalities exposed by a microservice is easy with courier constructs (http://docs.jolie-lang.org/#!documentation/architectural_com...).

However, if your client application is a web app, that may mean generating a lot of traffic between clients and web server.

In theory, we could make a tool for automatically propagating validation checking from Jolie to client code, but that's a hard problem because some checks depend on information that only the server knows, so sometimes you need to make remote calls anyway. Not all hope is lost, because in many cases a static analysis could tell us what can be safely exported to the client and what cannot.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Leonardo is almost production ready, we usually just add some lines to tune the caching parameters as needed.

This is the code for the Jolie website if you're curious about an example:

https://sourceforge.net/p/jolie/code/HEAD/tree/web/trunk/jol...

We launch leonardo/leonardo.ol on the server.

The reason for which Leonardo works is that "execution { concurrent }" line which tells Jolie to start a new (light) process whenever a top-level operation is invoked. In this case we have only default, a catch-all operation for serving requests for files. So each time a client invokes Leonardo, a new process handles the request. Jolie processes are implemented as threads (cached in a thread pool when possible) with a local state (no data sharing, only communications).

Notice that in Leonardo we are embedding frontend.ol, which means that it will be run as a sub-service. And we also aggregate it in the HTTP input port, which means that its operations become available to clients. So now clients can not only invoke the catch-all default operation, but also the operations in frontend.ol.

Looking at frontend.ol, you will find one of these operation, e.g., "news". That's what you access when you go to http://www.jolie-lang.org/news

What does it do? It uses another sub-(micro)service, a blog reader, to fetch blog entries from our news blog, and then displays it to the user.

It's all a bit crude, in the enterprise we don't usually build html from scratch, but the Jolie website was so simple that we just went for it.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
It looks like another interesting difference may come from the workflow primitives (e.g., sequence, parallel, input choice) that Jolie comes with.
fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
I would be very interested in seeing a comparison with gen_server, it looks interesting.

Embedding in Jolie looks like a language primitive implementing something that resembles some of the ideas found in supervision trees.

AFAIK, dynamic fault handling is not subsumed by dynamic code loading in the specific case of request-response operations in parallel code (http://iospress.metapress.com/content/p0647559l8455778/?issu..., see my webpage fabriziomontesi.com/research.html for the pdf), but if that's relevant for the comparison with Erlang, I don't know. In all other cases your statement is correct. It's subsumed also in that case if you allow for dynamic code loading in the middle of waiting for a response for a request in a request-response invocation.

Another point which may be interesting: in Jolie a process inside of a microservice can have many input queues. Which messages go in which queue is decided by (an easier form of) correlation sets, basically a declarative part of the program where the programmer tells which parts of messages identify the queue in which they must go. These can be application data or even HTTP cookies, we use this features a lot for integration.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Thanks, I get it now.

If you use Jolie for implementing MVC, then every component is automatically a microservice (by construction from the language) and you can reuse them very easily in Jolie, Java, and Javascript inside of web browsers.

If you use other languages:

- if you need to use logic handled by a Jolie microservice, then you just need an API for making remote calls to that microservice. Jolie provides HTTP/JSON, HTTP/XML, SOAP, SODEP, XML-RPC, Java RMI, HTTP/GWT, and others. We have native libraries in Java (also usable in Scala) for making it even easier and look more native. You do not need to consider which protocol you will use in your logic, Jolie separates data format from logic by design. So it boils down to how easy it is to make remote calls in the "client" language.

- if you have programmed your logic in another language, you will need to expose it somehow to Jolie. If you use Java or Javascript, we can reuse it natively or almost natively. Otherwise, you will need to expose the functionalities using one of the protocols above, then Jolie will immediately see it as a native service as if it were implemented in Jolie (we make no difference between stuff implemented in Jolie or not if you support any of our communication means).

Is this a satisfactory answer? We can dive into examples if you have something specific in mind.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Short answer: we usually don't use SOAP unless it is strictly necessary in your system. We have simpler and/or more efficient protocols.

Long answer:

We do not use SOAP when it is not strictly necessary. Most Jolie programs use SODEP (our own open binary protocol) or HTTP/JSON or HTTP/XML. You do not need to deal with this manually, you just tell Jolie "use HTTP" or "use SODEP" in the deployment part. For example, this is how you expose your service in SODEP:

inputPort MyService { Location: "socket://localhost:80" Protocol: sodep Interfaces: MyIface }

and this is how you get the same thing but in HTTP:

inputPort MyService { Location: "socket://localhost:80" Protocol: http Interfaces: MyIface }

If you use Jolie to provide a SOAP service, it will most probably be completely invisible. You just have to choose soap and you are done:

inputPort MyService { Location: "socket://localhost:80" Protocol: soap Interfaces: MyIface }

Jolie will take care of using the right data formats without you noticing.

If you need to access an external SOAP service, there are many cases in which it can be invisible, but also many other cases in which you will have to tell Jolie some extra parameters in case some extensions or weird details need to be used.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
It may be the late hour here (CET), but I only kinda understood your question. What do you mean by "I can't replicate my model logic in my node services" ?
fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Another thing: the fact that it is imperative does not mean that we suffer from all the side effects. You cannot share data among different microservices, you must use communications (if you need performance, communications can be in-memory). The imperative paradigm (mixed with workflow programming) is used only for internal state manipulation, so that it is safer for concurrent programming.

I should really get down to write all of this in the FAQ page.. ;)

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Maybe this is a good hint that we should clarify this in the footer. :)
fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
Right, excellent question. We should put something in the FAQ. It's going to take some time to answer properly, but here are some initial pointers. Note that while I know Erlang academically I am definitely not an expert, so feel free to add more comments if you like.

Both languages are based on message passing, but Erlang is functional whereas Jolie is classical imperative/stateful.

Jolie provides architectural programming, e.g., you can make proxies abstracting from the behaviour of what you are composing with a language primitive.

Jolie provides integration natively, e.g., with automatic data transformations between different data protocols. The contract with the developer is that if you need to change protocols or deployment information (e.g., switch from TCP/IP to Bluetooth L2CAP or in-memory communication), you just have to change a couple of lines in the deployment part of a Jolie program and the rest will continue working without modifications to the program logic (logic/deployment decoupling).

Jolie has dynamic fault handling: fault handlers can be updated at runtime compositionally (higher-order code composition), which is afaik a new thing.

fmontesi··on Show HN: Jolie – The First Programming Language for Microservices
We are in the process of moving to github, but it is not a high priority right now and we have so many things to reconfigure in our servers that it is not going to happen until March at the earliest. Meanwhile you can use svn:

svn co svn://svn.code.sf.net/p/jolie/code/trunk jolie-src

You can also browse the code here:

https://sourceforge.net/p/jolie/code/HEAD/tree/