SlideShare a Scribd company logo
About me:
@AntyaDev
like types*
- Biggest provider in sport offering
- Supports a lot of regulated markets
- About 1000 microservices (200 distinct types)
- 5 datacenters maintained fully by SBTech
- About 500 concurrent live events at pick time
- On average we handle about 100K+ RPS
highload and
near real time
Why F#?
Why F#?
If we have
sexy C#
If we have sexy C#
class Person
{
public string FirstName; // Not null
public string? MiddleName; // May be null
public string LastName; // Not null
}
If we have sexy C#
switch (shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Square s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
}
If we have sexy C#
public (string, string) LookupName(long id)
{
// some code..
return (first, middle);
}
var names = LookupName(id);
WriteLine($"found {names.first} {names.last}.");
Why F#?
If we have
sexy C#
1 day
Story of a new C# project
Get("/api/bets", async request =>
{
var result = Validator.Validate(request); // unit testable
if (result.IsOk)
{
var response = await _httpClient.Call(request);
return BetsMapper.MapResponse(response); // unit testable
}
else return Errors.MapError(result); // unit testable
});
1 day
In 1 week
public class BetsProviderService : IBetsProviderService
{
readonly IOpenBetsRepository _openBetsRepository;
readonly ISettledBetsRepository _settledBetsRepository;
public BetsProviderService(IOpenBetsRepository openBetsRepository,
ISettledBetsRepository settledBetsRepository)
{
_openBetsRepository = openBetsRepository;
_settledBetsRepository = settledBetsRepository;
}
}
Story of a new C# project
Different Culture
OOP FP
abstraction
extensibility
purity
composability
correctness
Triggers:
Much better tooling support
Community growth
Recursive modules
Tooling support
Visual Studio
RiderVisual Studio Code
Recursive modules
type Plane() = member x.Start() = PlaneLogic.start(x)
// types and modules can't currently be mutually
// referential at all
module private PlaneLogic =
let start (x: Plane) = ...
Recursive modules
module M
type First =
| T of Second
and Second =
| T of First
Recursive modules
module M
type First =
| T of Second
type Second =
| T of First
Recursive modules
module rec M
type First =
| T of Second
type Second =
| T of First
Recursive modules
module M
let private helper () = ...
let publicApiFunc () = helper()
Recursive modules
module rec M
let publicApiFunc () = helper()
let private helper () = ...
Community growth
• To begin, F# has grown to be bigger than ever, at least as far as
we can measure, through product telemetry, twitter activity,
GitHub activity, and F# Software Foundation activity.
• Active unique users of F# we can measure are in the tens of
thousands.
• Measured unique users of Visual Studio Code
with Ionide increased by over 50% this year, to become far larger
than ever.
• Measured unique users of Visual Studio who use F# increased by
over 20% since last year to be larger than ever, despite quality
issues earlier in the year that we believe have inhibited growth.
• Much of the measured growth coincides with the release of .NET
Core 2.0, which has shown significant interest in the F#
community.
namespace SportData.ETL.Core
type ItemRawUpdate<'Item> = {
Id: string
Data: 'Item option
}
module TransformationFlow =
let getUpdates (feed: ChangeFeed, lastOffset: uint32) =
Code Style
Code sample
let createGame (globalCache: GlobalItemsCache,
masterEvent: MasterEventItem, currentTime: DateTime) = trial {
let! league = Cache.get(globalCache.Leagues, masterEvent.LeagueID)
let! country = Cache.get(globalCache.Countries, league.CountryID)
let! sport = Cache.get(globalCache.Branches, masterEvent.BranchID)
...
return { Id = masterEvent.ID.ToString()
Type = getEventType(masterEvent) }
}
I need website
Website
SBTech story
I need an API
to build
unique UI
The Problem
Oops?!
The Problem
Oops?!
1. well defined contracts (Event, Market, Selection)
2. flexible way to query data and subscribe on changes
3. push updates notifications about changes
4. near real time change delivery (1 sec delay)
We need to provide:
PUSH based
Queryable API
(Change Feed)
select * from Games where isLive = true
order by totalBets desc
limit 10
PUSH changes
Change Feed
(Actor)
Change Stream
Feed View
2:2
1:0 Chelsea - Milan
Milan - Liverpool
Subscribers
Feed View
2:2
1:0 Chelsea - Milan
Milan - Liverpool
Change Log
Query
Change Feed
(Actor)
Subscribers
type NodeName = string
type LastHeartBeat = DateTime
type NodeSubscribers = Map<NodeName, LastHeartBeat>
type FeedStatus =
| ReadyForDeactivation
| HasSubscribers
| NoSubscribers
type ChangeFeed = {
Id: FeedId
View: FeedView
ChangeLog: ChangeLog
Subscribers: NodeSubscribers
Query: Query
Status: FeedStatus
}
Query
Feed View
2:2
1:0 Chelsea - Milan
Milan - Liverpool
Change Feed
Change Log
module ChangeFeed
let getSnapshot (feed: ChangeFeed, fastPreloadAmount: uint32) = ...
let getUpdates (feed: ChangeFeed, lastOffset: uint32) = ...
let getLatestUpdate (feed: ChangeFeed) = ...
let subscribe (feed: ChangeFeed, name: NodeName, currentTime: DateTime) = ...
let subscribeByOffset (feed: ChangeFeed, name: NodeName, lastOffset: uint32) = ...
let unsubscribe (feed: ChangeFeed, name: NodeName) = ...
let getInactiveNodes (feed: ChangeFeed, currentTime: DateTime, inactivePeriod: TimeSpan) = ...
let reloadView (feed: ChangeFeed, queryResults: QueryResult seq) = ...
Feed View
2:2
1:0 Chelsea - Milan
Milan - Liverpool
type PartialView = {
EntityType: EntityType
Entities: IEntity seq
}
type FeedView = {
OrderType: EntityType
OrderIds: string seq
OrderFilter: FilterFn option
Views: Map<EntityType, PartialView>
}
let tryCreate (queryResults: QueryResult seq, orderType: EntityType,
orderFilter: FilterFn option) =
match queryResults with
| NotMatchFor orderType -> fail <| Errors.OrderTypeIsNotMatch
| Empty -> ok <| { OrderType = orderType; OrderIds = Seq.empty
OrderFilter = orderFilter; Views = views }
| _ -> ok <| ...
[<Property>]
let ``empty ChangeLog should start with offset 0 and requested maxSize`` (maxSize: uint32) =
let changeLog = ChangeLog.create(maxSize)
Assert.Equal(0u, changeLog.Offset)
Assert.Equal(maxSize, changeLog.MaxSize)
[<Property(Arbitrary=[|typeof<Generators.Generator>|])>]
let ``all changes in changeLog.stream should have UpdateType.Update`` (payloads: Payload array) =
let mutable changeLog = ChangeLog.create(5u)
for p in payloads do
changeLog <- ChangeLog.append(changeLog, p)
let result = changeLog.Stream.All(fun change -> change.Type = UpdateType.Update)
Assert.True(result)
TDD without Mocks
We have our own frontend
but
we need a Data
The Next Challenge
Oops?!
SBTech
All changes
Operator
RDBMS
All changes
from
40 tables
ETL
Operator
Well defined entities
compose entities
react on changes
recalculate odds
(data locality)
C#
F#Asp NET Core
Orleans
DB Drivers
[ DDD; Tests]
Infrastructure
business logic
public Task<FullFeedUpdate> GetSnapshot(GetSnapshot msg)
{
// invoke F# code from C#
var updates = ChangeFeedModule.getSnapshot(FeedState, msg.FastPreloadAmount);
return updates;
}
Applied at the heart of the system
Zero Null Reference exceptions
Domain errors instead of exceptions
DDD with types (strong determinism)
Dependency Rejection
TDD without mocks (property based testing)
http://nbomber.com
- Technology agnostic
(no dependency on HTTP, WebSockets, SSE)
- Very simple API
(to test Pull and Push scenarios)
- CI/CD integration
- Technology agnostic
(no dependency on HTTP, WebSockets, SSE)
- Very simple API
(to test Pull and Push scenarios)
- CI/CD integration
- Technology agnostic
(no dependency on HTTP, WebSockets, SSE)
- Very simple API
(to test Pull and Push scenarios)
- CI/CD integration
- Technology agnostic
(no dependency on HTTP, WebSockets, SSE)
- Very simple API
(to test Pull and Push scenarios)
- CI/CD integration
type Step =
| Request of RequestStep // to model Request-response pattern
| Listener of ListenerStep // to model Pub/Sub pattern
| Pause of TimeSpan // to model pause in your test flow
type TestFlow = {
FlowName: string
Steps: Step[]
ConcurrentCopies: int
}
type Scenario = {
ScenarioName: string
TestInit: Step option
TestFlows: TestFlow[]
Duration: TimeSpan
}
let execStep (step: Step, req: Request, timer: Stopwatch) = task {
timer.Restart()
match step with
| Request r -> let! resp = r.Execute(req)
timer.Stop()
let latency = Convert.ToInt64(timer.Elapsed.TotalMilliseconds)
return (resp, latency)
| Listener l -> let listener = l.Listeners.Get(req.CorrelationId)
let! resp = listener.GetResponse()
timer.Stop()
let latency = Convert.ToInt64(timer.Elapsed.TotalMilliseconds)
return (resp, latency)
| Pause time -> do! Task.Delay(time)
return (Response.Ok(req), 0L)
}
type TestFlowRunner(flow: TestFlow) =
let createActors (flow: TestFlow) =
flow.CorrelationIds
|> Set.toArray
|> Array.map(fun id -> TestFlowActor(id, flow))
let actors = createActors(flow)
member x.Run() = actors |> Array.iter(fun x -> x.Run())
member x.Stop() = actors |> Array.iter(fun x -> x.Stop())
member x.GetResult() = actors
|> Array.collect(fun actor -> actor.GetResults())
|> TestFlowStats.create(flow)
// C# example
var flow = new TestFlow(flowName: "READ Users",
steps: new[] {step1, step2, step3},
concurrentCopies: 10);
new ScenarioBuilder(scenarioName: "Test MongoDb")
.AddTestFlow(flow)
.Build(duration: TimeSpan.FromSeconds(10))
.RunInConsole();
// F# example
let flow = { FlowName = "GET flow"
Steps = [step1; step2; step3]
ConcurrentCopies = 100 }
Scenario.create("Test HTTP https://github.com")
|> Scenario.addTestFlow(flow)
|> Scenario.withDuration(TimeSpan.FromSeconds(10.0))
|> Scenario.runInConsole
var httpClient = new HttpClient();
var httpStep = Step.CreateRequest("GET request", execute: async _ => {
var response = await httpClient.SendAsync(request);
return response.IsSuccessStatusCode
? Response.Ok()
: Response.Fail();
});
var pause_1s = Step.CreatePause(duration: TimeSpan.FromSeconds(1));
var scenario = new ScenarioBuilder("Test HTTP")
.AddTestFlow("PULL", new[] { httpStep, pause_1s }, concurrentCopies: 10)
.Build(duration: TimeSpan.FromSeconds(10));
scenario.RunInConsole();
RDBMS
Storage
Kafka ETL
Kafka
NoSQL
Storage
Push
API
- 1470 LOC
- (4) OOP objects
- (~100) functions
- try/catch used 2 times
async { let! x = myFunction()
match x with
| Some v -> ...
| None -> ... }
F# vNext
match!
async { match! myFunction() with
| Some v -> ...
| None -> ... }
F# vNext
match!
F# vNext
Struct Records
type Vector3 = { X: float; Y: float; Z: float }
[<Struct>]
type Vector3 = { X: float; Y: float; Z: float }
F# vNext
Struct Records
[<Struct>]
type Result<'T,'TError> =
| Ok of 'T
| Error of 'Terror
[<Struct>]
type ValueOption<'T> =
| Some of ‘T
| None
F# vNext
Anonymous Records
type Data = {
X: int
Y: string
}
let data = { X = 1; Y = "abc" }
F# vNext
Anonymous Records
let data = {| X = 1; Y = "abc" |}
F# vNext
Structural Type System
type User() =
member this.GetName() = "test user"
type Car() =
member this.GetName() = "test car"
let inline printName (x: ^T when ^T : (member GetName: unit -> string)) =
x.GetName()
|> Console.WriteLine
F# vNext
Applicative functors
validate {
let! name = validateName(name)
let! age = validateAge(age)
let! email = validateEmail(email)
return User(name, age, email)
}
F# vNext
Applicative functors
validate {
let! name = validateName(name)
and! age = validateAge(age)
and! email = validateEmail(email)
return User(name, age, email)
}
F# vNext
Applicative functors
parallel {
let! x = slowRequestX()
and! y = slowRequestY()
and! z = slowRequestZ()
return f(x, y, z)
}
THANKS
@antyadev
antyadev@gmail.com
@nbombertest
http://nbomber.com

More Related Content

Similar to .NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech

Swift Bengaluru Meetup slides
Swift Bengaluru Meetup slidesSwift Bengaluru Meetup slides
Swift Bengaluru Meetup slides
Pushkar Kulkarni
 
Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
Audrey Lim
 
Server Side Swift
Server Side SwiftServer Side Swift
Server Side Swift
Chad Moone
 
Types Working for You, Not Against You
Types Working for You, Not Against YouTypes Working for You, Not Against You
Types Working for You, Not Against You
C4Media
 
An Architecture for Agile Machine Learning in Real-Time Applications
An Architecture for Agile Machine Learning in Real-Time ApplicationsAn Architecture for Agile Machine Learning in Real-Time Applications
An Architecture for Agile Machine Learning in Real-Time Applications
Johann Schleier-Smith
 
Swift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS XSwift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS X
Sasha Goldshtein
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
Jens Ravens
 
XAML/C# to HTML/JS
XAML/C# to HTML/JSXAML/C# to HTML/JS
XAML/C# to HTML/JS
Michael Haberman
 
Google Wave API: Now and Beyond
Google Wave API: Now and BeyondGoogle Wave API: Now and Beyond
Google Wave API: Now and Beyond
Marakana Inc.
 
FIWARE IoT Proposal & Community
FIWARE IoT Proposal & CommunityFIWARE IoT Proposal & Community
FIWARE IoT Proposal & Community
FIWARE
 
Monitoring as an entry point for collaboration
Monitoring as an entry point for collaborationMonitoring as an entry point for collaboration
Monitoring as an entry point for collaboration
Julien Pivotto
 
Letswift Swift 3.0
Letswift Swift 3.0Letswift Swift 3.0
Letswift Swift 3.0
Sehyun Park
 
Developing apps using Perl
Developing apps using PerlDeveloping apps using Perl
Developing apps using Perl
Anatoly Sharifulin
 
Generating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPCGenerating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPC
C4Media
 
Istio's mixer policy enforcement with custom adapters (cloud nativecon 17)
Istio's mixer  policy enforcement with custom adapters (cloud nativecon 17)Istio's mixer  policy enforcement with custom adapters (cloud nativecon 17)
Istio's mixer policy enforcement with custom adapters (cloud nativecon 17)
Torin Sandall
 
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
WSO2
 
Mashing Up The Guardian
Mashing Up The GuardianMashing Up The Guardian
Mashing Up The Guardian
Michael Brunton-Spall
 
PyTorch 튜토리얼 (Touch to PyTorch)
PyTorch 튜토리얼 (Touch to PyTorch)PyTorch 튜토리얼 (Touch to PyTorch)
PyTorch 튜토리얼 (Touch to PyTorch)
Hansol Kang
 
Api
ApiApi
Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)
Andrey Volobuev
 

Similar to .NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech (20)

Swift Bengaluru Meetup slides
Swift Bengaluru Meetup slidesSwift Bengaluru Meetup slides
Swift Bengaluru Meetup slides
 
Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
 
Server Side Swift
Server Side SwiftServer Side Swift
Server Side Swift
 
Types Working for You, Not Against You
Types Working for You, Not Against YouTypes Working for You, Not Against You
Types Working for You, Not Against You
 
An Architecture for Agile Machine Learning in Real-Time Applications
An Architecture for Agile Machine Learning in Real-Time ApplicationsAn Architecture for Agile Machine Learning in Real-Time Applications
An Architecture for Agile Machine Learning in Real-Time Applications
 
Swift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS XSwift: Apple's New Programming Language for iOS and OS X
Swift: Apple's New Programming Language for iOS and OS X
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
 
XAML/C# to HTML/JS
XAML/C# to HTML/JSXAML/C# to HTML/JS
XAML/C# to HTML/JS
 
Google Wave API: Now and Beyond
Google Wave API: Now and BeyondGoogle Wave API: Now and Beyond
Google Wave API: Now and Beyond
 
FIWARE IoT Proposal & Community
FIWARE IoT Proposal & CommunityFIWARE IoT Proposal & Community
FIWARE IoT Proposal & Community
 
Monitoring as an entry point for collaboration
Monitoring as an entry point for collaborationMonitoring as an entry point for collaboration
Monitoring as an entry point for collaboration
 
Letswift Swift 3.0
Letswift Swift 3.0Letswift Swift 3.0
Letswift Swift 3.0
 
Developing apps using Perl
Developing apps using PerlDeveloping apps using Perl
Developing apps using Perl
 
Generating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPCGenerating Unified APIs with Protocol Buffers and gRPC
Generating Unified APIs with Protocol Buffers and gRPC
 
Istio's mixer policy enforcement with custom adapters (cloud nativecon 17)
Istio's mixer  policy enforcement with custom adapters (cloud nativecon 17)Istio's mixer  policy enforcement with custom adapters (cloud nativecon 17)
Istio's mixer policy enforcement with custom adapters (cloud nativecon 17)
 
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
WSO2 Product Release Webinar: WSO2 Complex Event Processor 4.0
 
Mashing Up The Guardian
Mashing Up The GuardianMashing Up The Guardian
Mashing Up The Guardian
 
PyTorch 튜토리얼 (Touch to PyTorch)
PyTorch 튜토리얼 (Touch to PyTorch)PyTorch 튜토리얼 (Touch to PyTorch)
PyTorch 튜토리얼 (Touch to PyTorch)
 
Api
ApiApi
Api
 
Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)Prompt engineering for iOS developers (How LLMs and GenAI work)
Prompt engineering for iOS developers (How LLMs and GenAI work)
 

More from NETFest

.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
NETFest
 
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE....NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
NETFest
 
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
NETFest
 
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
NETFest
 
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem....NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
NETFest
 
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
NETFest
 
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
NETFest
 
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A....NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
NETFest
 
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
NETFest
 
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
NETFest
 
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос....NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
NETFest
 
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
NETFest
 
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
NETFest
 
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com....NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
NETFest
 
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real....NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
NETFest
 
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
NETFest
 
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ....NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
NETFest
 
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali....NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
NETFest
 
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
NETFest
 
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur....NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
NETFest
 

More from NETFest (20)

.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
.NET Fest 2019. Николай Балакин. Микрооптимизации в мире .NET
 
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE....NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
.NET Fest 2019. Сергей Калинец. Efficient Microservice Communication with .NE...
 
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
.NET Fest 2019. Оля Гавриш. .NET Core 3.0 и будущее .NET
 
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
.NET Fest 2019. Оля Гавриш. Машинное обучение для .NET программистов
 
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem....NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
.NET Fest 2019. Roberto Freato. Provisioning Azure PaaS fluently with Managem...
 
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
 
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
 
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A....NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
 
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
 
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
 
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос....NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
 
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
 
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
 
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com....NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
 
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real....NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
 
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
 
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ....NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
 
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali....NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
 
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
 
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur....NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
 

Recently uploaded

Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
imrankhan141184
 
Temple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation resultsTemple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation results
Krassimira Luka
 
Main Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docxMain Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docx
adhitya5119
 
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
PECB
 
Mule event processing models | MuleSoft Mysore Meetup #47
Mule event processing models | MuleSoft Mysore Meetup #47Mule event processing models | MuleSoft Mysore Meetup #47
Mule event processing models | MuleSoft Mysore Meetup #47
MysoreMuleSoftMeetup
 
B. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdfB. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdf
BoudhayanBhattachari
 
Chapter wise All Notes of First year Basic Civil Engineering.pptx
Chapter wise All Notes of First year Basic Civil Engineering.pptxChapter wise All Notes of First year Basic Civil Engineering.pptx
Chapter wise All Notes of First year Basic Civil Engineering.pptx
Denish Jangid
 
Solutons Maths Escape Room Spatial .pptx
Solutons Maths Escape Room Spatial .pptxSolutons Maths Escape Room Spatial .pptx
Solutons Maths Escape Room Spatial .pptx
spdendr
 
spot a liar (Haiqa 146).pptx Technical writhing and presentation skills
spot a liar (Haiqa 146).pptx Technical writhing and presentation skillsspot a liar (Haiqa 146).pptx Technical writhing and presentation skills
spot a liar (Haiqa 146).pptx Technical writhing and presentation skills
haiqairshad
 
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdfবাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
eBook.com.bd (প্রয়োজনীয় বাংলা বই)
 
Film vocab for eal 3 students: Australia the movie
Film vocab for eal 3 students: Australia the movieFilm vocab for eal 3 students: Australia the movie
Film vocab for eal 3 students: Australia the movie
Nicholas Montgomery
 
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem studentsRHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
Himanshu Rai
 
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
Nguyen Thanh Tu Collection
 
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UPLAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
RAHUL
 
Constructing Your Course Container for Effective Communication
Constructing Your Course Container for Effective CommunicationConstructing Your Course Container for Effective Communication
Constructing Your Course Container for Effective Communication
Chevonnese Chevers Whyte, MBA, B.Sc.
 
Hindi varnamala | hindi alphabet PPT.pdf
Hindi varnamala | hindi alphabet PPT.pdfHindi varnamala | hindi alphabet PPT.pdf
Hindi varnamala | hindi alphabet PPT.pdf
Dr. Mulla Adam Ali
 
How to Make a Field Mandatory in Odoo 17
How to Make a Field Mandatory in Odoo 17How to Make a Field Mandatory in Odoo 17
How to Make a Field Mandatory in Odoo 17
Celine George
 
Leveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit InnovationLeveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit Innovation
TechSoup
 
writing about opinions about Australia the movie
writing about opinions about Australia the moviewriting about opinions about Australia the movie
writing about opinions about Australia the movie
Nicholas Montgomery
 
math operations ued in python and all used
math operations ued in python and all usedmath operations ued in python and all used
math operations ued in python and all used
ssuser13ffe4
 

Recently uploaded (20)

Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
Traditional Musical Instruments of Arunachal Pradesh and Uttar Pradesh - RAYH...
 
Temple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation resultsTemple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation results
 
Main Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docxMain Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docx
 
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
 
Mule event processing models | MuleSoft Mysore Meetup #47
Mule event processing models | MuleSoft Mysore Meetup #47Mule event processing models | MuleSoft Mysore Meetup #47
Mule event processing models | MuleSoft Mysore Meetup #47
 
B. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdfB. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdf
 
Chapter wise All Notes of First year Basic Civil Engineering.pptx
Chapter wise All Notes of First year Basic Civil Engineering.pptxChapter wise All Notes of First year Basic Civil Engineering.pptx
Chapter wise All Notes of First year Basic Civil Engineering.pptx
 
Solutons Maths Escape Room Spatial .pptx
Solutons Maths Escape Room Spatial .pptxSolutons Maths Escape Room Spatial .pptx
Solutons Maths Escape Room Spatial .pptx
 
spot a liar (Haiqa 146).pptx Technical writhing and presentation skills
spot a liar (Haiqa 146).pptx Technical writhing and presentation skillsspot a liar (Haiqa 146).pptx Technical writhing and presentation skills
spot a liar (Haiqa 146).pptx Technical writhing and presentation skills
 
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdfবাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
 
Film vocab for eal 3 students: Australia the movie
Film vocab for eal 3 students: Australia the movieFilm vocab for eal 3 students: Australia the movie
Film vocab for eal 3 students: Australia the movie
 
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem studentsRHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
 
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
 
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UPLAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
LAND USE LAND COVER AND NDVI OF MIRZAPUR DISTRICT, UP
 
Constructing Your Course Container for Effective Communication
Constructing Your Course Container for Effective CommunicationConstructing Your Course Container for Effective Communication
Constructing Your Course Container for Effective Communication
 
Hindi varnamala | hindi alphabet PPT.pdf
Hindi varnamala | hindi alphabet PPT.pdfHindi varnamala | hindi alphabet PPT.pdf
Hindi varnamala | hindi alphabet PPT.pdf
 
How to Make a Field Mandatory in Odoo 17
How to Make a Field Mandatory in Odoo 17How to Make a Field Mandatory in Odoo 17
How to Make a Field Mandatory in Odoo 17
 
Leveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit InnovationLeveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit Innovation
 
writing about opinions about Australia the movie
writing about opinions about Australia the moviewriting about opinions about Australia the movie
writing about opinions about Australia the movie
 
math operations ued in python and all used
math operations ued in python and all usedmath operations ued in python and all used
math operations ued in python and all used
 

.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech

  • 1.
  • 3.
  • 4. - Biggest provider in sport offering - Supports a lot of regulated markets - About 1000 microservices (200 distinct types) - 5 datacenters maintained fully by SBTech - About 500 concurrent live events at pick time - On average we handle about 100K+ RPS
  • 7. Why F#? If we have sexy C#
  • 8. If we have sexy C# class Person { public string FirstName; // Not null public string? MiddleName; // May be null public string LastName; // Not null }
  • 9. If we have sexy C# switch (shape) { case Circle c: WriteLine($"circle with radius {c.Radius}"); break; case Square s when (s.Length == s.Height): WriteLine($"{s.Length} x {s.Height} square"); break; case Rectangle r: WriteLine($"{r.Length} x {r.Height} rectangle"); break; }
  • 10. If we have sexy C# public (string, string) LookupName(long id) { // some code.. return (first, middle); } var names = LookupName(id); WriteLine($"found {names.first} {names.last}.");
  • 11. Why F#? If we have sexy C#
  • 12. 1 day
  • 13. Story of a new C# project Get("/api/bets", async request => { var result = Validator.Validate(request); // unit testable if (result.IsOk) { var response = await _httpClient.Call(request); return BetsMapper.MapResponse(response); // unit testable } else return Errors.MapError(result); // unit testable });
  • 14. 1 day
  • 16. public class BetsProviderService : IBetsProviderService { readonly IOpenBetsRepository _openBetsRepository; readonly ISettledBetsRepository _settledBetsRepository; public BetsProviderService(IOpenBetsRepository openBetsRepository, ISettledBetsRepository settledBetsRepository) { _openBetsRepository = openBetsRepository; _settledBetsRepository = settledBetsRepository; } } Story of a new C# project
  • 17.
  • 19. Triggers: Much better tooling support Community growth Recursive modules
  • 21.
  • 22.
  • 23. Recursive modules type Plane() = member x.Start() = PlaneLogic.start(x) // types and modules can't currently be mutually // referential at all module private PlaneLogic = let start (x: Plane) = ...
  • 24. Recursive modules module M type First = | T of Second and Second = | T of First
  • 25. Recursive modules module M type First = | T of Second type Second = | T of First
  • 26. Recursive modules module rec M type First = | T of Second type Second = | T of First
  • 27. Recursive modules module M let private helper () = ... let publicApiFunc () = helper()
  • 28. Recursive modules module rec M let publicApiFunc () = helper() let private helper () = ...
  • 29. Community growth • To begin, F# has grown to be bigger than ever, at least as far as we can measure, through product telemetry, twitter activity, GitHub activity, and F# Software Foundation activity. • Active unique users of F# we can measure are in the tens of thousands. • Measured unique users of Visual Studio Code with Ionide increased by over 50% this year, to become far larger than ever. • Measured unique users of Visual Studio who use F# increased by over 20% since last year to be larger than ever, despite quality issues earlier in the year that we believe have inhibited growth. • Much of the measured growth coincides with the release of .NET Core 2.0, which has shown significant interest in the F# community.
  • 30.
  • 31. namespace SportData.ETL.Core type ItemRawUpdate<'Item> = { Id: string Data: 'Item option } module TransformationFlow = let getUpdates (feed: ChangeFeed, lastOffset: uint32) = Code Style
  • 32. Code sample let createGame (globalCache: GlobalItemsCache, masterEvent: MasterEventItem, currentTime: DateTime) = trial { let! league = Cache.get(globalCache.Leagues, masterEvent.LeagueID) let! country = Cache.get(globalCache.Countries, league.CountryID) let! sport = Cache.get(globalCache.Branches, masterEvent.BranchID) ... return { Id = masterEvent.ID.ToString() Type = getEventType(masterEvent) } }
  • 34. I need an API to build unique UI The Problem Oops?!
  • 35. The Problem Oops?! 1. well defined contracts (Event, Market, Selection) 2. flexible way to query data and subscribe on changes 3. push updates notifications about changes 4. near real time change delivery (1 sec delay) We need to provide:
  • 37. select * from Games where isLive = true order by totalBets desc limit 10 PUSH changes
  • 38. Change Feed (Actor) Change Stream Feed View 2:2 1:0 Chelsea - Milan Milan - Liverpool
  • 39. Subscribers Feed View 2:2 1:0 Chelsea - Milan Milan - Liverpool Change Log Query Change Feed (Actor)
  • 40. Subscribers type NodeName = string type LastHeartBeat = DateTime type NodeSubscribers = Map<NodeName, LastHeartBeat> type FeedStatus = | ReadyForDeactivation | HasSubscribers | NoSubscribers type ChangeFeed = { Id: FeedId View: FeedView ChangeLog: ChangeLog Subscribers: NodeSubscribers Query: Query Status: FeedStatus } Query Feed View 2:2 1:0 Chelsea - Milan Milan - Liverpool Change Feed Change Log
  • 41. module ChangeFeed let getSnapshot (feed: ChangeFeed, fastPreloadAmount: uint32) = ... let getUpdates (feed: ChangeFeed, lastOffset: uint32) = ... let getLatestUpdate (feed: ChangeFeed) = ... let subscribe (feed: ChangeFeed, name: NodeName, currentTime: DateTime) = ... let subscribeByOffset (feed: ChangeFeed, name: NodeName, lastOffset: uint32) = ... let unsubscribe (feed: ChangeFeed, name: NodeName) = ... let getInactiveNodes (feed: ChangeFeed, currentTime: DateTime, inactivePeriod: TimeSpan) = ... let reloadView (feed: ChangeFeed, queryResults: QueryResult seq) = ...
  • 42. Feed View 2:2 1:0 Chelsea - Milan Milan - Liverpool type PartialView = { EntityType: EntityType Entities: IEntity seq } type FeedView = { OrderType: EntityType OrderIds: string seq OrderFilter: FilterFn option Views: Map<EntityType, PartialView> } let tryCreate (queryResults: QueryResult seq, orderType: EntityType, orderFilter: FilterFn option) = match queryResults with | NotMatchFor orderType -> fail <| Errors.OrderTypeIsNotMatch | Empty -> ok <| { OrderType = orderType; OrderIds = Seq.empty OrderFilter = orderFilter; Views = views } | _ -> ok <| ...
  • 43. [<Property>] let ``empty ChangeLog should start with offset 0 and requested maxSize`` (maxSize: uint32) = let changeLog = ChangeLog.create(maxSize) Assert.Equal(0u, changeLog.Offset) Assert.Equal(maxSize, changeLog.MaxSize) [<Property(Arbitrary=[|typeof<Generators.Generator>|])>] let ``all changes in changeLog.stream should have UpdateType.Update`` (payloads: Payload array) = let mutable changeLog = ChangeLog.create(5u) for p in payloads do changeLog <- ChangeLog.append(changeLog, p) let result = changeLog.Stream.All(fun change -> change.Type = UpdateType.Update) Assert.True(result) TDD without Mocks
  • 44. We have our own frontend but we need a Data The Next Challenge Oops?!
  • 46. RDBMS All changes from 40 tables ETL Operator Well defined entities compose entities react on changes recalculate odds (data locality)
  • 47. C# F#Asp NET Core Orleans DB Drivers [ DDD; Tests] Infrastructure business logic
  • 48. public Task<FullFeedUpdate> GetSnapshot(GetSnapshot msg) { // invoke F# code from C# var updates = ChangeFeedModule.getSnapshot(FeedState, msg.FastPreloadAmount); return updates; }
  • 49. Applied at the heart of the system Zero Null Reference exceptions Domain errors instead of exceptions DDD with types (strong determinism) Dependency Rejection TDD without mocks (property based testing)
  • 51. - Technology agnostic (no dependency on HTTP, WebSockets, SSE) - Very simple API (to test Pull and Push scenarios) - CI/CD integration
  • 52. - Technology agnostic (no dependency on HTTP, WebSockets, SSE) - Very simple API (to test Pull and Push scenarios) - CI/CD integration
  • 53. - Technology agnostic (no dependency on HTTP, WebSockets, SSE) - Very simple API (to test Pull and Push scenarios) - CI/CD integration
  • 54. - Technology agnostic (no dependency on HTTP, WebSockets, SSE) - Very simple API (to test Pull and Push scenarios) - CI/CD integration
  • 55. type Step = | Request of RequestStep // to model Request-response pattern | Listener of ListenerStep // to model Pub/Sub pattern | Pause of TimeSpan // to model pause in your test flow type TestFlow = { FlowName: string Steps: Step[] ConcurrentCopies: int } type Scenario = { ScenarioName: string TestInit: Step option TestFlows: TestFlow[] Duration: TimeSpan }
  • 56. let execStep (step: Step, req: Request, timer: Stopwatch) = task { timer.Restart() match step with | Request r -> let! resp = r.Execute(req) timer.Stop() let latency = Convert.ToInt64(timer.Elapsed.TotalMilliseconds) return (resp, latency) | Listener l -> let listener = l.Listeners.Get(req.CorrelationId) let! resp = listener.GetResponse() timer.Stop() let latency = Convert.ToInt64(timer.Elapsed.TotalMilliseconds) return (resp, latency) | Pause time -> do! Task.Delay(time) return (Response.Ok(req), 0L) }
  • 57. type TestFlowRunner(flow: TestFlow) = let createActors (flow: TestFlow) = flow.CorrelationIds |> Set.toArray |> Array.map(fun id -> TestFlowActor(id, flow)) let actors = createActors(flow) member x.Run() = actors |> Array.iter(fun x -> x.Run()) member x.Stop() = actors |> Array.iter(fun x -> x.Stop()) member x.GetResult() = actors |> Array.collect(fun actor -> actor.GetResults()) |> TestFlowStats.create(flow)
  • 58. // C# example var flow = new TestFlow(flowName: "READ Users", steps: new[] {step1, step2, step3}, concurrentCopies: 10); new ScenarioBuilder(scenarioName: "Test MongoDb") .AddTestFlow(flow) .Build(duration: TimeSpan.FromSeconds(10)) .RunInConsole();
  • 59. // F# example let flow = { FlowName = "GET flow" Steps = [step1; step2; step3] ConcurrentCopies = 100 } Scenario.create("Test HTTP https://github.com") |> Scenario.addTestFlow(flow) |> Scenario.withDuration(TimeSpan.FromSeconds(10.0)) |> Scenario.runInConsole
  • 60. var httpClient = new HttpClient(); var httpStep = Step.CreateRequest("GET request", execute: async _ => { var response = await httpClient.SendAsync(request); return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail(); }); var pause_1s = Step.CreatePause(duration: TimeSpan.FromSeconds(1)); var scenario = new ScenarioBuilder("Test HTTP") .AddTestFlow("PULL", new[] { httpStep, pause_1s }, concurrentCopies: 10) .Build(duration: TimeSpan.FromSeconds(10)); scenario.RunInConsole();
  • 62. - 1470 LOC - (4) OOP objects - (~100) functions - try/catch used 2 times
  • 63. async { let! x = myFunction() match x with | Some v -> ... | None -> ... } F# vNext match!
  • 64. async { match! myFunction() with | Some v -> ... | None -> ... } F# vNext match!
  • 65. F# vNext Struct Records type Vector3 = { X: float; Y: float; Z: float } [<Struct>] type Vector3 = { X: float; Y: float; Z: float }
  • 66. F# vNext Struct Records [<Struct>] type Result<'T,'TError> = | Ok of 'T | Error of 'Terror [<Struct>] type ValueOption<'T> = | Some of ‘T | None
  • 67. F# vNext Anonymous Records type Data = { X: int Y: string } let data = { X = 1; Y = "abc" }
  • 68. F# vNext Anonymous Records let data = {| X = 1; Y = "abc" |}
  • 69. F# vNext Structural Type System type User() = member this.GetName() = "test user" type Car() = member this.GetName() = "test car" let inline printName (x: ^T when ^T : (member GetName: unit -> string)) = x.GetName() |> Console.WriteLine
  • 70. F# vNext Applicative functors validate { let! name = validateName(name) let! age = validateAge(age) let! email = validateEmail(email) return User(name, age, email) }
  • 71. F# vNext Applicative functors validate { let! name = validateName(name) and! age = validateAge(age) and! email = validateEmail(email) return User(name, age, email) }
  • 72. F# vNext Applicative functors parallel { let! x = slowRequestX() and! y = slowRequestY() and! z = slowRequestZ() return f(x, y, z) }