TL;DR
Server-side Swift has some big disadvantages comparing to other languages / frameworks and it is missing some key features (ecosystem, stability, tooling). There are some niches, where using Swift is a good solution, but very often it isn't.
Issues
Safety (one of the marketing advantages)
One of the advantages of Swift is safety. Yes, it removes a lot of possible issues, but it is still away from safe:
- Low stack size on secondary threads (5120kb), the app will crash if the stack size isn't big enough: Increase size of stack
- Lacy variables are not thread safe
- Parts of the standard library still crash like:
Dictionary(_:uniquingKeysWith:)
: Apple Developer Documentation - Crash for handling integer overflows
Special for Server-side applications a crash means always a downtime and has the potential of an incident for your service.
There are ways to minimise the issue like:
- Proxy in front of the Swift application who detects such issue
- Cache bad request
- Restart Swift application fast with tools like supervisor
- Load balancer
- ...
But: It is a lot of extra work, there are no guidelines, it is complicated to find the reason of a crash, ...
Performance
It is possible to write fast Swift code, but it isn't easy.
Why I believe it is not easy:
- Network driver implemented in multiple languages, swift is one of the slowest: GitHub - ixy-languages/ixy-languages: A high-speed network driver written in C, Rust, C++, Go, C#, Java, OCaml, Haskell, Swift, Javascript, and Python
- Benchmarks Game which compares multiple benchmarks, swift is sometimes close to languages like c/rust, but sometimes far away from it: Which programming language is fastest?
- Comparisons of web frameworks, swift is sometimes as fast as node: GitHub - kjessup/CENGN-Perfect Swift vs .NET Core — Benchmark. Before you choose language/platform for… | by Marcin Czachurski | ITNEXT Updated Benchmarks for the Top Server-Side Swift Frameworks vs. Node.js | by Ryan Collins | Medium
- Our application :D
Some of the issues are:
- ARC: yes, we all love it, but counting the references costs time
- Copy on Write and there is no easy way to find such places within the code: "High Performance Systems in Swift": High Performance Systems in Swift – Cory Benfield at Hacking with Swift Live 2019 - YouTube
- Values <-> Classes: Its hard to understand the drawbacks (when it comes to performance). With classes you always have the issue of ARC and of the heap, with values you have issue of copying (special for large structures), you have the issue of a potential stack limit and the issue of references within values
- There is no good documentation / guidelines when it comes to performance
- There is no good way to measure the performance:
- Instruments: Not possible to deal with big call stacks
- The integrated performance tests are useless, because they are running without optimisation
It feels like: If you want to write fast Swift code you have to:
- Write custom benchmark tools
- Search for non-planned COWs
- Find the right balance by using References or Values
- Deal with pointers
- (Non)performant operations are hidden to the engineers and you have to try them out
Swift will have a ownership model (like Rust) in the future and this will improve the situation of some of the issues.
Tooling
SPM
- No possibility of already compiled libraries
- No resource support
- The checkout of dependencies stuck sometimes without any progress
- Bad error messages if there is a typo in you Package.swift
- The output of the tests is overwhelming, using
--parallel
help, but than it's hard to understand when a test was crashing - There are always some small issues like:
- You need an empty LinuxMain.swift: Test discovery on Linux
- We had a package with the name
TestSupport
, which clashed with the same named package of the SPM O_O - Running multiple tests with the
filter
option is slower than without
Xcode
- You have to download >5GB for every release
- The used Swift version in Xcode is not always in sync with the released version of Linux or apples docker image: GitHub - apple/swift-docker: Docker Official Image packaging for Swift
- Limited SPM support
- Limited Test support (disabling tests, running categories of tests, performance tests, ...)
- Its hard to use other tools and very often they have other issues because they can't integrate it like apple (like AppCode or CLion)
- Does not run on Linux, but when you main target is Linux this creates some extra work
- Switching branches doesn't work well enough, sometimes only "Clean Product" and recreating the Xcode project helps
Compiler + Errors
- The error messages of the Swift compiler are in the best case ok, sometimes a joke (
too complex to be solved
) and sometimes they lead you into a wrong direction, special when it comes to generics, function overloading - Slow compile times in general
- The compile times are not predictable
- Splitting up the code into modules has some advantages and disadvantages related to compilation times
- The "good old" trick to combine all files into one still improves the compilation sometimes (
SWIFT_WHOLE_MODULE_OPTIMIZATION=YES
), even after the new build system - A change of one test case sometimes means you have to compile multiple minutes again
Ecosystem
The Server-side Swift community was always a niche and it feels like it hasn't grown a lot.
If there is an issue which is not covered by the starting tutorials you are very often alone with it. The Swift forum is at least a good place to get in contact and have one first place to follow the discussions.
There is no easy way to find package and many packages are abandoned. There are still some good packages and in some of them you see the enthusiasm behind their project. But after IBM left the Swift ecosystem, is there any other big player in it? Is Apple able to drive such process, special with the lack of exchange with the community (I only say SwiftUI).
I'm aware that some of the issues are because of the age of the language. At some parts you can see improvements like:
- Swift language service: GitHub - apple/sourcekit-lsp: Language Server Protocol implementation for Swift and C-based languages
- Apple is creating own docker images: GitHub - apple/swift-docker: Docker Official Image packaging for Swift
- ...
Conclusion
A lot of the claimed advantages (safety, performance) are true comparing to objective c, but not when you compare it with more mature languages like Java/Kotlin/Scale, node or elixir/erlang.
I don't want to say that you should not use Swift on the server, but Swift on the server has some pain points and you should be aware of it.
I still feel that Server-side Swift has a big potential but on the other hand I'm not sure if swift has to be everywhere. Swift has already started with a big backpack ((objective) c compatibility, fast as c, tools / environment to create apps, apple has big impact on the development, ...). Running it on a different OS and for a different reason is a challenge and comes with a cost.
Out of this post I can easily create a whish list how to improve the situation. And I hope Apple is taking the Server-side Community more serious and improve some of the situation. Some the issues can possibly be improved by the community, but I have the feeling that the community already has to do a lot of stuff.
Background
We are using Server-side Swift since more than 4 years. This means:
- We started to migrate our Swift Code to run on Linux with the first Swift snapshot for Linux (October 2016)
- We were using it on production since Swift DEVELOPMENT-SNAPSHOT-2016-03-01-a
- We have gone through all the pain of:
- Migrating code from one Swift version to the next one
- Bugs which existed only on Linux
- Non existing Swift mature Web Frameworks
- Our application: Mathematical application within a docker container behind a web framework. > 120.000 loc and over 11.000 tests