Merge branch 'release' of github.com:wasp-lang/wasp

This commit is contained in:
Filip Sodić 2023-10-16 16:05:32 +02:00
commit 1162fedd20
17 changed files with 329 additions and 0 deletions

View File

@ -0,0 +1,192 @@
---
title: "On Importance of Naming in Programming"
authors: [martinsos]
image: /img/on-importance-of-naming-in-programming/variables-naming-pet-white.png
tags: [programming, clean-code]
---
import ImgWithCaption from './components/ImgWithCaption'
In stories, you will often find the motif of a powerful demon that **can be controlled only by knowing its true name**. Once the hero finds out that name, through cunning dialogue or by investigating ancient tomes, they can turn things around and banish the demon!
I firmly believe writing code is not much different: through finding good names for functions, variables, and other constructs, we truly recognize the essence of the problem we are solving. **The consequence of clarity gained is not just good names but also cleaner code and improved architecture**.
<ImgWithCaption
alt="The power of correct naming in programming"
source="img/on-importance-of-naming-in-programming/naming-banish-thee-white.png"
/>
I would go as far as to say that **90% of writing clean code is “just” naming things correctly**.
Sounds simple, but it is really not!
Lets take a look at a couple of examples.
# Example #1
```js
// Given first and last name of a person, returns the
// demographic statistics for all matching people.
async function demo (a, b) {
const c = await users(a, b);
return [
avg(c.map(a => a.info[0])),
median(c.map(a => a.info[1]))
];
}
```
What is wrong with this code?
1. The name of the function `demo` is **very vague**: it could stand for “demolish”, or as in “giving a demo/presentation”, … .
2. Names `a`, `b`, and `c` are **completely uninformative**.
3. `a` is reused in lambda inside the `map`, **shadowing** the `a` that is a function argument, confusing the reader and making it easier to make a mistake when modifying the code in the future and reference the wrong variable.
4. The returned object doesnt have any info about what it contains, instead, **you need to be careful about the order of its elements** when using it later.
5. The name of the field `.info` in the result of a call to `users()` function gives us **no information as to what it contains**, which is made further worse by its elements being accessed by their position, also hiding any information about them and making our code prone to silently work wrong if their ordering changes.
Lets fix it:
```js
async function fetchDemographicStatsForFirstAndLastName (
firstName, lastName
) {
const users = await fetchUsersByFirstAndLastName(
firstName, lastName
);
return {
averageAge: avg(users.map(u => u.stats.age)),
medianSalary: median(users.map(u => u.stats.salary))
};
}
```
What did we do?
1. **The name of the function now exactly reflects what it does, no more no less**. `fetch` in the name even indicates it does some IO (input/output, in this case fetching from the database), which can be good to know since IO is relatively slow/expensive compared to pure code.
2. **We made other names informative enough**: not too much, not too little.
- Notice how **we used the name `users` for fetched users**, and not something longer like `usersWithSpecifiedFirstAndLastName` or `fetchedUsers`: there is no need for a longer name, as this variable is very local, short-lived, and there is enough context around it to make it clear what it is about.
- **Inside lambda, we went with a single-letter name**, `u`, which might seem like bad practice. But, here, it is perfect: this variable is extremely short-lived, and it is clear from context what it stands for. Also, we picked specifically the letter `u` for a reason, as it is the first letter of `user`, therefore making that connection obvious.
3. **We named values in the object that we return**: `averageAge` and `medianSalary`. Now any code that will use our function wont need to rely on the ordering of items in the result, and also will be easy and informative to read.
Finally, notice how there is no comment above the function anymore. The thing is, **the comment is not needed anymore**: it is all clear from the function name and arguments!
# Example #2
```js
// Find a free machine and use it, or create a new machine
// if needed. Then on that machine, set up the new worker
// with the given Docker image and setup cmd. Finally,
// start executing a job on that worker and return its id.
async function getJobId (
machineType, machineRegion,
workerDockerImage, workerSetupCmd,
jobDescription
) {
...
}
```
In this example, we are ignoring the implementation details and will focus just on getting the name and arguments right.
What is wrong with this code?
1. **The function name is hiding a lot of details about what it is doing**. It doesnt mention at all that we have to procure the machine or set up the worker, or that function will result in the creation of a job that will continue executing somewhere in the background. Instead, it gives a feeling that we are doing something simple, due to the verb `get`: we are just obtaining an id of an already existing job.
Imagine seeing a call to this function somewhere in the code: `getJobId(...)`**you are not expecting it to take long or do all of the stuff that it really does, which is bad**.
Ok, this sounds easy to fix, lets give it a better name!
```jsx
async function procureFreeMachineAndSetUpTheDockerWorkerThenStartExecutingTheJob (
machineType, machineRegion,
workerDockerImage, workerSetupCmd,
jobDescription
) {
...
}
```
**Uff, that is one long and complicated name**. But the truth is, that we cant really make it shorter without losing valuable information about what this function does and what we can expect from it. Therefore, **we are stuck**, we cant find a better name! What now?
The thing is, **you can't give a good name if you don't have clean code behind it**. So a bad name is not just a naming mishap, but often also an indicator of problematic code behind it, a failure in design. Code so problematic, that you dont even know what to name it → there is no straightforward name to give to it, because it is not a straightforward code!
<ImgWithCaption
alt="Bad name is hiding bad code"
source="img/on-importance-of-naming-in-programming/bad-name-bad-code-scooby.png"
/>
In our case, the problem is that this **function is trying to do too much at once**. A long name and many arguments are indicators of this, although these can be okay in some situations. Stronger indicators are the usage of words “and” and “then” in the name, as well as argument names that can be grouped by prefixes (`machine`, `worker`).
The solution here is to clean up the code by breaking down the function into multiple smaller functions:
```jsx
async function procureFreeMachine (type, region) { ... }
async function setUpDockerWorker (machineId, dockerImage, setupCmd) { ... }
async function startExecutingJob (workerId, jobDescription) { ... }
```
# What is a good name?
But lets take a step back - what is a bad name, and what is a good name? What does that mean, how do we recognize them?
**Good name doesnt misdirect, doesnt omit, and doesnt assume**.
A good name should give you a good idea about what the variable contains or function does. A good name will tell you all there is to know or will tell you enough to know where to look next. It will not let you guess, or wonder. It will not misguide you. A good name is obvious, and expected. It is consistent. Not overly creative. It will not assume context or knowledge that the reader is not likely to have.
Also, **context is king:** you cant evaluate the name without the context in which it is read. `verifyOrganizationChainCredentials` could be a terrible name or a great name. `a` could be a great name or a terrible name. It depends on the story, the surroundings, on the problem the code is solving. Names tell a story, and they need to fit together like a story.
# Examples of famous bad names
- **JavaScript**
- I was the victim of this bad naming myself: my parents bought me a book about JavaScript while I wanted to learn Java.
- **HTTP Authorization header**
- It is named `Authorization`, but is used for authentication! And those are not the same: authentication is about identifying yourself, and authorization is about granting permissions. More about it can be found here: [https://stackoverflow.com/questions/30062024/why-is-the-http-header-for-authentication-called-authorization](https://stackoverflow.com/questions/30062024/why-is-the-http-header-for-authentication-called-authorization) .
- **Wasp-lang**:
- This one is my fault: [Wasp](https://github.com/wasp-lang/wasp) is a full-stack JS web framework that uses a custom config language as only a small part of its codebase, but I put `-lang` in the name and scared a lot of people away because they thought it was a whole new general programming language!
# How to come up with a good name
## Dont give a name, find it
The best advice is maybe not to give a name, but instead to **find out** a name. You shouldnt be making up an original name, as if you are naming a pet or a child; **you are instead looking for the essence of the thing you are naming, and the name should present itself based on it**. If you dont like the name you discovered, it means you dont like the thing you are naming, and you should change that thing by improving the design of your code (as we did in the example #2).
<ImgWithCaption
alt="You shouldn't name your variables the same way you name your pets, and vice versa"
source="img/on-importance-of-naming-in-programming/variables-naming-pet-white.png"
/>
## Things to look out for when figuring out a name
1. **First, make sure it is not a bad name :)**. Remember: dont misdirect, dont omit, dont assume.
2. **Make it reflect what it represents.** Find the essence of it, capture it in the name. Name is still ugly? Improve the code. You have also other things to help you here → type signature, and comments. But those come secondary.
3. **Make it play nicely with the other names around it.** It should have a clear relation to them - be in the same “world”. It should be similar to similar stuff, opposite to opposite stuff. It should make a story together with other names around it. It should take into account the context it is in.
4. **Length follows the scope**. In general, the shorter-lived the name is, and the smaller its scope is, the shorter the name can/should be, and vice versa. This is why it can be ok to use one-letter variables in short lambda functions. If not sure, go for the longer name.
5. **Stick to the terminology you use in the codebase**. If you so far used the term `server`, dont for no reason start using the term `backend` instead. Also, if you use `server` as a term, you likely shouldn't go with `frontend`: instead, you will likely want to use `client`, which is a term more closely related to the `server`.
6. **Stick to the conventions you use in the codebase**. Examples of some of the conventions that I often use in my codebases:
- prefix `is` when the variable is Bool (e.g. `isAuthEnabled`)
- prefix `ensure` for the functions that are idempotent, that will do something (e.g allocate a resource) only if it hasnt been set up so far (e.g. `ensureServerIsRunning`).
## The simple technique for figuring out a name every time
If you are ever having trouble coming up with a name, do the following:
1. Write a comment above the function/variable where you **describe what it is, in human language**, as if you were describing it to your colleague. It might be one sentence or multiple sentences.
This is the essence of what your function/variable does, what it is.
2. Now, you take the role of the sculptor, and you chisel at and **shape that description of your function/variable until you get a name**, by taking pieces of it away. You stop when you feel that one more hit of your imagined chisel at it would take too much away.
3. Is your name still too complex/confusing? If that is so, that means that the code behind is too complex, and should be reorganized! **Go refactor it**.
4. **Ok, all done** → you have a nice name!
5. That comment above the function/variable? Remove everything from it that is now captured in the code (name + arguments + type signature). If you can remove the whole comment, great. Sometimes you cant, because some stuff cant be captured in the code (e.g. certain assumptions, explanations, examples, …), and that is also okay. But dont repeat in the comment what you can say in the code instead. **Comments are a necessary evil and are here to capture knowledge that you cant capture in your names and/or types**.
Dont get overly stuck on always figuring out the perfect name at the get-go → it is okay to do multiple iterations of your code, with both your code and name improving with each iteration.
# Reviewing code with naming in mind
Once you start thinking a lot about naming, you will see how it will change your code review process: focus shifts from looking at implementation details to looking at names first.
**When I am doing a code review, there is one predominant thought I will be thinking about: “Is this name clear?”**. From there, the whole review evolves and results in clean code.
Inspecting a name is a single point of pressure, that untangles the whole mess behind it. Search for bad names, and you will sooner or later uncover the bad code if there is some.
# Further reading
If you havent yet read it, I would recommend reading the book **Clean Code by Robert Martin**. It has a great chapter on naming and also goes much further on how to write code that you and others will enjoy reading and maintaining.
Also, [A popular joke about naming being hard](https://martinfowler.com/bliki/TwoHardThings.html).

View File

@ -0,0 +1,137 @@
---
title: 'Wasp Launch Week #4: Waspolution'
authors: [matijasos]
image: /img/lw4/lw4-banner.png
tags: [launch-week, update]
---
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import InBlogCta from './components/InBlogCta';
import WaspIntro from './_wasp-intro.md';
import ImgWithCaption from './components/ImgWithCaption'
<ImgWithCaption
alt="Launch Week 4 is coming"
source="img/lw4/lw4-banner.png"
/>
We're back! Beginning of the October was both the craziest and busiest time we've ever had at Wasp - we ended up on GitHub Trending (almost at [7,000 stars](https://github.com/wasp-lang/wasp) - thank you🙏), [MAGE](https://usemage.ai/) (our GPT web app generator) exploded with 20,000 apps created and more people than ever used Wasp!
Crazily enough, we've even had a first [startup project made in Wasp that has been acquired](https://dev.to/wasp/from-idea-to-exit-building-and-selling-an-ai-powered-saas-in-5-months-27d9) (GPT-powered, of course)! 💸🐝💸
To top it all off, we have a new launch week incoming that brings a ton of new exciting product updates! If this is your first rodeo, check out our previous launches:
- [Launch Week 1: Beta](/blog/2022/11/26/wasp-beta-launch-week) 🎉
- [Launch Week 2: Pizzazz](/blog/2023/04/11/wasp-launch-week-two) 🍕
- [Launch Week 3: Magic](/blog/2023/06/22/wasp-launch-week-three) 🧙
## What's this launch all about?
As you might have noticed, each of our launches comes with a specific theme. We've come a long way since our first launch week, Beta release, which moved Wasp from a prototype to a real, working framework. In the previous two launch weeks we've added plenty of new features and unlocked functionalities you couldn't have used before (e.g. email sending, async jobs, ...).
This time we kept introducing new features, but we also realised there are many opportunities to make developers' lives even easier. That's why the theme of this launch week stems from "Evolution" - Wasp is now well set on its way, lies on the solid foundations with a strong community behind it and keeps naturally evolving!
<ImgWithCaption
alt="Growing up"
source="img/lw4/grown_up.gif"
caption="Wasp from this launch onwards."
/>
Enough chit-chat - let's see what will go down next week! We'll present a new feature (or more of them) every day. To stay in the loop follow us on Twitter/X ([@WaspLang](https://twitter.com/WaspLang)) and join our community on [Wasp Discord](https://discord.gg/rzdnErX)!
## Launch party 🚀🎉
<ImgWithCaption
alt="launch event 3 - screenshot"
source="img/lw4/lw3-party-screenshot.jpeg"
caption="A bit of the atmosphere from LW3 launch party!"
/>
As it is a tradition by now, we'll kick things off with a launch party on our Discord! You will be able to meet the team and be the first one to learn about the new features we'll be revealing for the rest of the week. We'll also answer community questions, discuss plans for the future, and of course, hand out some sweet swag (finally get your hands on that Da Boi plushie)!
The party starts at **11 am EDT / 5 pm CET** - sign up [here](https://discord.gg/nGgfbEae?event=1162316586963710023) and make sure to mark yourself as "interested"!
<ImgWithCaption
alt="launch event - how to join"
source="img/lw4/lw4-event-instructions.png"
/>
## Monday: I am Speed 🚄
<ImgWithCaption
alt="Why waste time"
source="img/lw4/kevin-waste-time.gif"
caption="We think the same, but about keystrokes."
/>
We all know that developer productivity is a hot topic these days. At the end of the day, why waste time use many keystroke when few do trick?
That's exactly what we will feature on Monday! Wasp is already famous for its brevity and prototyping speed, which is powered by its high-level configuration language, but we found a way to make things even simpler!
**When**: Monday, October 16 2023
## Tuesday: Safety first 👷
<ImgWithCaption
alt="Realtime"
source="img/lw4/safety-first.gif"
/>
In every industry they have strict safety protocols - we believe programming should be no different! Especially when it comes to types - imagine if you had a piece of data running around your application, without even knowing what it looks like!? No sir, not under my watch ⬇️⌚️.
**When**: Tuesday, October 17 2023
## Wednesday: Wasp x AI x ...base 🤖⚡️
<ImgWithCaption
alt="Power Rangers"
source="img/lw4/power-rangers.gif"
/>
The best things happen when you combine multiple amazing things together - and that's exactly what we did! I don't want to spoil too much, but let's just say it has become much easier to do a certain similarity search with Wasp 😉.
I don't want to overhype it, but it might be one of the coolest things you've seen so far - see you on Wednesday!
**When**: Wednesday, October 18 2023
## Thursday: A glimpse into the future 🛸
<ImgWithCaption
alt="World if everyone used Wasp for web development"
source="img/lw4/web-if-wasp.jpg"
/>
Although there is a plenty of work to refine the existing features and polish the overal developer experience, we still always have our eyes on the future and take time to experiment. This is what we will present here - a really cool feature that is possible due to the Wasp's unique approach, that will illuminate a lot posibilities for the future!
**When**: Thursday, October 19 2023
## Friday: Polish 💅
<ImgWithCaption
alt="Wax on, Wax off"
source="img/lw4/karate-kid.gif"
/>
Sometimes, the best thing you can do is take care of what you already have! As we mentioned in the intro, Wasp is becoming all about DX, feature completeness and elegance of use. And this is what we will demonstrate today!
**When**: Friday, October 20 2023
## Monday: SaaS-a-thon!
<ImgWithCaption
alt="Hacking"
source="img/lw4/hacking.gif"
/>
As the ancient scrolls say, every launch week must end with a hackathon, and this is no exception! We'll share more details soon, but as the title says, we'll equip you as well as possible to create a SaaS of your dreams in no time!
**When**: Monday, October 23 2023
## Recap
- **We are kicking off Launch Week #4 on Mon, Oct 16, at 11am EDT / 5pm CET** - make sure to [register for the event](https://discord.gg/nGgfbEae?event=1162316586963710023)!
- **Launch Week #4 brings a ton of new exciting features** - well highlight one each day, starting Monday. Follow us on [twitter](https://twitter.com/WaspLang) and [join our Discord](https://discord.gg/rzdnErX) to stay in the loop!
- **Following launch week, well announce a SaaS-a-thon** - get your keyboards warmed up and ready to roll!

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB