# 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"}
    256 views
   owned this note