The creator of Vapor talks about what’s new in Vapor 3
With the release of Swift 4.1, work on Vapor 3 is finally on the verge of being complete and the team are busy tagging all the Vapor repositories for the 3.0 release.
Vapor 3 changes a huge amount from Vapor 2, so I sat down with Tanner Nelson – founder and lead developer on the Vapor project – to ask him what was changing and why, as well as what it’s like working on the very cutting edge of Swift…
Swift Developer News: A lot of folks have been trying out Vapor since the early days, and for them Vapor 3 is going to be a big change. What was it that prompted you to make such a big change for this release?
Tanner Nelson: Building Vapor 1 was a very much an exploratory and educational process. Swift is a really unique language (especially when compared to languages commonly used for web development) so there was a lot of ground to cover in terms of designing server-side APIs. We ended up taking lots of inspiration from web frameworks that we had used in the past and liked.
In the same way that Swift 3 shed a lot of the Objective-C baggage and defined clearly what Swift should look like, Vapor 3 is defining what Swift on the server should look like.
That was a great first step, but the end goal was always to create a web framework that is totally Swift from start to finish – and that's what Vapor 3 is. I think it's similar to Swift 3 in that sense. In the same way that Swift 3 shed a lot of the Objective-C baggage and defined clearly what Swift should look like, Vapor 3 is defining what Swift on the server should look like.
SDN: I know we’ve talked in the past about how Vapor 3 is as big a break as Swift 3 was – does this mean there’s hope that Vapor 4 might be more incremental and additive?
TN: Yes, definitely. One of our primary goals for Vapor 3 is to get the API to a point of stability. Swift is still very much growing and changing as a language, so don't expect stability like Java, PHP, Ruby, etc frameworks. But I believe when you look at Vapor again in 10 years, 3.0 will still have been the biggest change.
SDN: One of the things that struck me when writing the book was how hard you’re making Swift work – lots of Codable, keypaths, protocol extensions, generics, and associated types, and with Swift 4.1 even cutting-edge features like conditional conformances. Do you think all that makes Vapor 3 easier or harder to learn and use?
TN: One of Vapor's core concepts is to push as many errors as possible from runtime to compile time. Most of the languages commonly used for web development have very limited type systems and this causes developers a lot of pain. I can attest to that from personal experience.
Each of those Swift features you listed have allowed us to make certain common developer mistakes impossible in Vapor 3. For example, key paths allow Fluent to type check and verify filters on a query builder.
If you change the name of a property in Fluent, you will see exactly which places in the code are affected before even running your application.
This gets rid of a ton of duplicated (and typo-prone) strings that most ORMs rely on. If you change the name of a property in Fluent, you will see exactly which places in the code are affected before even running your application. Working with a strict type system can seem like it takes longer or is more difficult at first, but in the end it leads to more resilient code that you will not need to spend nearly as much time maintaining later on.
SDN: What was it like developing Vapor while Swift itself was also developing so quickly – Swift 4.1 literally only just got released!
TN: It's been quite an experience. I've learned so much about Swift and programming in general along the way. Things were especially crazy at the very beginning with Swift 2.2. It was like the wild west as Logan [Wright; co-founder of Vapor] has said. We had to invent literally everything that wasn't the core Swift language itself.
Since then Swift on Linux – especially Foundation – have really grown. And of course we have SwiftNIO now which is an incredible IO layer. Vapor is able to push a huge amount of work to Foundation and SwiftNIO now which makes my life easier, makes Vapor more stable, and increases the interoperability of server-side Swift packages.
I think if things continue at this rate, the future of server-side Swift is very bright.
SDN: Speaking of SwiftNIO, Apple announced it towards the end of Vapor 3's development. What effect did that have on your work?
TN: I've seen a surprising amount of people thinking that the server-side Swift community or the Swift Server working group was somehow blind-sided by SwiftNIO. That couldn't be farther from the truth. We had known about SwiftNIO before the first line of Vapor 3 code was even written.
Obviously Apple can never make promises about a timeline and I was surprised that [SwiftNIO] came out so quickly.
Obviously Apple can never make promises about a timeline and I was surprised that it came out so quickly. But Vapor 3 was built with NIO's architecture in mind so it was relatively easy (and was the goal since the beginning) to transition. I'm just glad it came out before the official 3.0.0 tag so that we didn't have to wait until Vapor 4!
SDN: You mentioned the Swift Server working group, which was formed as part of Swift.org to help find common ground between the various server-side Swift projects. How has that worked out for Vapor?
TN: There wasn't really a lot we could do in the working group prior to SwiftNIO being released. Although we knew what NIO would look like, it's hard to gather community consensus building things on top of something that didn't exist then.
Now that NIO is here, I think the working group is due for revitalization. It will always be a core goal of Vapor to create code that benefits the entire server-side Swift ecosystem, not just the Vapor framework itself. That's why we put so much effort into maintaining separate repos with carefully curated dependency trees and why we are so excited to be using SwiftNIO now.
SDN: Do you think it’s realistic that developers can port Vapor 2 code to Vapor 3, or has so much changed that it’s probably best to do a rewrite?
TN: If you designed your code to be very protocol-oriented and modular, then you should be able to re-use a lot of it going forward. However, you should at least start with a fresh template and copy-paste things over since the core architecture is different.
If the project you are creating ever becomes popular, you will be very grateful that you built it the right way from the start.
If you are coming from Vapor 2, you should also take time to understand the new concurrency (async) architecture. Some hacky stuff you could get away with in Vapor 2, like creating global singletons synchronized with
NSLock, is just not going to work with the multi-reactor concurrency architecture in Vapor 3. Understanding these things will probably be the hardest thing for people – but it really is the right thing to do.
If the project you are creating ever becomes popular, you will be very grateful that you built it the right way from the start.
SDN: The huge switch to an asynchronous structure is probably one of the biggest changes in Vapor 3. What does it mean for developers? Do you think it will take more time to learn?
TN: Yes, it will take time to learn – especially learning futures if you have never used those before. But these are things that I believe web developers really must understand if they want to create high-concurrency applications.
Even after Swift gets the
await keywords, understanding how async works under the hood and how Futures work will help you write better code.
SDN: I know true
await support is something you’re very keen on – when it finally lands in Swift 6 or beyond, how much do you think it will affect the fundamentals of working with Vapor?
TN: The goal is that once Swift adds
await, we will be able to offer a synchronous API more similar to what was in Vapor 2. Whether that is just syntax sugar on top of futures or fundamentally
await all the way down is hard to say now because we don't know exactly how it will be implemented in the compiler yet. Either way, it should mean that developers get a cleaner, simpler API while still maintaining all the benefits of async.
There's still a lot of work for Apple to do figuring out how
await will work with Dispatch (for iOS and macOS) and that seems to be the main blocker. My guess would be we see more talk about how
await will be implemented during Swift 5's development including some low-level groundwork laid out, then we see the implementation land in Swift 6.
SDN: One of Vapor’s best-known features is its Fluent framework for database access. How has that evolved and matured in Vapor 3?
TN: Fluent has changed a lot since its first iteration in Vapor 1. In the beginning, Fluent was designed to be an air-tight abstraction around any database you might want to use with your application.
Fluent is no longer the ORM you deal with directly, instead it is a toolkit for building ORMs.
That seemed like a great idea at first, but as time went on it became very difficult to offer first-class support for each database's unique characteristics. Fluent 2 began to invert that architecture and now in Fluent 3 this idea has been fully realized.
Fluent is no longer the ORM you deal with directly, instead it is a toolkit for building ORMs. For example, if you are using MySQL, you will use and import
FluentMySQL. This has allowed us to take much better advantage of each database's unique feature set and I think it makes working with your database feel much more seamless.
This new architecture should make it possible to create great Swift integrations for all types of databases and I can't wait to see what people build with it.
SDN: When writing the projects in my book, it was remarkable how well Fluent tied in to Codable – is it fair to say that most folks will find they can add Fluent database support in only a dozen or so lines of code?
A lot of Fluent 3's more concise syntax is thanks to the brilliance of Swift's protocols and protocol-oriented programming in general.
TN: I'm glad to hear that! Reducing the amount of boilerplate was a big goal for Fluent 3 and always will be going forward. There's always need to be cautious when making things more concise that they don't become difficult to understand or overly "magic".
A lot of Fluent 3's more concise syntax is thanks to the brilliance of Swift's protocols and protocol-oriented programming in general. By utilizing protocols, codable, and extensions, Fluent is able to do a lot of things for you automatically in a way that is understandable and can always be overridden.
SDN: Even though Vapor was known for Fluent previously, when discussing Vapor 3 most folks are talking about how it should be screamingly fast – is that largely down to its asynchronous nature, or did other work also contribute?
TN: A ton of work has gone into making all parts of Vapor fast. Async is the most obvious one, but there are so many moving parts in a web application and you can only be as fast as your weakest link.
That's why, at release, Vapor 3 is including database drivers for Redis, MySQL, and PostgreSQL that have been built from the ground up in pure Swift to be as performant and efficient as possible (with more database types coming soon).
Other things like Codable and the new Services architecture have played an important role as well in making things faster. I think Vapor's tightly integrated ecosystem is one of its best qualities and what will allow Vapor 3 to be one of the fastest web frameworks out there.
SDN: Do you have any early indications of performance compared to other frameworks?
Vapor will be unmatched given its tightly integrated packages sharing the same async architecture.
TN: I'll be doing some open source benchmarks and full write up soon, so I want to hold off giving exact numbers until then. But Vapor 3 is very fast. Our goal is to be as fast or faster than frameworks written in Golang for a plaintext benchmark. We're very close to that currently and I think with the HTTP optimizations NIO has in the pipeline that should be a reality soon.
In terms of real-world performance (things including a database, view rendering, etc), Vapor will be unmatched given its tightly integrated packages sharing the same async architecture.
SDN: Although performance is definitely important, many people will feel that functionality and usability comes first – “does this feel like a great way to build websites and APIs?” What do you think sets Vapor apart when compared to alternatives such as Ruby on Rails or Laravel?
If you have zero concern for performance and only want something easy, then Vapor might not be the right choice for you.
TN: Functionality and usability are definitely important, but I don't believe they come first. I think those matters need to be evaluated on a case-by-case basis.
For Vapor 3, there are definitely some usability tradeoffs we made for the sake of performance. If you have zero concern for performance and only want something easy, then Vapor might not be the right choice for you. There are definitely web frameworks out there that are easier to use and there are definitely web frameworks out there that are faster.
That said, I do think we managed to create a wonderful API and I think you will be hard pressed to find another web framework that is as concise and expressive as Vapor while also being as performant.
SDN: I think it’s fair to say that Vapor 3 is “Swifty” – it feels natural to Swift developers approaching it for the first time.
TN: I'm very glad to hear that!
SDN: Vapor has done a lot of work to advance server-side Swift, but IBM’s Kitura is doing some great work too. What do you see as Kitura’s strengths compared to Vapor 3?
Vapor… is higher level and more opinionated.
TN: I think Kitura is a great framework and I'm excited to see how it continues to grow over time and how they utilize SwiftNIO. Kitura is lower-level than Vapor, so it would be a good choice for projects that want something small and simple. It's a lot like express.js.
Vapor on the other hand is higher level and more opinionated. It's more like Ruby on Rails in that regard. We have a great relation with the Kitura team and I am grateful for the tremendous work they have put into Foundation on Linux (which Vapor has benefited from!).
I think Vapor and Kitura work well together as unique tools in the tool belt of server-side Swift developers.
SDN: Do you think there’s room for more collaboration between server-side Swift projects?
TN: Yes, definitely. I believe collaboration and compatibility between frameworks will be crucial to the success of server-side Swift. The more we can re-use code and move our focus to solving novel problems, the better.
Swift is a really modular language and SPM is built on solid principles that makes sharing code reliable and easy, so sharing code should be easy. I think NIO is a huge step in the right direction here and I think things will continue to get even better.
SDN: In closing, what’s the best piece of advice you’d give to Swift developers coming fresh to Vapor for the first time?
TN: The best way to learn is by doing!
SDN: Dive in and hope for the best?
TN: Yup. I know a guy that wrote a great book about it, too. So maybe pick that up!
SAVE 20% ON iOS CONF SG The largest iOS conference in Southeast Asia is back in Singapore for the 5th time in January 2020, now with two days of workshops plus two days of talks on SwiftUI, Combine, GraphQL, and more! Save a massive 20% on your tickets by clicking on this link.
Paul Hudson is the creator of Hacking with Swift, the most comprehensive series of Swift books in the world. He's also the editor of Swift Developer News, the maintainer of the Swift Knowledge Base, and a speaker at Swift events around the world. If you're curious you can learn more here.