Inflight Magazine no. 1
The first ever issue of the Wing Inflight Magazine.
Welcome to the first ever issue of the Wing Inflight Magazine, our periodic update on what's up (yes, two puns) with the Wing Programming Language, and the community that is starting to gather around the mission to democratize cloud development.
We will try to publish these frequently to keep them short and sweet, but given this is our first issue since the alpha release, there is a bit more ground to cover.
Let us know what you think! π We are @winglangio on Twitter, and we hang out 24/7 on Wing Discord.
TL;DRβ
Here is a summary of the topics in today's issue:
- π Deep dive: Our alpha release - sharing some stats and details from the first month of Wing in the daylight.
- π Deep dive: The story of inflight functions - "inflight functions" are Wing's primary "cloud-oriented" language innovation and we are focused on getting them right.
- π New: Implicit
await
, explicitdefer
- async calls in Wing are implicitlyawait
ed. You will be able to usedefer
to get the promise instead. - π New: Introducing
while
andenum
- our primary engineering focus is to finish implementing the compiler so we can actually start using Wing to build some real stuff. - π New: Wing Console now supports hot reloading -
you can now
wing run FILE.w
and the Wing Console will take care of the rest. Just edit your code and the console will update automatically. - π£οΈ RFC: Wing SDK Spec - your golden opportunity for shaping the first set of resources and APIs that will be included in the Wing SDK.
- π£οΈ RFC: Terraform Resources in Wing
- exploring the desired developer experience for using arbitrary Terraform resources in Wing.
TS;GMM (too short; give me more)β
The Wingnuts are hereβ
Before heading to re:Invent in late November we figured that it makes sense to start sharing publicly what we've been working on in the past 6 months. The main goal was to be able to talk to folks at the conference and invite them to check out our very early alpha bits and initial documentation.
We published our manifesto for cloud-oriented programming which describes the background for our project. It talks about the current challenges that developers and companies face when building for the cloud and describes the "impedance mismatch" between the applications we are building and the languages we use.
Since we are in early alpha, we realized that at this stage we are looking for a handful of folks that are enthusiastic and excited about being able to write both infrastructure and code in one language. We definitely didn't expect over a 1,000 people to sign up. We were surprised how many folks at re:Invent have already heard about the project, have already formed strong (sometimes very strong) opinions, and had deep and interesting questions to ask.
We were also thrilled to see pull requests start to pop up with some initial code contributions to the project from @jogold, @yamatatsu, @spara, @rjourdan, @skinny85, @Eitansl, @schosterbarak, @YoniMelki, @perpil, @VictorEB, @joao-zanutto, @tsuf239, @sebbel, @flyingImer, @Warkanlock, @ogre14t, @raywonkari and @hasanaburayyan β€οΈ β€οΈ
This was followed up by a post by Eric Riddoch and another on Hacker News, which brought about 11K new visitors to winglang.io, with even more interesting feedback and relevant conversations:
"This is one of the more sophisticated and cool of the 'Self Provisioning Runtime' concepts that have emerged in the last few years" - zoomzoom
"Why is this a language, not just a framework for JavaScript or whatever? - OJFord
"Great works! Seeing the demo in the front page really makes me think of the cloud architecture as a whole may just be an operating system out of itself." - stevefan1999
"New languages == zero ecosystemβno third-party libraries, community discussion (e.g. StackOverflow), real-world repositories, etc." - MontyCarloHall
"That animation on the home page is sick af" - tomcam
"The team is top notch (of CDK fame) found a non-trivial bug was assigned and fixed in 30 min. In general joy to interact with. Very strong focus on dev. experience. After a very subpar experience of building a very large enterprise project using AWS serverless stack Wing is the first thing that gives me hope that things can be way better." - qaq
We are suckers for open-source communities! We see our team as the seed of this community, and we couldn't have been more excited for all the new folks that joined. We believe that this is how software should be built, and we are here to share our work, listen to your inputs and collaborate on shaping the future of cloud development with anyone who is interested to take part.
Go, Wingnuts π
Yes, we are still implementing some very basic language featuresβ
In the next few months, our main focus is to implement compiler support for the initial Wing Language Specification. The spec currently includes the minimal set of features we believe are required to build cloud applications with Wing.
We recently added support for while
loops (#312) and
basic enum
declarations (#273).
Wing's while
loops look like this, where CONDITION
is any boolean expression. In the spirit
of minimalism, we decided not to require parenthesis around the loop's condition:
while CONDITION {
// rock!
}
Enums are currently very simplistic (likely too simplistic). They are a custom type and can just contain a list of members (at the moment we don't even support specifying a value for the members):
enum RecordType {
CUSTOMER,
ORDER,
INVOICE
};
let record = RecordType.CUSTOMER;
Naturally enums are going to evolve. There's an interesting discussion over #977 on giving enums Algebraic super-powers, with similar capabilities that exist in Rust and Swift.
Check out the Wing Language Roadmap for an up-to-date status.
Diving deeper into inflight functionsβ
Inflight functions are likely Wing's most significant language innovation. Since cloud applications are distributed systems and code is executed on multiple machines across various compute platforms, our language needs first-class support for this idea: code that executes in the cloud and interacts with cloud resources around it. This is where inflight functions come into play.
Asynchronous and concurrent programming have been a continuous source for programming language
innovation and research. Since the early days of
fork()
in POSIX, multi-threaded programming,
Goroutines, Erlang
Processes and the recently popularized,
cooperative concurrency with async/await
, developers have been looking for ways to write
applications that included more than a single thread of execution in a safe and intuitive manner.
Wing's inflight functions can be thought of as a type of asynchronous function that can be packaged and executed on a remote system, such as inside a Kubernetes Pod, AWS Lambda, Azure Functions, on Cloudflare Edge Workers or on any other cloud compute platform.
Our canonic example is a function that wants to put an object inside a bucket:
bring cloud;
let myBucket = new cloud.Bucket();
new cloud.Function(inflight () => {
myBucket.put("hello", "world");
});
The magic happens when the inflight function is referencing myBucket
. The cloud.Bucket
which is
defined (with new
) outside the function closure represents a cloud infrastructure resource,
not an in-memory object. When the function code interacts with this bucket (calls
myBucket.put()
), it represents an interaction across machine boundaries. The code is executed
inside some compute service such as AWS Lambda, and the bucket is backed by something like Amazon
S3. The compiler has to do quite a lot in order to make this a reality on the cloud: it needs to
wire up the bucket information during deployment, add the right permissions to the Lambda's IAM
policy, and create a code bundle with just the right set of dependencies.
Inflight functions can interact with resources through their inflight interface. This is not very
different from e.g. async
functions in JavaScript, where it doesn't really make sense to await
an async function from synchronous contexts. It is also not very different from how
Goroutines can only interact with the world through
Channels, or child processes can interact through pipes.
Inflight functions are an isolation boundary enforced by the compiler. This means that there are
certain limitations on what can be accessed from an inflight scope. Specifically, you can only
access immutable data and interact with cloud resources through their inflight API (like the
example above demonstrates). If you try to call myBucket.put()
outside of an inflight
context
the Wing compiler will emit this error:
Cannot call inflight function "myBucket.put" while in preflight phase
Many folks are asking us why is Wing a language and not a library. Inflight functions and resources are a great example. We believe it is impossible to ensure this level of isolation and interaction semantics in existing languages through a library, or even through a compiler extension. We've seen some worthy efforts in projects like Pulumi's Function Serialization, Punchcard and Functionless, and in all of these cases, there are either compromises in safety (e.g. it is possible to capture mutable objects) or in the programming model (e.g. type system is too complex).
We believe inflight functions are a fundamental building block of cloud-oriented programming, and we
are on a journey to get them right. From a syntactic perspective, we recently decided to remove the
short hand ~>
for representing inflight closures, and
instead use a simple inflight
modifier. We've been debating this for a while, and a
comment
from a Wingnut, Adam Ruka, tilted the scale in favor of the less quirky syntax. Don't be surprised,
though, if ~>
will come back, in addition to the inflight keyword, at some point when things mature.
So now, defining inflight functions in Wing is very similar to defining async
functions, only that
instead of the async
modifier, you can use the inflight
modifier. Here's an inflight function
closure:
let handler = inflight (e: str): str => {
// on air (apologies, the puns are unavoidable, really)
};
The next major step for inflights is to establish a model that allows them to be composed together, while tracking the operations performed by each one for the purpose of permission inference and other wiring. We've implemented the first stage in the SDK (#869), and we are working on implementing this in the compiler (#542), which will enable the creation of resources with inflight methods.
To see what this work will enable, check out this user story which talks about declaring a user-defined resource in Wing with a set of inflight methods. This is going to be fabulous!
Implicit await
and explicit defer
FTW!β
On a related topic, we decided that awaiting asynchronous calls will be implicit in Wing (spec change, compiler update).
We are trying to optimize the language for the common cases, and we realized that it makes sense to
reverse the common syntax around async calls. So, by default, when calling an async method in Wing,
the call will be awaited, and you will be able to use defer
to access the promise (and await
it
later).
let handler = inflight () => {
myBucket.put("file1.txt", "1");
myBucket.put("file2.txt", "2");
};
Each call to put()
will be awaited by default. Let's say I want to use Promise.all()
to await
all of the promises in parallel, I can obtain them using defer
:
let handler = inflight () => {
let promise1 = defer myBucket.put("file1.txt", "1");
let promise2 = defer myBucket.put("file2.txt", "2");
// hypothetical syntax: see https://github.com/winglang/wing/issues/1004
await promise.all(promise1, promise2);
};
Requesting comments on our SDK specificationβ
We have been working on the initial revision for the specification of the Wing SDK. This is where we are discussing which resources will be shipped as part of Wing's standard library, what's the right abstraction for each one, how can we map them across the various providers, and cross-cutting design guidelines and programming patterns.
To whet your appetite, here is the list of resources we are considering for our beta. This is just a snapshot from the RFC at the time of this writing to give you a sense of what we are discussing.
Resource | Priority | Description |
---|---|---|
Bucket | P1 | object storage, similar to AWS S3, Azure Blob Storage, GCP Storage |
Queue | P1 | a message queue, similar to AWS SQS, Azure Storage Queues, GCP Pub/Sub |
Function | P1 | a serverless function, similar to AWS Lambda, Azure Functions, GCP Cloud Functions |
Topic | P1 | a pub/sub topic, similar to AWS SNS, Azure Event Grid, GCP Pub/Sub |
Logger | P1 | a log aggregator |
Tracer | P1 | a distributed tracing system, similar to AWS X-Ray, Azure Application Insights, GCP Stackdriver Trace |
Counter | P1 | an atomic counter |
Schedule | P1 | a cron job / scheduled task trigger |
Website | P1 | a CDN-backed static website |
Api | P1 | a REST API |
Metric | P1 | a metric for monitoring system performance |
Alarm | P1 | an alarm that triggers when a metric crosses a threshold |
Service | P1 | a long-running service, similar to AWS ECS, Azure Container Instances, GCP Cloud Run |
Table | P2 | a relational database table |
Key-value store | P2 | a lightweight key-value store, similar to Redis or Memcached |
Job | P2 | a long-running compute workload that can be run on demand |
Workflow | P2 | a task orchestration engine, similar to AWS Step Functions, Azure Logic Apps, GCP Workflows |
Secret | P2 | a secret value, similar to AWS Secrets Manager, Azure Key Vault, GCP Secret Manager |
Stream | P2 | a stream of events, similar to AWS Kinesis, Azure Event Hubs, GCP Pub/Sub and Dataflow |
OnDeploy | P2 | a variation of Function that runs every time the app is deployed |
We would love to get your comments and thoughts on this important pull request, which will be used to prioritize the roadmap for our SDK towards beta.
The std
namespace is taking shapeβ
We are also starting to devise a way for declaring the APIs for the built-in types in Wing. This
pull request defines a new SDK namespace called std
which is implicitly loaded into the compiler's type checker and will be used to declare and
implement the APIs for types such as Array
, Map
and str
.
The first type in std
is the duration
type which represents a time-based duration (a pretty
common thing needed in cloud applications):
let tenHours = 10h;
let twoMinutes = 2m;
let fiveSeconds = 5s;
print("${tenHours.seconds}");
print("${twoMinutes.minutes}");
print("${fiveSeconds.seconds}");
Hot reloading the cloud with Wing Consoleβ
A great example how Wing is able to remove developer experience boilerplate.
Previously, Wing Console needed a .wsim
file as input, which is a Wing program compiled for the
sim
target. This means that if you changed your code, you would need to recompile manually and
reload the console.
We've realized we can short circuit the whole experience and simply allow pointing Wing Console
directly at a .w
source file. The console will take care of watching the file (and host directory)
for changes, recompile and reload.
The console now prints compilation errors and clicking on them jumps over to your favorite editor at the right line.
Here's a short video that shows this new feature:
Using Terraform resources in Wingβ
The beauty and power of the cloud comes from the endless ecosystem of services that we can leverage as developers to build applications. Contrary to what people might think, Wing is designed with cloud heterogeneity in mind.
In that spirit, we've started to explore what would be the best developer experience in Wing for using any resource from the vast Terraform provider ecosystem.
The following example shows a sketch for what it might be like to define a GitHub repository as part
of a Wing application and push a file from a bucket to it. The code uses the
github_repository
Terraform resource directly from the CDKTF provider.
bring cloud;
bring git;
bring fs;
bring "@cdktf/provider-github" as github;
let filename = "message.txt";
let repo = new github.repository.Repository(
name: "my-repo",
description: "My new github repository",
visibility: "public",
);
let api = cloud.Api();
api.onPut("/messages", (req: cloud.ApiRequest, res: cloud.ApiResponse) => {
let repo = new git.Repository(fs.mkdtemp());
repo.clone(repo.gitCloneUrl, depth: 0);
fs.File.write(fs.Path.join(repo.dir, filename), req.body);
repo.commit("update message", add: true);
repo.push(remote: "origin");
});
NOTE: the
fs
andgit
APIs are hypothetical
This issue and this RFC are starting to explore this idea, and we would love your feedback and inputs on this topic.
Summaryβ
Yes, we know this was a bit lengthy, but we are just so very excited to share what we've been up to. We promise to try and publish these more frequently, so it's easier to keep track.
We are just warming our engines... Stay tuned!
As usual, we couldn't be more excited for anyone to join our journey to make the cloud a better place to build software. We constantly hang out on Discord, and if you haven't already, please join our alpha.
See you in our next flight.