SlideShare une entreprise Scribd logo
1  sur  54
Télécharger pour lire hors ligne
About me:
@AntyaDev
like types*
genda
• Why F#?
• Adopting F# for C#/OOP
developers (inconveniences, C#
interoperability, code style,
domain modeling, testing)
- 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
});
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 rec SportData.ETL.Core
type ItemRawUpdate<'Item> = {
Id: string
Data: 'Item option
}
module TransformationFlow =
let getUpdates (feed: ChangeFeed, lastOffset: uint32) =
Code Style
public Game CreateGame(MasterEventInfo masterEventInfo)
{
var league = ItemsCacheReference.LeagueInfoCache.GetItem(masterEventInfo.LeagueID);
var region = league != null
? ItemsCacheReference.CountryInfoCache.GetItem(league.Country)
: null;
var branch = ItemsCacheReference.BranchInfoCache.GetItem(masterEventInfo.BranchID);
var isLive = DateTime.UtcNow.AddMinutes(5) > masterEventInfo.GameDate;
return new Game(masterEventInfo.MasterEventID.ToString())
{
LastUpdateDateTime = DateTime.UtcNow,
SportId = masterEventInfo.BranchID.ToString(),
SportName = branch?.Name,
SportOrder = branch?.OrderId ?? 0,
LeagueId = masterEventInfo.LeagueID.ToString(),
LeagueName = league?.Name,
RegionId = region?.RegionID.ToString(),
RegionName = region?.CountryName,
RegionCode = region?.CountryCode,
LeagueOrder = league?.OrderID ?? 0,
IsTopLeague = league?.IsHot ?? false
}
}
let createGame (globalCache: GlobalItemsCache,
masterEvent: MasterEventItem, currentTime: DateTime) = maybe {
let! league = Cache.get(globalCache.Leagues, masterEvent.LeagueID)
let! country = Cache.get(globalCache.Countries, league.CountryID)
let! sport = Cache.get(globalCache.Branches, masterEvent.BranchID)
let! participants = getParticipants(masterEvent, globalCache)
let isTeamSwap = isTeamSwapEnabled(globalCache, masterEvent.LeagueID, masterEvent.BranchID)
let isLive = isEventLive(currentTime, masterEvent.GameDate)
let eventTags = getEventTags(globalCache, masterEvent.ID)
let mainEventId = getMainEventId(masterEvent)
let metadata = getEventMetadata(globalCache, mainEventId, masterEvent.ID)
let liveGameState = if isLive then getLiveGameStateByMasterEvent(globalCache, masterEvent)
else None
return { Id = masterEvent.ID.ToString()
Type = getEventType(masterEvent) }
}
Maybe Monad
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)
let result = [ChaosMonkey
LatencyMonkey
CpuMonkey
MemoryMonkey]
|> induceDamage
NDamage
feature "Github Activity" [
step "list repository events"
(GET "/repos/WeKnowSports/SportsDataAPI/events") // action
(checkStatus HttpStatusCode.OK) // validator
step "list issue events for a repository"
(GET "/repos/WeKnowSports/SportsDataAPI/issues/events")
(checkStatus HttpStatusCode.OK)
pause "00:00:05"
]
let platform = Docker(host = "http://localhost:2375")
let chaosMonkey = {
Name = "DockerChaosMonkey"
Frequency = "00:00:05"
Probability = 1.0 // 100% that alive node will be terminated
TargetGroups = ["api"; "mongo"; "rabbit"]
Platform = platform
}
let httpBase = http
|> baseURL("https://api.github.com")
|> header("User-Agent", "NDamage")
|> header("Accept", "application/json")
|> header("Accept-Encoding", "gzip")
[
feature "Github Reactions" [
step "list reactions for an issue"
NDamage
http://ndamage.com
@n_damage
Supported Platforms: [Docker; Google Cloud; Amazon; Azure]
Test your resilience!
CI Pipeline: [Jenkins; Team City]
Alerting: [Email; Slack]
Adopting F# at SBTech

Contenu connexe

Tendances

Dictionary e book
Dictionary e bookDictionary e book
Dictionary e booksharmilakt
 
Swift Basics with iOS 8 features
Swift Basics with iOS 8 featuresSwift Basics with iOS 8 features
Swift Basics with iOS 8 featuresVivekChaudharyDev
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koinJintin Lin
 
Test and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppTest and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppMichele Capra
 
Policy Injection in ASP.NET using Enterprise Library 3.0
Policy Injection in ASP.NET using Enterprise Library 3.0Policy Injection in ASP.NET using Enterprise Library 3.0
Policy Injection in ASP.NET using Enterprise Library 3.0PhilWinstanley
 
ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON Padma shree. T
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networkingVitali Pekelis
 
Realm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseRealm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseSergi Martínez
 
Easy REST APIs with Jersey and RestyGWT
Easy REST APIs with Jersey and RestyGWTEasy REST APIs with Jersey and RestyGWT
Easy REST APIs with Jersey and RestyGWTDavid Chandler
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web developmentJohannes Brodwall
 
Christopher Latham Portfolio
Christopher Latham PortfolioChristopher Latham Portfolio
Christopher Latham Portfoliolathamcl
 
How lagom helps to build real world microservice systems
How lagom helps to build real world microservice systemsHow lagom helps to build real world microservice systems
How lagom helps to build real world microservice systemsMarkus Eisele
 
Appengine Java Night #2a
Appengine Java Night #2aAppengine Java Night #2a
Appengine Java Night #2aShinichi Ogawa
 

Tendances (19)

Dictionary e book
Dictionary e bookDictionary e book
Dictionary e book
 
Swift Basics with iOS 8 features
Swift Basics with iOS 8 featuresSwift Basics with iOS 8 features
Swift Basics with iOS 8 features
 
Dagger 2 vs koin
Dagger 2 vs koinDagger 2 vs koin
Dagger 2 vs koin
 
Test and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 AppTest and profile your Windows Phone 8 App
Test and profile your Windows Phone 8 App
 
Policy Injection in ASP.NET using Enterprise Library 3.0
Policy Injection in ASP.NET using Enterprise Library 3.0Policy Injection in ASP.NET using Enterprise Library 3.0
Policy Injection in ASP.NET using Enterprise Library 3.0
 
Android development
Android developmentAndroid development
Android development
 
Data binding
Data bindingData binding
Data binding
 
Introduction toandroid
Introduction toandroidIntroduction toandroid
Introduction toandroid
 
Android data binding
Android data bindingAndroid data binding
Android data binding
 
ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON
 
Introduction to android
Introduction to androidIntroduction to android
Introduction to android
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
Realm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app databaseRealm or: How I learned to stop worrying and love my app database
Realm or: How I learned to stop worrying and love my app database
 
Practical
PracticalPractical
Practical
 
Easy REST APIs with Jersey and RestyGWT
Easy REST APIs with Jersey and RestyGWTEasy REST APIs with Jersey and RestyGWT
Easy REST APIs with Jersey and RestyGWT
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
Christopher Latham Portfolio
Christopher Latham PortfolioChristopher Latham Portfolio
Christopher Latham Portfolio
 
How lagom helps to build real world microservice systems
How lagom helps to build real world microservice systemsHow lagom helps to build real world microservice systems
How lagom helps to build real world microservice systems
 
Appengine Java Night #2a
Appengine Java Night #2aAppengine Java Night #2a
Appengine Java Night #2a
 

Similaire à Adopting F# at SBTech

.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech
.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech
.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTechNETFest
 
Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017Matt Raible
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
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 YouC4Media
 
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Jung Kim
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTMichael Galpin
 
Bootiful Development with Spring Boot and React - SpringOne 2017
Bootiful Development with Spring Boot and React - SpringOne 2017Bootiful Development with Spring Boot and React - SpringOne 2017
Bootiful Development with Spring Boot and React - SpringOne 2017Matt Raible
 
Adopting Swift Generics
Adopting Swift GenericsAdopting Swift Generics
Adopting Swift GenericsMax Sokolov
 
Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018Matt Raible
 
.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#Bertrand Le Roy
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Hw09 Analytics And Reporting
Hw09   Analytics And ReportingHw09   Analytics And Reporting
Hw09 Analytics And ReportingCloudera, Inc.
 
Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018Matt Raible
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentanistar sung
 
Cleaning your architecture with android architecture components
Cleaning your architecture with android architecture componentsCleaning your architecture with android architecture components
Cleaning your architecture with android architecture componentsDebora Gomez Bertoli
 

Similaire à Adopting F# at SBTech (20)

.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech
.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech
.NET Fest 2018. Антон Молдован. One year of using F# in production at SBTech
 
Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017Bootiful Development with Spring Boot and React - RWX 2017
Bootiful Development with Spring Boot and React - RWX 2017
 
mobl
moblmobl
mobl
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
Api
ApiApi
Api
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
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
 
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
Letswift18 워크숍#1 스위프트 클린코드와 코드리뷰
 
Python, WebRTC and You (v2)
Python, WebRTC and You (v2)Python, WebRTC and You (v2)
Python, WebRTC and You (v2)
 
XAML/C# to HTML/JS
XAML/C# to HTML/JSXAML/C# to HTML/JS
XAML/C# to HTML/JS
 
RIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWTRIAs Done Right: Grails, Flex, and EXT GWT
RIAs Done Right: Grails, Flex, and EXT GWT
 
Bootiful Development with Spring Boot and React - SpringOne 2017
Bootiful Development with Spring Boot and React - SpringOne 2017Bootiful Development with Spring Boot and React - SpringOne 2017
Bootiful Development with Spring Boot and React - SpringOne 2017
 
Adopting Swift Generics
Adopting Swift GenericsAdopting Swift Generics
Adopting Swift Generics
 
Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018Bootiful Development with Spring Boot and React - Belfast JUG 2018
Bootiful Development with Spring Boot and React - Belfast JUG 2018
 
.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#.NET Foundation, Future of .NET and C#
.NET Foundation, Future of .NET and C#
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Hw09 Analytics And Reporting
Hw09   Analytics And ReportingHw09   Analytics And Reporting
Hw09 Analytics And Reporting
 
Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018Bootiful Development with Spring Boot and React - UberConf 2018
Bootiful Development with Spring Boot and React - UberConf 2018
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app development
 
Cleaning your architecture with android architecture components
Cleaning your architecture with android architecture componentsCleaning your architecture with android architecture components
Cleaning your architecture with android architecture components
 

Dernier

Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 

Dernier (20)

Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 

Adopting F# at SBTech

  • 1.
  • 3. genda • Why F#? • Adopting F# for C#/OOP developers (inconveniences, C# interoperability, code style, domain modeling, testing)
  • 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 });
  • 15. 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
  • 16.
  • 18. Triggers: Much better tooling support Community growth Recursive modules
  • 20.
  • 21.
  • 22. 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) = ...
  • 23. Recursive modules module M type First = | T of Second and Second = | T of First
  • 24. Recursive modules module M type First = | T of Second type Second = | T of First
  • 25. Recursive modules module rec M type First = | T of Second type Second = | T of First
  • 26. Recursive modules module M let private helper () = ... let publicApiFunc () = helper()
  • 27. Recursive modules module rec M let publicApiFunc () = helper() let private helper () = ...
  • 28. 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.
  • 29.
  • 30. namespace rec SportData.ETL.Core type ItemRawUpdate<'Item> = { Id: string Data: 'Item option } module TransformationFlow = let getUpdates (feed: ChangeFeed, lastOffset: uint32) = Code Style
  • 31. public Game CreateGame(MasterEventInfo masterEventInfo) { var league = ItemsCacheReference.LeagueInfoCache.GetItem(masterEventInfo.LeagueID); var region = league != null ? ItemsCacheReference.CountryInfoCache.GetItem(league.Country) : null; var branch = ItemsCacheReference.BranchInfoCache.GetItem(masterEventInfo.BranchID); var isLive = DateTime.UtcNow.AddMinutes(5) > masterEventInfo.GameDate; return new Game(masterEventInfo.MasterEventID.ToString()) { LastUpdateDateTime = DateTime.UtcNow, SportId = masterEventInfo.BranchID.ToString(), SportName = branch?.Name, SportOrder = branch?.OrderId ?? 0, LeagueId = masterEventInfo.LeagueID.ToString(), LeagueName = league?.Name, RegionId = region?.RegionID.ToString(), RegionName = region?.CountryName, RegionCode = region?.CountryCode, LeagueOrder = league?.OrderID ?? 0, IsTopLeague = league?.IsHot ?? false } }
  • 32. let createGame (globalCache: GlobalItemsCache, masterEvent: MasterEventItem, currentTime: DateTime) = maybe { let! league = Cache.get(globalCache.Leagues, masterEvent.LeagueID) let! country = Cache.get(globalCache.Countries, league.CountryID) let! sport = Cache.get(globalCache.Branches, masterEvent.BranchID) let! participants = getParticipants(masterEvent, globalCache) let isTeamSwap = isTeamSwapEnabled(globalCache, masterEvent.LeagueID, masterEvent.BranchID) let isLive = isEventLive(currentTime, masterEvent.GameDate) let eventTags = getEventTags(globalCache, masterEvent.ID) let mainEventId = getMainEventId(masterEvent) let metadata = getEventMetadata(globalCache, mainEventId, masterEvent.ID) let liveGameState = if isLive then getLiveGameStateByMasterEvent(globalCache, masterEvent) else None return { Id = masterEvent.ID.ToString() Type = getEventType(masterEvent) } } Maybe Monad
  • 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)
  • 50. let result = [ChaosMonkey LatencyMonkey CpuMonkey MemoryMonkey] |> induceDamage
  • 51. NDamage feature "Github Activity" [ step "list repository events" (GET "/repos/WeKnowSports/SportsDataAPI/events") // action (checkStatus HttpStatusCode.OK) // validator step "list issue events for a repository" (GET "/repos/WeKnowSports/SportsDataAPI/issues/events") (checkStatus HttpStatusCode.OK) pause "00:00:05" ]
  • 52. let platform = Docker(host = "http://localhost:2375") let chaosMonkey = { Name = "DockerChaosMonkey" Frequency = "00:00:05" Probability = 1.0 // 100% that alive node will be terminated TargetGroups = ["api"; "mongo"; "rabbit"] Platform = platform } let httpBase = http |> baseURL("https://api.github.com") |> header("User-Agent", "NDamage") |> header("Accept", "application/json") |> header("Accept-Encoding", "gzip") [ feature "Github Reactions" [ step "list reactions for an issue"
  • 53. NDamage http://ndamage.com @n_damage Supported Platforms: [Docker; Google Cloud; Amazon; Azure] Test your resilience! CI Pipeline: [Jenkins; Team City] Alerting: [Email; Slack]