Techorama 2022 in Kinepolis - Utrecht - dag 1: 11 oktober 2022

Ingediend door Dirk Hornstra op 19-oct-2022 22:17

Waarschuwing: dit wordt een heel lang verhaal. Ik heb namelijk alle sessies die ik op 11 oktober bezocht heb samengevat. Dat zijn 6 stuks, de sessies duurden meestal een uur.

11 oktober, 10:00 - 11:00, room 2, John Craddock, Lifting the covers on Azure AD Authentication and Conditional Access

De eerste sessie van vandaag. John is iemand die “al wat langer mee gaat”. Hij heeft real-time control-systemen voor zowel hardware als software gemaakt. Hij heeft met elke versie van Microsoft Windows gewerkt. En in 1999 werd hij gebeld door Microsoft met de vraag: “jij doet veel met Active Directory, zou je ons daar wat over willen vertellen?”. Vanaf dat jaar is hij diep betrokken bij Microsoft en nu ook een Microsoft MVP. Vanaf 2002 is John begonnen om zich te specialiseren in “Federated Identity”.

Tijdens deze sessie gaat hij de volgende punten bespreken:

  • Zorgen dat wij gaan begrijpen wat de componenten van “Conditional Access” zijn en waarom het de bron van de Zero Trust architectuur is.
  • Ons leren wanneer en hoe Conditional Access geactiveerd wordt.
  • En ons een paar exotische aspecten van Conditional Access bijbrengen.

 

We krijgen een schema te zien van hoe gebruikers/workloads bepaalde devices willen benaderen.
Gebruikers/workloads heeft een aantal onderdelen:

  • Groups/role (waar maakt deze user of workload onderdeel van uit?)
  • Location (user logt altijd in vanuit Amsterdam, maar nu ineens New York?)
  • Application (user gebruikt altijd applicatie X, maar nu probeer applicatie Z toegang te krijgen?)
  • Sign-in Risk
  • User Risk

De devices zijn onderverdeeld naar deze aspecten:

  • Zijn ze “managed/beheerd” of zijn het eigen devices (BYOD)
  • Health/compliance
  • Device Risk
  • Type and OS version
  • Encryption Status


Deze zaken komen samen in de Conditional access policy engine. Daar zit nog een stuk Identity protection threat intelligence bij.

Microsoft Azure AD authenticeert toegang tot apps.
Microsoft Defender producten worden gebruikt om de beslissingen te bepalen en om toegang tot apps te controleren.
Microsoft Intune is er voor device compliance en mobile app management.

Er wordt gekeken wat er gedaan moet worden, block, increase assurance, remediate (bij afwijkingen). Vervolgens ga je naar de session controls.

En daarna ga je door naar de cloud SaaS apps en on-premise en web-apps met volledige of beperkte toegang.

Wanneer wordt conditional access geëvalueerd?
Elke keer als er een authenticatie-verzoek uitgevoerd wordt voor een SAML-token, Id_token of Access_token.
CA wordt ook geëvalueerd op het moment dat je “bewijst” wie je bent met een cookie (session tokens) en refresh tokens.

Hierna krijgen we de OpenID Connect en OAuth 2.0 flow te zien, we zien hierbij 2 apps. Een user wordt geauthenticeerd via Azure Active Directory voor app1. Hij krijgt daar een Id_token voor terug. Het access_token wat Azure AD geeft is om aan te geven dat app1 gebruik mag maken van app2.

Azure AD kan ook een refresh_token uitgeven. Hier nog een paar zaken voor access_token en refresh_token:

  • Een access_token kan nooit toegang geweigerd worden. De levensduur is daarom altijd kort.
  • Met een refresh_token kan een nieuw id_token en access_token aangevraagd worden. Refresh_tokens kunnen wel geweigerd worden, waardoor je dus geen nieuw access_token/id_token meer krijgt.


Hierna gaan we door naar CAE, continuous access evaluation.
We zien een schema. Tussen Azure AD en Microsoft API staan pijltjes (beide kanten op) voor het abonneren op events en policies.

Vervolgens wil de applicatie data van de API en stuurt een verzoek met een access_token.
Dit wordt gevalideerd met een policy check. Als er “iets” is (event-notificatie, policy) kan de toegang geweigerd worden en een claims challenge geretourneerd worden. Op dat punt MOET de cliënt CAE-aware zijn (John gaf het voorbeeld van Outlook die dat niet was, dus deze begon weer het access_token te sturen, kreeg weer de claim-challenge terug en bleef daardoor in een loop hangen).

Microsoft CAE is gericht op Exchange, Teams en Sharepoint online.

De huidige “kritische events” zijn:

  • User account is verwijderd/uitgeschakeld
  • Wachtwoord is veranderd/reset
  • MFA is actief voor de user
  • Refresh tokens zijn geweigerd
  • Azure AD Identity Protection detecteert een verhoogd “user risk”

 

De huidige “kritische policies” zijn:

  • Wijziging van de netwerklocatie


Met CAE sessies kan de levensduur van een access_token langer worden (tot wel 28 uur). We zien in het voorbeeld hoe dit bij Outlook verschilt (na een uur al ververst, met CAE na een dag en een uur en een kwartier). John legt ook uit dat “de start van een access-token” 5 minuten in het verleden is, omdat anders mogelijk een uitgegeven access-token nog niet actief zou zijn. En er zit een soort random verloop in, zodat niet exact na een uur de tokens vernieuwd worden, maar met een bepaalde marge.

John toont ons hoe policies ingericht kunnen worden, phishing resistant (onder andere door een FIDO device te gebruiken), password less door de Authenticator te gebruiken.
Als je bijvoorbeeld een user-risk hebt kan de vraag komen om je wachtwoord te wijzigen. MFA is hierbij noodzakelijk.
Ook nog een goed punt was de resilience settings. John had het erover dat de Azure Active Directory er wel eens uitgelegen heeft. Als de primary authentication service eruit ligt, kun je instellen dat de backup authentication service nog steeds tokens kan uitgeven aan bestaande sessies.

CA kan daardoor niet real-time data evalueren;

  • Sign-in risk
  • User risk
  • Group Membership
  • Role Membership
  • Country location


Bij CA Policies is resilience automatisch actief. Als je niet wilt dat er tokens uitgegeven kunnen worden als je geen real-time-data hebt, zet die optie dan expliciet uit (en dat kun je ook alleen voor de key-users doen, zodat de “normale users” wel door kunnen werken).

Je kunt session controls ook verbeteren;

Gebruik app enforced restrictions: device compliance status wordt gedeeld met Sharepoint en Exchange. Restricted access op basis van application controls.

Gebruik conditional access app control: toegang tot apps via de reverse proxy van Defender for Cloud, beperkte toegang via MDCA policies.

Sign-in-frequency: dit is voor OpenID Connect/OAuth 2.0 apps.
Persistent browsersessie: persistent vs niet-persistent session tokens (cookies).
CA is/wordt een key component van Zero Trust en er wordt nog actief aan ontwikkeld. Zo zie je soms in een screenshot voor een bepaald punt dat er een optie (checkbox) bij gekomen is die nu nog niet live staat (in het voorbeeld van John een vinkje voor “require token binding for sign-in sessions”.

We zien hoe John in Azure zijn Conditional Access Policies opgezet heeft. Een hele lijst. John houdt er structuur in met de naamgeving: [SERIENUMMER}: omschrijving (bijvoorbeeld SN015: SharePoint MFA for John when Always).
Ook zien we hoe een download geblokkeerd kan worden.
We krijgen nog een stuk JSON voor de authentication context, we zien de claims zoals:
Claims = {“access_token”:{“acrs”:{“essential”:true,”value”:”c1”}}}

Deze authentication context kan ingesteld worden door een applicatie.
Dit wordt ondersteund in Sharepoint.
Een app kan een authenticatie-request sturen en deze context mee sturen in de request string.
In het voorbeeld is c1 voor de CA policy die afgedwongen moet worden.
Je kunt tot 25 authentication contexts aanmaken in het portal.
Elke context krijgt een display naam en een id (van c1 tot c25).

Advies van John om te starten:

Begin simpel en voeg dit als laag toe op je bestaande policies.

Authenticatie:
MFA voor admins, MFA voor users, block legacy authentication.

Devices:
Vereis: compliant devices, Azure AD joined, approved apps voor mobiele toegang
Blok unsupported devices

Stricter controls:
evalueer sign-in en user-risk
controleer de sign-in frequentie
schakel persistent cookies uit
verplicht terms of use
blokkeer MFA registraties van niet vertrouwde locaties (Iran, Rusland)
Integreer met Microsoft Defender voor Cloud Security
En zorgt dat je ook de andere signalen van andere Microsoft Defender producten binnen krijgt

Azure bestaat nog uit veel meer, John geeft binnenkort een masterclass: link.

Daar komen zaken in naar voren als

  • Azure AD Authentication
  • Securing access to applications
  • Registering apps in Azure AD
  • Application protocols (OpenID Connect and OAuth 2.0)
  • The Azure AD Application Proxy
  • Meer…


Paar extra zaken die zijn blijven hangen:
John zegt dat de “authenticator not phishing resistant is” !
Bij je policies moet je altijd je “breaking glass accounts” uitsluiten. Die term is nieuw voor mij, John is volgens mij een beetje verontrust dat dit bij meer mensen het geval is en hij raadt ons aan: zoek het op en doe er wat mee. Logisch gezien lijken mij dit bepaalde admin-accounts (met volgens John lange, moeilijke wachtwoorden) die über-rechten hebben.
En ik heb hier nog staan “melding access is monitored”, “proxy in de cloud” en “downloads blokkeren”, deze hebben volgens mij allemaal een relatie met CAE.


11 oktober, 11:30 - 12:30, room 8, Loek Duys, Five things every developer should know about modern identity platforms

Loek Duys is van Xpirit. Zijn verhaal gaat over identity platforms, ontstaan uit de vraag van de klant “kun je zorgen dat de site via single-sign-on werkt?”. Want ja, niemand wil 20x inloggen, 1x inloggen en klaar. Maar hoe realistisch is dat?
Loek toont eerst de blokken van moderne Identity Platformen (IDP). Er is een directory die beschikbaar is voor “security principals”. Users, groups, system-accounts. Je kunt daar profieldata opslaan (gebruikersnaam, geboortedatum). En je kunt samenwerken met andere IDP’s.
Een IDP biedt diensten voor applicaties, het dwingt identity en rollen af (authenticatie en autorisatie). Je kunt inlogcredentials omruilen voor een accesstokens of identity-data (tokens, cookies). Tevens gebruikt het standaard protocollen en endpoints.
En het laatste blok is operaties. Ondersteuning van automatische processen. Self-service capabilities (handig als je zelf je wachtwoord kunt wijzigen of “wachtwoord-vergeten-actie” kunt uitvoeren). En het is audible: wie heeft wat wanneer gedaan?
Waarom zou je gebruik maken van gecentraliseerde IDP’s?
Centralized: separate user accounts from systems
Je hoeft in je apps maar 1 IDP te vertrouwen (lagere complexiteit)
Hiermee kun je accounts en SSO hergebruiken
Minder platformen die je moet “verdedigen” en de “audits” van hoeft te beoordelen

Hosted: IDP as a Service
Single point of failure, moet dus zeer robuust zijn
Pay for use, betrouwbare leverancier en als je het zelf zou moeten bouwen zou dat niet haalbaar zijn
En daarmee kun jij je dus gewoon focussen op je “core business”

Separate customers from employees
Voorkom autorisatie / licentie vergissingen
Medewerkers loggen “anders in” dan klanten

Customization
Klanten verwachten een consistente “experience”
Werknemers moeten mogelijk extra checks uitvoeren (op basis van locatie wel of geen toegang)

Vervolgens komt Loek met Azure Active Directory B2C.
Globaal beschikbaar: gebouwd en onderhoud door Microsoft, 99.99 SLA, meerdere authenticatie-services: OIDC, OAUTH, SAML.
Aanpasbaar: eigen policies, styling, user attributen, federation, REST services, MFA, Conditional Access Policies. En je kunt er een eigen domein aan koppelen!
Acties: facturen via Azure subscription, je betaalt alleen voor de actieve gebruikers. Beheer de zaken via de portal of Graph API. En monitor de acties met Log Analytics en App Insights.
Hierna toont Loek ons de demo van een simpele verzekeringsmaatschappij.
Er is een Sales (front-end), hier kun je je aanmelden, inloggen als klant en verzekeringen kopen. Blazor WASM – single page web-applicatie. Daarnaast heb je nog een front-end voor Damage-claims. Je logt hier in als klant om schade te melden (of vermissing). Blazor WASM – single page web applicatie. En als laatste de Insurance API (back-end). Algemene service om data op te slaan en gerelateerde data te beheren. ASP.NET MVC Web API.

Advies om te starten met je eigen inrichting van de IDP:
Maak een productie en een non-productie tenant. Je kunt dan flows testen in de non-prod tenant.
Bouw flows. User Flows voor standaard zaken als aanmelden, inloggen, wachtwoord resetten. En voeg custom policies toe voor custom processen.
Application registration: elk executable deel heeft App Registration counterpart en identy. De access permissions zijn vooraf gedefinieerd.

Je hebt verschillene soorten app registraties.
Public client is voor apps die uitgevoerd worden op hardware waar jij geen invloed op hebt, die zichzelf niet veilig kunnen identificeren. Voorbeelden daarvan zijn een Single Page Application (SPA), web site, mobiele app, native apps.
De confidential client is voor apps die op hardware uitgevoerd wordt waar je wel invloed op hebt. Met Client ID en secret kan deze zich identificeren. Voorbeeld is een reguliere website.
En nog special clients required to operate B2C. Dit zijn er twee om toegang te krijgen tot Graph. 1 is voor de custom user attributes. En de andere is om de tenant te beheren.
Dan volgt nog het combineren van Indentity Platformen. Bij Customer Accounts heb je een App account in Azure AD B2C (lokaal), een sociaal account (Facebook), een overheidsaccount (DigiD).
Bij employee en partner-accounts heb je een corporate account van Azure AD, partner account via B2B Guest invites.

Dan de vraag, wat is Identity Federation?
Dat is vertrouwen tussen meerdere IDP’s.
Jouw IDP vertrouwt een andere IDP.
Klanten loggen met de andere IDP in om in te loggen in jouw app.

Delegation of trust: geen locatie credentials nodig, de “remote IDP” stelt zich verantwoordelijk voor de user identity.

We krijgen een demo en daarna volgt nog even de uitleg hoe een app iets “weet” over een user. Dat komt omdat die via een /authorize en /token endpoints doorgestuurd wordt. De IDP daagt de user uit (of delegeert dit). Via de tokens krijgt de app informatie over de user.

Access token en Refresh token spreekt voor zich (ook al genoemd in de sessie van John Craddock), je hebt ook nog de Identity Token (OIDC). Dat is de identificatie van 1 enkele menselijke gebruiker. Bevat claims (info) over de gebruiker. Korte geldigheidsduur (5 minuten, 24 uur, standaard 1 uur) en is te bekijken.
We zien nog een paar flows, de Client Credentials Grant Flow, system to system, geen users. De client stuurt naar de IDP de credentials, deze stuurt een access_token terug en de cient kan de call naar de web API uitvoeren.

Bij de “on behalf of” flow ga je eerst naar API 1, deze vraagt  bij de IDP een nieuw token aan en gebruikt dat om API 2 aan te roepen.

En dan nog de “authorization code grant flow”, dit zijn server-side web-apps met een client-secret of single page apps zonder client secrets. Via knop login naar de IDP, deze stuurt een challenge terug, de gebruiker voer zijn/haar credentials in, de IDP logt in en stuurt een autorisatie code terug. De client stuurt die code en code_verifier naar de IDP die er tokens voor terug geeft. De client slaat die data op en gaat dan de aanvraag naar de web API uitvoeren.

Loek toont wat er gebeurt, de sales front-end logt in op een interactieve manier, hiermee krijg je een cookie en tokens. De schade-front-end logt “stil” in met het cookie. Deze krijgt een bijgewerkte cookie en tokens. De AAD B2C zorgt dat de cookie geldig is en verzend de tokens en bijgewerkte cookies.
Omdat teams los van elkaar moeten kunnen werken, moeten ze autonome delen kunnen beheren. Zoals het in- en uitloggen. Styling voor het sluiten van een verzekering is anders dan die van het indienen van schade. En je zulke specifieke policies hebben (bijvoorbeeld linken van accounts).
Ook het aanpassen van App Registraties valt hieronder. Ondersteun specifieke flows voor de applicatie, voeg nieuwe apps toe.
Maak dus 2 tenants aan (1 productie, 1 niet-productie).
Dat is één keer een handmatig proces.
Maak management SPN voor Powershell of Graph API.
En voer bij de rest “Infrastructure as code” door voor de rest.
Gebruik pipelines om tenant management te beheren.
Voeg (speciale) app registraties toe.
Configureer deze per team.

En een samenvatting:
1.    Gebruik centrale IDP’s.
2.    Gebruik Federation.
3.    Weet dat er tokens zijn (en hoe je ze gebruikt).
4.    Weet welke flow je wanneer gebruiken moet.
5.    Gebruik DevOps principles om je omgevingen in te richten. Geen handwerk: alles via code.
En mocht je zelf die demo willen doorbladeren, via de Github te downloaden: github.com/loekd/insurance-demo

Nog een paar zaken die in deze sessie voorbij kwamen; Azure is de hoofdmoot maar ook Okta werd genoemd en Auth0 (en ik zie dat dat van Okta is).


11 oktober, 13:45 - 14:45, room 11, Mark Heath, HyperLINQ -  take your LINQ skills to the next level

Bij Creative Industries (voormalig werkgever) had volgens mij onze collega Peter Kiers geregeld dat we naar Info Support zouden gaan. Samen met Klaas-Jan heen geweest en toen werd getoond wat LINQ was. Dat was nieuw. En het was supertof!
Op dit moment gebruikt elke developer wel LINQ. Mark had het erover dat het vanaf 2008 of zoiets in C# zit. Dus er zijn mensen die niet beter weten dan dat het beschikbaar is.

Goed, deze sessie. Mark Heath maakt ook trainingen voor Pluralsight. En deze week is de “free week”. Dat zou ik nog even delen, maar nu ik dit typ is het zondagavond, dus die week is al voorbij. Gelukkig zitten we bij TRES ook op Pluralsight – zoeken naar Mark Heath dus! Hij laat zien dat LINQ begon toen Windows Vista uitgebracht werd, in C# 3.0.
Om developers uit te dagen heeft Mark ook regelmatig lunch-time-challenges: markheath.net/category/linq-challenge
Je noteert dit, maar nu ik naar die link ga zie ik dat 2018 voor het laatst een artikel geplaatst is. Dat is niet heel actief Mark :D We gaan voor de tips!

Tip 1 is om Linqpad te gebruiken – www.linqpad.net
In de applicatie van linqpad.net kun je stukjes LINQ in plakken, ook connecties met databases werken, je kunt scripts opslaan en weer openen. Ik had dat al eens eerder bekeken, het is een betaald product (want dan heb je de echte mogelijkheden om er wat mee te doen). Toch nog eens zelf maken dan maar?

Tip 2, let op patronen.
Dat is inderdaad wel een goede. Mark laat een lijst zien, daar ga je met een for-loopje doorheen en als een item een e-mailadres heeft, dan voeg je deze toe in een andere lijst, 8 regels code. Maar dat kan heel simpel met een .Where(…).ToList(). Mark heeft het op 2 regels gezet, maar kan dus bijna in 1.
Mark laat nog een ander loopje zien. Als de naam met een T begint dan stuur je die als resultaat terug (dus je breekt uit de loop). Dat kan ook supersimpel met een .FirstOrDefault(rec => rec.StartsWith(“T”)).
Je gaat van de “imperatieve flow” naar de “declaratieve flow” (van hoe naar wat).

Tip 3 is om pijplijnen te gebruiken.
We zien een stukje code als:
var result = DoLast(DoThird(DoSecond(DoFirst(data))));
Totaal onduidelijk wat er gebeurt en je werkt “van rechts naar links”, wat voor “ons” eigenlijk niet logisch is. Mark laat zien hoe het in F# werkt (daar zeg ik al 5 jaar van: daar wil ik nog wat mee doen!), maar hij laat dus ook zien hoe het bij ons kan:
var result = data.DoFirst().DoSecond().DoThird().ToLast();
Tussen de tips door komt ook de “LINQ STINQ” voorbij.

Linq Stinq 1: complexe pijplijnen.
We zien een stuk code waarin regels uit data.txt uitgelezen worden, skip(1) (dus eerste regels met titels overgeslagen) en dan een select, waarbij de regel wordt gesplit op tabs, waarbij de lengte groter dan 1 is en de eerste waarde “getrimt” groter dan 0 is. Eerste karakter wordt dan gesplitst op puntkomma en er worden zaken geselecteerd. Het zal hier vast om een CSV of iets dergelijks gaan, maar echt leesbaar is het niet.
Je kunt die zaken “daar binnen” als functies schrijven. Dus we zien later een
customers.Where(IsElegibleForDiscount).Select(GetDiscountPercentage).
Je kunt daar in die functies de selecties doen en daar de moeilijke acties op het selecteren van data. Dit houdt deze functie overzichtelijk/leesbaar.

Tip 4 is om LINQ te extenden / uit te breiden.
Mark toont ons het voorbeeld voor bijvoorbeeld schaatsers. Je krijgt alle rondetijden in een lijst terug. Dat is: 00:01:10, 00:02:05, 00:03:15. Dat zijn de tijden van de stopwatch, maar je wilt de echte tijd “per ronde”. Dus dat is “per paar”.
We zien een ingewikkelde .SelectMany(..).Skip(1).Select(..).GroupBy(.).Select(..).Where(..).Select(..)
Dit kan omgezet worden naar 1 tot 2 regels: bron.PairWise((a,b) => b-a)
Die functie PairWise is een static functie in een static class die door de lijst bladert en met een “yield” op het juiste moment een bepaalde waarde terug geeft aan de aanroepende functie. Maar dat ziet er een stuk logischer uit dan die hele LINQ-query’s.

Tip 5 is om MoreLINQ te gebruiken.
Te vinden op morelinq.github.io
Want hoewel je veel dingen kunt met LINQ, er zijn zaken die missen. En die komen er op een bepaald moment wel bij, maar als je het “nu!” nodig hebt, dan is het handig dat dit project je de oplossing levert.

Tip 6 is het snappen van deferred execution.
Als je een LINQ query maakt dan wordt de LINQ-actie nog niet uitgevoerd. Pas als je .ToList() e.d. doet, dan wel.
We zien een voorbeeld waarbij een functie aangeroepen wordt. Waarin ook een Sleep zit. En het throwen van een exceptie. Vraag is of dat ooit gebeurt. Het antwoord is nee, door de eerste yield return “Hello”;  vlieg je al uit de functie en wordt de rest niet uitgevoerd.

Linq Stinq 2: teveel lezen.
Hier zien we het al, er word data uit een Blob-store opgevraagd, maar ook meteen een .ToList() gedaan. Alle 650.000 blobs van 1 GB per stuk worden binnengehaald. Succes!

Linq Stinq 3: teveel enumeraties.
We zien weer een GetBlobs, gevolgd door een .MaxBy(..) en een .MinBy(…). Hierdoor wordt 2x de volledige set doorlopen.
Hier is het dan wel handig om de .ToList() uit te voeren.
We zien het voorbeeld van een platenverzameling. Naast het feit dat alle velden opgevraagd worden (terwijl alleen Titel en naam artiest relevant is), wordt ook de artiest elke keer los opgevraagd. Dus als je 20 albums hebt, wordt ook nog 20 keer los de artiest opgevraagd.

Linq Stinq 4: side-effects, neveneffecten.
We zien het voorbeeld van het inlezen van .cs-bestanden in een map. Maar daar kan iemand een bestand toevoegen of verwijderen, dus de input kan veranderen.

Tip 6.5 is de IAsyncEnumerable<T>.
Eindelijk kunnen we await / async gebruiken!

Tip 7 is het kennen van beide syntaxes.
We zien het voorbeeld van een schaakbord, waarbij de loper diagonaal over het bord mag bewegen.
In de Enumerable.Range(‘a’, 8).SelectMany(…).Select(..).Where(..).Select(..)
daar raak je gauw het overzicht kwijt (wat gebeurt hier in godsnaam?).
Met de:
from row in Enumerable.Range(‘a’, 8)
from col in Enumerable.Range(‘1’, 8)
let dx = Math.Abs(row – ‘c’)
let dy = Math.Abs(col – ‘6’)
enzovoort
Dat maakt het een stuk leesbaarder. Dus je kunt ook deze syntax van LINQ in sommige gevallen gebruiken om zaken overzichtelijk te houden.

Tip 8 is performance matters.
Mark toont een loopje en hoe dat best snel gaat. Er zijn developers die geen LINQ gebruiken omdat ze denken/vinden dat het trager is. Misschien was dat in het begin zo, maar dat zal nu weinig meer uitmaken. Er was zelfs een case waarbij LINQ juist sneller was.
En nog even voor als het straks december is: adventofcode.com

11 oktober, 13:45 - 14:45, room 12, Rob Richardson, Minimal API's with ASP.NET 6.0

Deze sessie van Rob Richardson liep een beetje uit, dus omdat ik al naar de zaal liep voor de sessie van Sander kon ik nog net een stukje meepakken van deze demo. Met "minimal API's" kun je supersnel een stuk API opzetten in C#. Vraag is even hoe robuust dat in een productie-omgeving is, maar goed, dat zal wel eerder in deze demo besproken zijn. Rob heeft zijn zaken goed voor elkaar! Hij heeft een aantal presentaties gegeven bij Techorama (welke ik allemaal niet gezien heb), maar hij heeft een nette "presentations-pagina" op zijn site waar je zaken terug kunt vinden: link. En hier de code op Github: link. Dus als je meer over minimal API's wilt weten, daar even doorheen klikken!

11 oktober, 15:00 - 16:00, room 12, Sander Hoogendoorn, The Zen of Programming. A personal journey towards writing beautiful code

Sander Hoogendoorn heb ik vaker zien/horen spreken en dat is altijd reden voor een thumbs-up. Voor de start van zijn sessie nog even een handje gegeven, daarna gaat de man los;
Sander houdt van reizen en van programmeren. Hij heeft de definitie van reizen erbij gepakt en die een beetje aangepast zodat die ook geschikt is voor “coding”. Want “like to learn new languages”, dat kan meerdere interpretaties hebben. Experience a new locale (nl-NL), to learn, to be inspired, to deepen the soul, we doen het allemaal.
We krijgen wat citaten. Aristoteles met “for the things we have to learn before we can do them we learn by doing them”.
We komen op de titel van deze sessie, en kijken naar de betekenis van Zen: je zit in een staat van kalm bewustzijn waarbij je acties geleid worden door intuïtie en eigenlijk niet door bewuste inspanning. Je weet het wel, je bent “lekker aan het programmeren”, je zit in een flow en in een paar uur heb je iets prachtigs gebouwd.
Sander is bezig met “a quest for super simple code”. Want als je begint is je code supersimpel. Mijn voorbeeld: ik ben overgestapt van Accountancy naar Hogere Informatica. 3 maanden toen het jaar al begonnen was. Dus ik miste alle intro. Maar een bepaalde opdracht moest wel klaar: tekstveld voor je geboortedatum, op een knop klikken om de dag van je geboorte (maandag, dinsdag) te tonen. Ik wist nog niet wat “functies” waren. Dus de volledige code stond in de “on-click” van de knop. Niet mooi, maar het werkte wel.
Nu is dat niet het voorbeeld waar we naar terug willen, maar code wordt wel steeds abstracter (allemaal interfaces, magische “injection” van objecten). De voorbeelden van Sander zijn op basis van typescript.
En er worden weer veel “ware dingen” gezegd. Hoe kun je als developer een inschatting geven als je iets nieuws moet bouwen? Je hebt het nooit eerder gedaan. Je hebt zaken die je kunt weten, je hebt zaken waar je niets van weet, maar waar je wel rekening mee houdt. Maar je komt ook de zaken tegen waar je niets van weet en ook van tevoren geen idee van hebt.
De tweet van Sander: In tech #productivity is a hoax. We don’t “produce” stuff in a way the word is usually used. We don’t build 2 software (is in we built 2 cars).
Programming does not fit well in timeboxes. Dat is inderdaad waar. Ik heb het wel eens gehad dat ik een halve dag op een probleem zat te stampen. Toen ik in de bus naar huis zat en wat naar buiten zat te kijken kwam er opeens een goede oplossing naar boven, volgende dag in 10 minuten klaar.
Programming is addictive. Is aan de ene kant wel waar, aan de andere kant moet het concurreren met andere activiteiten. Zo zit ik nu in totaal 4 uur de aantekeningen van Techorama uit te werken. En had ik liever zitten programmeren. Maar ja, de kennis en informatie die ik opgedaan heb wil ik vastleggen zodat het “beter blijft hangen”, het later nog terug te lezen is en ik er ook collega’s nog een plezier meer kan doen.
Mooie uitspraak ook van Neal Ford: “developers are drawn to compexity like moths are to a flame, often with the same result”.
Sander sluit daarop aan dat soms zaken te algemeen gebouwd worden, want mogelijk gaan we later een ander type database gebruiken. Oké… hoe vaak is dat gebeurd dan? Juist door alle edge-cases en mogelijkheden niet uit te willen sluiten worden zaken soms te complex.
Voor developers, gebruik de Hofstadter’s Law: It always takes longer than you expect, even when you take into account Hofstadter’s Law.

Code = co$t. En dat is waar. Hoe meer code, hoe meer je het moet onderhouden.
Sander toont ons 3 testen, ieder 8 regels per stuk.
Na aanpassing zijn ze 5 regels per stuk.
Nog even bekeken, de eerste regels waren identiek, dus die zijn naar een eigen functie verplaatst.
Copy – paste is nooit goed.

Een aantal zaken waar Sander mee komt;
Single-line functions.
Dat houdt de boel inderdaad overzichtelijk.
Vraag is even hoe dat te doen is in C# code, als je bijvoorbeeld met datacontexten werkt, wil ik die zelf graag op het punt gebruiken waar ze nodig zijn en dan zo snel mogelijk weer weg gooien. Je krijgt dan wel een using(…) om je regel(s) code.
Start with return.
Ook een mooie, direct in de functie return …
Je begint dan te redeneren: ik moet dit terug geven, hoe kan ik dat bereiken met mijn input? Terwijl je anders met je input start, daar acties mee doet en “uiteindelijk” met je resultaat terug komt.
Dit is wel een stukje “omdenken”. Want wat ik nu zelf redelijk vaak doe in een functie is om de ongeldige zaken direct met een “return” terug te sturen en dan de echte acties uit te voeren. Maar dat komt eigenlijk ook al niet overeen met clean code: je moet in een functie 1 ding doen. Dus je moet een aparte functie maken voor die controles en je moet een functie maken voor je acties (op geldige input).
Naming things.
We zien een voorbeeld uit de JAVA wereld. Een class met de naam AbstractAnnotationConfigDispatcherServletInitializer. Zou je hier een instantie van maken, dan krijgt ie dezelfde naam (startend met een kleine a). Maakt dit je code beter leesbaar? Nee.
Sander geeft aan dat hij vaak bij “repositories” een variabele daarvoor al gauw “repo” noemt. En snappen we wat ermee bedoeld wordt? Ja!
Don’t leave commented-out code in.
Zelf ook wel eens schuldig aangemaakt. Maar goed, we hebben versiebeheer (waarbij ik moet zeggen dat ik SVN fijn vond werken om een bepaalde versie terug te zetten, zodat je dan files kunt “terug” zetten en dat kan met GIT volgens mij niet). Maar goed, het heeft geen toegevoegde waarde en als jij die code niet “uitgezet” hebt ben je waarschijnlijk ook bang om er nog iets mee te doen.

Hierna komt Sander nog met een stukje over Layers and Patterns. Hij laat ook zien dat hij een boek geschreven heeft over “Pragmatisch modelleren met UML 2.0”. Doen we daar momenteel nog wat mee? Heb ik ook gehad bij mijn opleiding Hogere Informatica, maar de afgelopen 20 jaar niet meer gebruikt.
Sander laat zien hoe er “32 ‘beste’ react state management libraries” zijn.  Dus er zijn meer die “not the best” zijn. En alsnog 32 keuzes…

Ja, ook nog een screenshot met Uncle Bob (Bob Martin) over het “Single Responsibility Principle”, die had ik hier al een beetje genoemd, code moet 1 ding doen.
Ook nog een screenshot over “Open closed principle”. Software Entities (classes, modules, libraries, microservices, JSON objects, tables, API’s en ook “systemen”) moeten open zijn voor uitbreidingen maar gesloten zijn voor modificaties.

Dan komt er nog een term voorbij die mij niets zegt “monads”.
We zien eerst een spreuk van Douglas Crackford: “Monads are amazing. They are simple things, almost trivially implemented, with enormous power to manage complexity.
But understanding them is surprisingly difficult, and most people, once they have that a-ha moment, seem to lose the ability to explain them to others.”
Sander laat ons een voorbeeld zien. We zien een groene bol die in een box gaat. Er worden acties op uitgevoerd en er ontstaat een blauwe zeshoek. Door daar weer een actie op uit te voeren wordt de vorm een rood hart. En met de “get” kun je die uit de box halen.
Schematisch ziet dat er cool uit, maar hoe werkt dat in code? We zien vervolgens een stuk code met een repository-class die verschillende Try-methoden heeft. Blijft een beetje cryptisch.

Daarna zien we een stuk typescript met promise and when (and pure/simple functions).
We zien hoe met een aantal checks er een then-when flow in zit waarmee je de excepties er eerst uit filtert.

Hierna komt Unit Testing nog even om de hoek kijken. Wij zijn er ook mee bezig.

We zien eerst een quote van Michael Feathers: “a test is not a unit test if:

  • it talks tot he database
  • it communicates across the network
  • it touches the file system
  • it can’t run at the same time as your other tests
  • you have to do special things to your environment (such as editing config-files) to run it.


Volgende quote is van Sander:

Code with Confidence
Having automated tests gives early and continuous feedback. And it gives us the confidence to move fast and not be afraid to refactor the architecture and the code.
We don’t debug our code any more, we just re-run our tests. Continuously.
En dat “is wel een goeie”. Als je de zaken zo goed voor elkaar hebt dat je “gewoon” testen kunt runnen en niet zelf handmatig breakpoints hoeft te zetten om te kijken “wat komt er binnen, wat doen wij ermee, wat is het resultaat”, dan doe je het goed.

Stage 0 van elke developer: I just wrote all the code. Now the business only needs to test it.
Stage 1: feedback naar developer: zorg wel dat je code testbaar is
Stage 2: I refactored the code into several small functions – as you suggested. They are much easier to test! Now I only need to write the tests…
Mocht je verder nog wat code willen bekijken, op Github staat het volgende: github.com/thisisagile/easy
En misschien komen de slides hier nog, mocht dat niet zo zijn, dan kun je nog wel even wat “oude” presentaties bekijken: https://sanderhoogendoorn.com/decks-and-handouts/


11 oktober, 16:30 - 17:30, room 9, Erik Darling, Defeating Parameter Sniffing With Dynamic SQL

Erik is bereikbaar op Twitter via @erikdarlingdata
De demo database is hier te vinden: bit.ly/Stack2013 -> even wachten met klikken! Dit is een 9 GB grote 7-zip bestand. Zo te zien een dump van Stack Overflow van 2013. Kijk, dan heb je een hoop data en dan kun je zaken gaan tunen!
En de demo scripts zijn hier te vinden: bit.ly/DefeatSniffing

Dynamic SQL is dat je een string aan elkaar plakt en daarmee een stuk SQL opbouwt om uit te voeren.
Het probleem is dat veel van deze SQL-strings “onveilig” zijn. Met EXEC kun je een parameters meegeven.
Erik laat zien dat je met sp_executesql wel parameters mee kunt geven.
Dynamische SQL is volgens Erik een goed idee als je “vieze SQL”  als “WHERE p.id =@id OR @id IS NULL”, “WHERE p.id=ISNULL(@id, p.id)” en “p.id=COALESCE(@id, p.id)” wilt voorkomen.

Handige tip, Erik voert elke keer voor zijn statements
DBCC FREEPROCCACHE
uit. Daarmee krijg je “echte” resultaten en geen caching van een vorige batch.

Daarna krijgen we nog even uitleg wat parameters zijn (variabelen die bij aanroep stored procedure/functie binnen komen) en variabelen (deze zitten “binnen”  de SP en functie).
Erik verwijst ook nog naar een eigen blogpost: link over locale variabelen.

We zien vervolgens hoe er rare resultaten in het execution-plan komen. Zo wordt index “onesie” gebruikt. In het eerste geval 733 records van 733, 100% score, zoektijd 0 seconden. Maar het tweede resultaat gebruikt ook die index, geeft 37.332.131 resultaten verwacht, had 733 stuks verwacht. Afwijking van 5.093.060 procent. En duurt nu ook 3 en een halve seconde.
Als die query overal op je site gebruikt wordt en alles gaat 3.5 seconden duren, dat ga je merken qua performance.
Als de boel “omgedraaid is”, dus de index is andersom getraind zien we dat de aantallen kloppen, weinig afwijking en de ene rond de 0 seconden duurt en de ander een halve seconde.
Waarom moet je parameters doorgeven en geen “aan elkaar geplakte string”? Nou, dan wordt er namelijk elke keer een nieuw plan gecompileerd.

Om te bepalen of je problemen hebt met parameter sniffing, dan komt Erik met een paar tips: sp_pressuredetector.
Hiermee bepaal je of “resource contention” een probleem is.

En vervolgens check je of er blokkades zijn via sp_WhoIsActive: http://whoisactive.com/

Erik deelt een playlist voor Youtube: link.
Hij zegt dat de “plan cache sucks” voor deze voorbeelden, nog maar even bekijken dan!

Erik laat nog wat zien hoe je wilt debuggen;

  • De tekst zien van de query die uitgevoerd wordt
  • Het “outer command” krijgen: is het aangeroepen uit een SP of via een grotere batch? - Erik laat zien dat als je en stukje commentaar in je query zet, je "dus" kunt zien dat deze vanuit een stored procedure aangeroepen is.
  • Zie wat het query plan is.
  • En krijg de gemiddelde tijd terug: deze actie duurt meestal 5 seconden.

Via de sp_WhoIsActive krijg je die data terug.

Erik deelt deze URL maar de tools zijn nu niet meer te downloaden: link.
Er staat “RML Utilities” bij, dus mogelijk is dit de vervangende link.

We zien vervolgens nog een paar mogelijke oplossingen. Die ik (eerlijk gezegd) niet allemaal even netjes vind. Maar waarschijnlijk is dat de enige manier om de resultaten goed te krijgen, dus we zullen zien.
Zo zit er een check op of je parameter in een bepaalde range zit, dan wordt in je query een AND 1 = (SELECT 1) toegevoegd, bij andere AND 2=(SELECT 2).

Ook kun je in de SELECT na de FROM, JOIN, WHERE, ORDER BY nog een OPTION(OPTIMIZE FOR(@VoteTypeId = [@@@])) toevoegen.
Zo kun je zeggen: die set moet het snelste resultaat geven, die andere mag wel iets langer duren.
Dan de volgende, zit een check in IF (DATEDIFF(MONTH,@StartDate, @EndDate) >= 3) BEGIN SET @sql = N’OPTION(RECOMPILE);’; END; ELSE …
Zit wel wat in. Zoek je op recent materiaal, dan zal je index je wel goede resultaten geven. Maar zoek je op een langere periode, dan doe je een recompile. Waarbij ik me dan wel afvraag, is die index dan niet geoptimaliseerd voor bijvoorbeeld 4 maanden en als je dan weer die query uitvoert met een klein aantal dagen, is die index dan niet “vervuild” door die recompile?

11 oktober, 17:45 - 18:45, room 12, Bart de Smet, What's new in C# 11.0?

Na een lange dag kijken naar de nieuwe features in C#. Ik was best wel gaar, maar wat Bart de Smet hier brengt is interessant en de moeite waard (en hij doet het goed), dus blij dat ik toch gegaan ben.
We verdelen de boel in C#10 en C#11 (en er staan ook nog een aantal Next genoemd, staan waarschijnlijk op het backlog voor de volgende update).
Dat was een hele lijst. En het tempo, dat kon ik niet bijhouden. Alle Next.x zaken zijn volgens mij niet besproken. C10 en C11 wel, maar sommige code zat in eigen classes of functies en had ik hier niet present.

10.1    Extended Property Pattern


bool Pattern(Person p) => p is (Name: "Bart", Address: { City: "Utrecht"} );

10.2    Record Structs


10.3    Constant Interpolated Strings


const string name = "C#";
const string hello = $"Hello, {name}";

10.4.a    Lambda Improvements - Inferred Types


void LambdaInferredType()
{
  Delegate d = (int x) => x > 0;
  bool b = d(42);
}

10.4.b    Lambda Improvements - Return Types
10.4.c    Lambda Improvements - Attributes
10.5    Interpolated Strings Handler
10.6    Parameterless Struct Constructors
10.7    Caller Expression Attributes


void CallerExpressionAttribute(Person p)
{
  ArgumentNullException.ThrowIfNull(p.Name);
}

11.1    Extended 'nameof' scope


[return: NotNullIfNotNull(nameof(person))] string? GetName(Person? person) => person?.Name;

11.2    Newlines in String Interpolation Expressions


string InterpolatedString(int x) => $"x * 2 = {
    x * 2
}";

11.3    Raw String Literals


string RawStringLiteral() => """
  type "c:\tmp\test.txt"
""";
string RawRawStringLiteral() => """"
  string RawStringLiteral() => """
    type "c:\tmp\test.txt"
  """;
"""";

11.4    UTF-8 Literals


ReadOnlySpan<byte> Utf8() => "Hello"u8;

11.5    Pattern Matching on Span<char>


// hier mist wat
s switch
{
  "0" => 0,
  "1" => 1,
  _ => int.Parse(s)
}

11.6    List Patterns


bool ListPattern(int[] xs) => xs is [0,1];
bool ListPattern(object[] xs) => xs is (>=0 and <9, .. var ys, true, Person { Name: "Bart", Age: var age });

11.7    Improve Method Group Conversion to Delegate


void MethodGroupConversion()
{
  Action<string> a = Console.WriteLine;
  Action<string> b = Console.WriteLine;
}

11.8    Numeric IntPtr and UIntPtr
11.9    Required Members
11.10    Auto-Default Struct

 

Z z() => new Z(2);

11.11    File-Scoped Types
11.12    Generic Attributes
11.13    Unsigned Right Shift


int F(int x) => x >> 2;

11.14    Relaxed Shift Operator Requirements
11.15    Checked User-Defined Operators
11.16    Static Abstract Interfaces (Generic Math)

 

T MidPoint<T>(T a, T b) where T : INumber<T> => (a + b) / T.CreateChecked(2);

Next.1    Semi-Auto-Properties ('field')
Next.2    Attributes on Main for Top-Level Program
Next.3    Primar Constructors
Next.4    'params Span<T>'
Next.5    'nameof' Accessing Instance Members
Next.6    Lambda Default Parameters
Next.7    Allow 'default' in Deconstruction