Inflight Magazine no. 6
The 6th issue of the Wing Inflight Magazine.
The 6th issue of the Wing Inflight Magazine.
The 7th issue of the Wing Inflight Magazine.
The 5th issue of the Wing Inflight Magazine.
Hey there! As a marketer with nearly a decade of experience in the fields of FinTech, MedTech, AI, and Cybersecurity, this was my first time working on an open source project. Turns out, gaining devs' trust is like playing a whole new game. So, I decided to share what I have learned so far in the world of marketing an open source project.
Okay, I can't stress this enough. Open source thrives on community contributions. If they can't understand your project, they can't contribute. This is probably one of the biggest lessons I have learned so far. And the best method to succeed? Ensure your documentation is clear, engaging, and transparent. Think of it as a user manual that constantly needs to be maintained.
As obvious as this one may seem, for a marketer that’s used to a typical B2B playbook, it’s not exactly a given. Developers love private communities - platforms like Stack Overflow, dev.to, and Reddit are great sources for promoting your project’s blogs, docs, or anything else you’d like to promote.
Another one of the most important lessons I have learned is that developers don't really care for marketing lingo or sales pitches. They value practicality. Be straightforward and provide them with what they need. Regular content generation is vital, but it must resonate with this unique audience. This is why your topic, tone and voice are really important to nail. But once you have that content? Spread it through the aforementioned developer communities. This goes beyond your website and the typical social channels. Again, engage where the devs roam.
Open source is all about the community. I found that one of the best ways to attract more and more users is to show active support and communication. A responsive support system can make or break your project's trustworthiness. Whether it's GitHub Issues, Slack messages, or Twitter, consistent engagement demonstrates that there’s a dedicated team at the helm. Answering questions and providing that extra engagement can go a long way.
So what have I learned? Marketing an open source project is less about sales pitches and lead-gen, and more about building genuine relationships and growing a community. It's about understanding the core of open-source: collaboration, transparency, and community.
I’m looking forward to continue sharing what I learn through this journey of marketing an open source project like Winglang.
import ReactPlayer from "react-player"; import multi_file_errors_mp4 from "./assets/2023-08-30-magazine-004/multi-file-errors.mp4";
The 4th issue of the Wing Inflight Magazine.
Picture this: you're in the zone, crafting some spectacular code like the rock star cloud developer you are. You know that to truly harness the power of the cloud ecosystem, your system needs to be distributed. After an all-night coding spree, you've created two nifty services lovingly named service1 and service2. Now, service1 must produce a message and send it to service2. So, it's time to choose a message format standard. Given that it's 2023, XML is off the table, making JSON the clear winner.
At this point, something odd happens in your development journey. You pause to figure out how to use JSON in your chosen programming language, only to discover that you need to import a library. Sure, it's manageable, but now you have to consider the implications of using this JSON library and compare it to others. Of course, you'll make the right choice, you are a rock star, after all. However, this experience leaves you wondering: with JSON being so common, shouldn't it be built into any language designed for distributed computing?
When designing a good distributed system, several key aspects come to mind, such as fault tolerance, scalability, security, high availability, and interoperability. In this section, we'll focus on interoperability — the ability of a system to work seamlessly with other systems. This means that communication between systems must adhere to not only standardized protocols but also data formats.
Wing has been tackling the complexities of distributed computing in the cloud from various angles. One of the most notable angles is the concept of inflight functions, which serve as Wing's distributed computing primitives. These are code blocks packaged up and executed on a compute platform (i.e. AWS Lambda), playing a crucial role in Wing's vision for cloud-oriented programming. As such, it's vital to enable smooth communication between these functions, and what better way to do that than with JSON!
JSON has become the de facto standard for data interchange on the web. As a minimal, text-based format that is a subset of JavaScript, JSON is easy to read and focuses on solving a single problem: data interchange. Its simplicity and widespread adoption make JSON a clear choice for incorporating into Wing, helping us achieve the vision of a truly cloud-oriented programming language.
Wing has decided to treat JSON as a first-class citizen with built-in primitives. Let's take a look at a simple example:
let j = Json {
wow: "so easy"
};
// Optionally we can omit the Json keyword prefix
let j = {
wow: "so easy"
};
That's all it takes to create a JSON object in Wing. No need to import anything!
Now, let's create an inflight function that requires a Json object as input:
bring cloud;
let b = new cloud.Bucket();
let someService = new cloud.Function(inflight (jsonString: str) => {
let message = Json.parse(jsonString);
let id = message.get("id");
let content = str.fromJson(message.get("content"));
b.put("file-${id}.txt", content);
});
// Test it out
test "storing a message" {
let payload = {
id: "abc123",
content: "Hello, Json!"
};
someService.invoke(Json.stringify(payload));
// retrieve object from bucket and validate content
let storedMessage = b.get("file-${str.fromJson(payload.get("id"))}.txt");
assert(storedMessage == str.fromJson(payload.get("content")));
}
Something noteworthy happens above when we call str.fromJson()
. All fields within a Json
object are of type Json
, and Wing does not allow for implicit type conversions from Json
to other types. Thus, we must explicitly convert the Json
object to a string using the fromJson()
function, which exists for all Wing primitive types.
Let's dive a little deeper and see what else Wing's Json
type offers.
While Json
objects are great for interoperability, they are not the best for working with data in Wing. This is because Json
objects are not strongly typed. However, Wing does provide a way to convert Json
objects to structs. This conversion is done by using the fromJson()
function, which exists on all structs created in Wing.
Lets take a look at an example:
bring cloud;
// Struct declaration of a payload object
struct Payload {
id: str;
content: str;
}
// inflight function that receives json string representing a payload
let someFunction = new cloud.Function(inflight(msg: str) => {
let jsonPayload = Json.parse(msg);
// Now we can convert the json into a struct
let payload = Payload.fromJson(jsonPayload);
let content: str = payload.content;
});
The fromJson()
function will validate the Json
object at runtime and throw an error if the object does not fully match the struct definition. This is a great way to ensure that the data you are receiving is valid.
Let's add a test that will try and pass an invalid object to our inflight function:
test "json that does not match payload" {
// remember id and content are expected to be strings in our payload struct
let invalidPayload = {
id: 1,
content: false
};
someFunction.invoke(Json.stringify(invalidPayload));
}
When invoking the test above we will get the following runtime error:
│ Error: unable to parse Payload:
│ - instance.id is not of a type(s) string
│ - instance.content is not of a type(s) string
It is also worth mentioning that if the desired behavior is not to throw an exception you can also use the tryFromJson()
function
to get an optional type back.
In line with JSON's ECMA-404 standard, Wing's Json
type supports the following data primitives:
let s = Json "string"; // string
let n = Json 1; // number
let b = Json true; // boolean
let a = Json [1, 2, 3]; // array
let o = Json { a: 1, b: 2 }; // object
As with most Wing types, Json
objects are immutable. This means that once a Json
object is created, it cannot be modified. However, Wing does provide a way to create a mutable Json
object. This is done by using the keyword MutJson
instead of Json
:
let j = MutJson { a: 1, b: 2 };
// We can now modify the json object elsewhere in the code
j.set("c", 3);
If you have played with Wing much, you're probably aware that nearly all container types in Wing are homogeneous. This is pretty crucial for Wing's type system, but homogeneous data doesn't work well for interoperability between systems. Take the following data for example:
let id = "abc123";
let gpa = 3.5;
let name = "John Doe";
let completed_courses = ["CS 101", "CS 102", "CS 103"];
let active = true;
Above, we have some student data, and it's clear that the data is heterogeneous and should be represented as such between systems. This is why Wing's Json type is an exception to the rule of homogeneous containers. The following is a valid Json object in Wing:
let student = Json {
id: "abc123",
gpa: 3.5,
name: "John Doe",
completed_courses: ["CS 101", "CS 102", "CS 103"],
active: true
};
While we are excited about the introduction of Json
into the Wing type system, we are not done yet. There are still a few features we are working on, such as removing the .get()
and .set()
syntax for just using the []
operator or .
accessor. We also have some work to do on Json
schema validation, and some other goodies which can be found in our language spec.
As always, we welcome any feedback and would love to hear from you! Come join our
community discord and share your thoughts on Wing's Json
support. As well check out and ⭐ our Github repo
I love working with the Wing community, and one of my favorite ways to engage is by publishing good first issues which serve as approachable gateways for newcomers to get involved in developing Wing! Recently, I was looking for an issue that could serve as a friendly introduction to Wing's various layers, without being overly complex. Adding a new method to a resource seemed to be a perfect match for these criteria. I posted, as a good first issue, the implementation of the Queue.purge
method, and within just 5 minutes I decided to take on the task myself. This felt like the perfect opportunity to dive into the heart of Wing's mechanics and explore how things work behind the scenes.
Before diving into implementation, it was crucial for me to go through the specifications of the resource I was about to work on. I found all the necessary details in the Wing spec, outlining the method's signature, return type, and arguments.
To add a method to an existing resource, I needed to modify the implementation files of the resource that are located in wingsdk/src/cloud
folder. The cloud
folder contains cloud-agnostic code, ensuring that implementations are not tied to any specific cloud provider.
Under the cloud
folder, I navigated to queue.ts
file that contains the cloud-agnostic implementation, added the relevant methods as well as comments and documentation using code suggestions from GitHub Copilot!
Wing's support for multiple cloud providers means that each new method must be implemented for every supported provider. Now it's time to change folders like target-awscdk
, target-sim
, and others, each contain cloud-specific implementation files. I will say that target-sim
is not really a cloud provider, but it is our local simulator that runs locally and allows us to code, test, and debug very fast.
Let me give you an example. For cloud provider target-sim
, I set the length of the messages
array to zero:
public async purge(): Promise<void> {
return this.context.withTrace({
message: `Purge ().`,
activity: async () => {
this.messages.length = 0;
}
}
}
While for the tf-aws
implementation, I implemented the following:
public async purge(): Promise<void> {
const command = new PurgeQueueCommand({
QueueUrl: this.queueUrl,
});
await this.client.send(command);
}
I adjusted the code in queue.inflight.ts
as purge
is part of the inflight API. As you can see, these implementations tailored to different cloud providers were where the real magic happened.
No new functionality is complete without testing right? So I located the appropriate provider's queue.test.ts
and realized that Purge
cannot be tested unless I have a way to get the number of messages in the Queue
. So I went back to step #1 and added Queue.approxSize
as well:
For cloud provider target-sim
:
public async approxSize(): Promise<number> {
return this.context.withTrace({
message: `ApproxSize ().`,
activity: async () => {
return this.messages.length;
},
});
}
While for the tf-aws
implementation:
public async approxSize(): Promise<number> {
const command = new GetQueueAttributesCommand({
QueueUrl: this.queueUrl,
AttributeNames: ["ApproximateNumberOfMessages"],
});
const data = await this.client.send(command);
return Number.parseInt(data.Attributes?.ApproximateNumberOfMessages ?? "0");
}
Okay, coding and testing behind me, now to the final step which is to align the documentation with the new method. By executing the pnpm turbo build
command, the build process integrated my comments into the documentation. This ensures that the documentation reflects the changes I have made and would appear in the API Reference section.
For the actual code, feel free to explore this (example)[https://github.com/winglang/wing/pull/1160]. Additionally, you can gain insights from a brief video that illustrates the changes made to the files:
We would love your feedback and suggestions on Wing Discord.
Let's connect!
"A 2020 McKinsey study found that companies with better work environments for their developers achieved revenue growth four to five times greater than that of their competitors."
This quote is from an insightful article I recently came across, authored by researchers from DX, the University of Victoria, and Microsoft.
The article delves into the concept of Developer Experience (DevEx) and its profound impact on developer productivity.
As a developer, I am delighted to see that a leading consulting firm is using empirical evidence to demonstrate to companies just how important improving my working conditions can be for them :)
As a co-creator of Winglang, which aims to enhance the DevEx of cloud applications, I am happy to find research-backed validation for what we intuitively felt when we embarked on our journey: that our success could boost productivity by unlocking the cloud for developers.
However thrilling it is to have my beliefs validated and to see powerful organizations promoting these ideas, that's not the focus of this post.
Instead, I want to focus on another aspect of the paper: its introduction of structured definitions of DevEx and methods for its evaluation.
I believe it's crucial for us, as developers of a language designed to enhance DevEx, to establish a framework for discussing our approach to improving DevEx. This becomes especially vital when our project is open-source, and we aim to involve the community in these discussions.
So, this post will examine Winglang's approach to improving DevEx for cloud apps, through the lens of the structured definitions given in the paper.
This isn't an evaluation of whether we have met our goals. To make that assessment, we'd need to conduct a study involving actual developers using a more mature version of Wing. Instead, it serves as a status check to understand how we are aiming to improve DevEx and how our approaches align with those outlined in the article.
I hope this post will spark your interest, and that you will join us in the subsequent discussion.
The 3rd issue of the Wing Inflight Magazine.
The 2nd issue of the Wing Inflight Magazine.
Customizations below the abstraction line with Wing compiler plugins.
Why does Wing let you only create resources in preflight?
Why we are making Wing immutable by default.
The first ever issue of the Wing Inflight Magazine.
A manifesto for cloud-oriented programming.