# FTL
---
## Introduction
FTL is a framework for building distributed systems that are safe to operate and easy to reason about.
---
## How is it different?
1. Language agnostic, code first
2. Whole-system static analysis
3. Infrastructure as code, not YAML
4. Fearlessly modify types
5. Incredibly fast development cycle
---
### Language agnostic, code first
Go calling a function in Kotlin:
```go
//ftl:export
func Echo(ctx context.Context, name string) (string, error) {
now, _ := ftl.CallSource(ctx, timemodule.Time)
return fmt.Sprintf("Hello, %s! It is %s.", name, now)
```
Kotlin:
```kotlin
@Verb @Export
fun time(): OffsetDateTime {
return OffsetDateTime.now()
}
```
*No IDL: no Protobuf, no Thrift, no JSON Schema.
Just code.*
---
### Whole-system static analysis
FTL statically extracts a schema from source code that describes all functions, types, resources and the topology of the system.
```shell
$ ftl schema
module time {
export verb time() Time
}
module echo {
export verb echo(String) String
+calls time.time
}
```
---
### Infrastructure as _Actual Code_, not YAML
Below, we declare that we need a MySQL database, define a query and call the query:
```go
var echodb = ftl.MySQLDatabase("echodb")
func Echo(ctx context.Context, name string) (string, error) {
echodb.InsertGreeting(name)
}
```
```sql
-- name: insertGreeting :exec
INSERT INTO greetings (name) VALUES (@name);
```
FTL will automatically provision the database, generate SQL mapping types and functions, update ACLs to allow access, and inject a connection.
---
### Why care about a schema?
Before we deploy our change above, FTL let's us see what has changed since the previous deployment:
```shell
$ ftl schema diff
module echo {
+ database mysql echodb
+
+ query verb insertGreeting(Greeting)
+ +query "INSERT INTO greetings (name) VALUES (@name)"
+ +sqlwrite echodb.greetings.name
+
export verb echo(String) String
+calls time.time
+ +calls echo.insertGreeting
```
FTL uses this information to safely support making changes to the system, disallowing breaking changes.
---
### Utilising the schema
Pull requests will display the schema diff, letting reviewers make informed decisions based on what infrastructure and function have been added, removed and modified.
Static analysis tools can also operate on the schema, allowing for automated checks of infrastructure changes, applying security policies, adding additional reviewers, and so on.
---
### Fearlessly modify types
Imagine we now need to change the `time` function's return type from a bare `Time` to a data structure:
```kotlin
data class TimeResponse(val time: OffsetDateTime)
@Verb @Export
fun time(): TimeResponse {
return Timeresponse(time = OffsetDateTime.now())
}
```
Deploying this would be a breaking change in traditional RPC systems, but FTL supports it by keeping the previous version of `time` alive to serve existing clients. Once all references to the old version are replaced, the old version is removed.
---
### Incredibly fast development cycle
One of the primary goals of FTL is to increase developer velocity, while ensuring that changes are safe.
Live reload, fully local development, function injection into existing clusters, easy fakes for unit tests, and so on, are all part of the developer experience that FTL delivers.
---
### Making changes to persistent data
Back to our example, we realise that we're storing PII data unencrypted in the database, and we attempt to alter our database schema accordingly:
```sql
ALTER TABLE greetings ALTER COLUMN name TYPE FULL_NAME;
```
FTL disallows this at compile time because it's a breaking change to persistent state:
```text
error: cannot alter database column echodb.greetings.name,
changing type is a breaking change
```
---
Prevented from accidentally breaking our system, we instead add a new column and backfill it:
```sql
ALTER TABLE greetings ADD COLUMN encrypted_name FULL_NAME;
```
```go
//ftl:backfill echodb.greetings
func EncryptName(ctx context.Context, rows []Greeting) error {
// Encrypt "name" and write it into "encrypted_name"
}
```
FTL now allows this schema change because it is backwards compatible.
---
### Semantic types
We also alter our function to use a semantic type that captures the desired intent:
```go
type EchoFullName = ftl.SemanticType[FullName, string]
//ftl:export
func Echo(ctx context.Context, name EchoFullName) (string, error) {
// ...
}
```
The FTL database integration recognises the semantic type and automatically encrypts and decrypts the value when inserting into and selecting from the database.
---
### Provenance
Semantic types also allow us to trace provenance. As values move through the system they can be annotated with each node they pass through.
In the above example, the "name" parameter might end up with a trace something like this:
```text
echo.name
-> echo.insertGreeting.name
-> echodb.greetings.name
```
{"description":"Author: @USER","contributors":"[{\"id\":\"c4a73880-dc3a-40ed-b3f1-8e1994e13af9\",\"add\":8302,\"del\":4791}]","title":"FTL"}