Martinsos
A unique thing about Wasp is that we built it around the central "specification" language (DSL) that lets you express the high-level of your app, for which we wrote our own compiler and language server in Haskell. You write 90% of logic in popular web tech (React, Node.js, Prisma), but specify the "full-stack" part of it in the DSL.
While we loved the idea of a custom language for optimal ergonomics and declarative nature of it, and had great time building it, we realized with time how hard it is to develop all the tooling around it while also building the framework, and also started getting constrained by its simplicity for some of the new ideas we have developed through time, of where we wanted to take Wasp.
So, 5 years since the start (wow feels like 2y), we made a big change: we replaced our custom DSL with the eDSL (embedded DSL, a library) in TypeScript!
So Wasp still has its spec(ification), stack-agnostic and standalone (runtime), but now you write it in TypeScript, with all the Turing-complete and side-effect goodiness, which allows things like splitting spec into multiple files, writing helpers, checking env vars, implementing your own file-based routing if you want, ... . And, also enables a lot of exciting stuff we plan to build upon it, like extensible spec, and full-stack modules.
For the full-story, please check out the attached blog post I wrote, and I am happy to answer any questions here!
Open Vibe: agent tutors you as you vibe code your SaaS app
I moved my blog from Jekyll to Emacs Lisp
Btw, AI actually works great for it. I am sure part is that the Wasp's DSL exists for some time now, but it actually worked well for the very start, because the DSL was quite simple (similar to JSON) and AI knows how to generalize very well.
So I wouldn't discourage people from writing DSLs because of AI -> AI can understand them very well -> but for the reasons of missing out on all of the benefits of using a strong host language and doing it as an embedded DSL in it. If you are doing your own, completely standalone DSL, you will need to implement a compiler, editor extensions, LSP, maybe module system if you need it, maybe package system/manager if you need it, ... . Although when I think about it, that is also easier now with AI, than it was before! Hm yeah actually maybe custom DSLs are a good idea these days, with AI doing most of the job for you. I still wouldn't go back to custom DSL for Wasp however because biggest thing for us is probably familiarity -> custom DSL just scares people off.
Comparison of two frameworks: 4.0M vs. 2.5M tokens for the same app
The Importance of Naming in Programming
On Importance of Naming in Programming
As for getting somebody on-board -> we hired a couple senior / intermediate devs that had no or introductory knowledge of Haskell, and all of them so far got up to speed in a month or so, while not learning exclusively Haskell but also the rest of the codebase at the same time, so normal learning process in the new company. So I wouldn't say at all that learning Haskell for them was an issue, but I am certain that big factor here was that they are generally experienced in other languages. That said, we do keep our codebase pretty tidy and simple (no super crazy Haskell features).
I participated teaching students Haskell on my alma mater this year and "what can Haskell be used for" was a common question, with genuine expectation that the answer will be it is limited to only specific use cases. I would answer that it can be used anywhere where languages like Java, C#, Go, and similar can be used -> it is a general programming language that uses garbage collector! And while somewhat harder to learn due to abstractions that we are all not used to, it is a delight to express business logic in it once you get to know it well.
The biggest factor for deciding if Haskell is a good fit for the problem is probably ecosystem support -> are there enough libraries and tools to support efficient development in a specific problem domain. In our case, we are building a compiler/transpiler, and Haskell is well-known for great support in that area, so it was a no-brainer. We were actually also considering Rust, but we just had no need for that level of memory control and rather decided to go with language where we don't have to think about that (Haskell).
So yes, you could use just Analyzer to produce AppSpec, and then write your own generator that will based on that AppSpec generate your own code! AppSpec currently exists only as Haskell in-memory data structure, but it could be relatively easy serialized via JSON and then imported in some other language.
You can see more about this in this README, there is a nice diagram showing parts of compiler (Analyzer, AppSpec, Generator): https://github.com/wasp-lang/wasp/tree/main/waspc#readme .
The reason why we already ensured this split was because the plan is in the future to have multiple different Generators, and also to allow users to write either their whole Generators or plugins that modify AST (AppSpec). We haven't explored this further yet, and probably won't push much in this direction until we get to Wasp 1.0, but we certainly want to work on it more in the future!
Permissions (access control) in web apps
We picked PrismaJS as a database layer for our full-stack JavaScript framework
Let's reason about client-server state management in web apps
I am developing an open-source web app DSL/framework and I would like to find the best abstraction for the client-server state management (SPA + API server, what we use Redux, MobX, Apollo and similar for).The fact that it is a DSL gives me a lot of freedom to implement whatever might be the best solution, so I am trying to think about it from the ground up.Below are my thoughts so far, to...
But I do think we are falling behind with opinionated approaches. I am guessing that is because experts are usually the most prominent in communities, they are directing the ecosystem, and they prefer flexibility and power vs opinionated approach.
Ruby on Rails was an opinionated approach made by non-expert that grew into something really big because of that. I am also trying to contribute in that direction with highly opinionated solution for web app development (https://wasp-lang.dev).
For example package.json in NPM packages -> that feels like a good fit for JSON (although it would be even better if JSON had comments). On the other hand, terraform, or build languages like Make or Meson -> they are complex enough that it probably makes sense to have a standalone DSL.
I was facing the same decision recently on my project while designing a declarative DSL for web app development (kind of like web framework). From simplest to most complex option:
- should I just let them define it all in JSON? There would be a lot of repetition at some point and it would become impractical, but it could be ok for the start.
- should I just implement JS library, that devs can use in JS to construct a config object that is then exported to JSON? That would be embedded DSL. Sounds flexible and easy to do, but it is also overly expressive and not "cool" (ok this is debatable).
- should I use something like Dhall? It is declarative and simple.
- should I come up with my own declarative, configuration-like DSL? It would probably end up similar to Dhall, but this means I can do whatever I want - I can make it as ergonomic and custom as I want to (which I guess is both good and bad :D!). It might also allow for nicer interop with Javascript and other languages.
In this case, we went for the last option, mostly because we felt the most important thing is ergonomics and interop, but well, I am still curious how would other directions play out. Plus at the end we didn't yet get to the point where language is more expressive than JSON (code example: https://github.com/wasp-lang/wasp/blob/master/examples/tutor...).
Maybe I am just missing a better design process, but it seems to me that with a language idea it is hard to say if it is good or not until you try using it.
There is a lot of talk at the start of the article how web development should be easier, how it should be less about the underlying architecture and that we shouldn't spend time on implementation details like state that SPA suddenly has to manage. On the other hand, I felt the rest of the article seemed pretty implementation focused, talking about details of how sockets could be used - I do have decent web dev experience but grasping the practicality of the concept based on what was described was beyond me.
That said, I love the first part that is talking about simplifying the web app development, to make it similarly simple as it was 10 years ago, but I can hardly imagine that solution to that is replacing one piece of underlying technology with another piece. I imagine that instead, we need a higher level of abstraction that will hide all the implementation details that we don't care about and capture that what is common through time, so we don't have to care if we are using websockets or http or smth else underneath - instead we say how we want data to behave, and it gets done. Dealing with HTTP or sockets should be reserved for advanced use cases, not typical web apps. I am working on a concept of this, open-source web dev DSL, still in alpha though: https://wasp-lang.dev , and while I can't be sure that it is the exact solution, I imagine something similar in the future, a DSL. At the end, frameworks are a step in that direction (embedded DSLs), it is just that they are not standalone languages and are therefore again pretty coupled with the language and architecture they are modeling.
Why do you think DSLs are not the full solution? My main thought was that having DSLs for specific areas of programming domains is the way to go. But they should have interop with Turing complete languages to implement specific sub-parts. That way DSLs can capture a lot of knowledge and best practices that we learned through years in that domain while still facilitating innovation being flexible. Such language would be very limited, more like "smart configuration languages". Some of them I have seen around are Terraform, Nextflow, Meson-build.
APL still sounds too general and self-sufficient to me to be a solution to this (but I don't know much about it so maybe I am wrong, I just checked it out on the wikipedia).
In our case, server is github so that is allright, but script is on master, so that is tricky because we might update it at any moment, so you should check it once it is downloaded. That is a concern for sure, and there are ways to remove that concern.
One thing that goes to our benefit though is that we are not requiring `sudo`.
Thanks for pointing all this out, we will certainly be looking into better ways to install Wasp in the future!
That said, we have not completely ditched idea of using NPM as installation mechanism, but we haven't convinced ourselves yet - maybe we should give it more thought though. What do you think is the benefit of using NPM vs our install script? Why would you trust NPM package more? Both NPM package and our install script are open source and you can see the code, both have equal execution privileges on your machine - why would you trust NPM package more?
The usual situations we get into is that people at the beginning can't remember which one has which name. Luckily, often it is also not important hehe :D.
The worst situation we had so far was probably when we were applying for our first year of uni - our applications looked so similar that they thought it was the same application sent twice by mistake, so they took into account only one of the applications! Luckily we realized on time that something is wrong and were able to appeal :D.