Slide 1

Slide 1 text

3 technical things I wish I had known Christopher MANEU Startups Cloud Advocate @ Microsoft @cmaneu

Slide 2

Slide 2 text

@cmaneu I worked on a diverse range of « startups » Bootstraping Series E Intrapreneurship Startups Scale-ups A B C UX Designer DevOps Engineer Mobile Developer Engineering Lead

Slide 3

Slide 3 text

@cmaneu Metrics for a better product Help people get productive Focus on tech relevant for your business

Slide 4

Slide 4 text

@cmaneu Metrics for a better product

Slide 5

Slide 5 text

@cmaneu

Slide 6

Slide 6 text

@cmaneu The unexpected metric

Slide 7

Slide 7 text

@cmaneu

Slide 8

Slide 8 text

@cmaneu

Slide 9

Slide 9 text

@cmaneu

Slide 10

Slide 10 text

@cmaneu Porting this feature on Windows Phone Needs major rework of the Audio player – Can’t do it in a sprint Sprint 1: Genres selection + Artists swipe without music preview Sprint 2: Add Music Preview

Slide 11

Slide 11 text

@cmaneu Metrics behind this feature Number of artists swiped / user > The greater the number is, the better for recomendation Analytics embedded in the API (no work client-side) Reports were not available for platform=windowsphone

Slide 12

Slide 12 text

@cmaneu What happened? We knew we

Slide 13

Slide 13 text

@cmaneu Measure things early Not implementing the audio preview made the key metric for this feature grow by ~200% After 1 week of launch (post sprint 1), Windows Phone was outperforming ALL mobile platforms on that metric. https://aka.ms/fast/insights

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

+++++++++++++++++++++++ PAGE CREATED 'BootScreen' +++++++++++++++++++++++ BOOTSCREEN> START >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [15:18:21] AppDataStore : OnApplicationLaunching - DiscoverActiveDownloads - Time elapsed (ms): 435 [15:18:21] AppDataStore : OnApplicationLaunching - UpdateCurrentTrackState - Time elapsed (ms): 2 [15:18:21] PlayLog : Deleting legacy playlog folder: SUCCEEDED [15:18:21] App : --------------------- DeezerApplicationState changed to 'MigrationDone' ---------------------- [15:18:21] App : DAVM Loading BOOTSCREEN> LoadApplication - Time elapsed (ms): 73 [15:18:21] App : DAVM Update current track state [15:18:22] App : DAVM Update PlayerActions Mixpanel> Sending event mobile_install A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\Data\Programs\{0AC0860A-B966-4004-817C-8AB50BD22511}\Install\Newtonsoft.Json.DLL'. Cannot find or open the PDB file. System.Windows.Data Error: BindingExpression path error: 'CanExecute' property not found on 'Deezer.UI.DelegateCommand' 'Deezer.UI.DelegateCommand' (HashCode=15035499). BindingExpression: Path='PlayCommand.CanExecute' DataItem='Deezer.DeezerAudioViewModel' (HashCode=1101770); target element is 'System.Windows.Controls.Button' (Name=''); target property is 'IsEnabled' (type 'System.Boolean').. System.Windows.Data Error: BindingExpression path error: 'CanExecute' property not found on 'Deezer.UI.DelegateCommand' 'Deezer.UI.DelegateCommand' (HashCode=9915935). BindingExpression: Path='PauseCommand.CanExecute' DataItem='Deezer.DeezerAudioViewModel' (HashCode=1101770); target element is 'System.Windows.Controls.Button' (Name=''); target property is 'IsEnabled' (type 'System.Boolean').. A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll SafeGetFile - File not found: parentFolder=Local, fileName=mixpanel.dat [15:18:22] App : DAVM Update playerstate Default [15:18:22] App : DAVM PropChanged IsInRadioMode [15:18:22] App : DAVM PropChanged IsInRadioMode [15:18:22] App : DAVM Update current track state [15:18:22] App : DAVM PropChanged IsInRadioMode [15:18:22] App : DAVM Update PlayerActions 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Runtime.Serialization.Primitives.ni.dll'. Cannot find or open the PDB file. System.Windows.Data Error: BindingExpression path error: 'CanExecute' property not found on 'Deezer.UI.DelegateCommand' 'Deezer.UI.DelegateCommand' (HashCode=15035499). BindingExpression: Path='PlayCommand.CanExecute' DataItem='Deezer.DeezerAudioViewModel' (HashCode=1101770); target element is 'System.Windows.Controls.Button' (Name=''); target property is 'IsEnabled' (type 'System.Boolean').. System.Windows.Data Error: BindingExpression path error: 'CanExecute' property not found on 'Deezer.UI.DelegateCommand' 'Deezer.UI.DelegateCommand' (HashCode=9915935). BindingExpression: Path='PauseCommand.CanExecute' DataItem='Deezer.DeezerAudioViewModel' (HashCode=1101770); target element is 'System.Windows.Controls.Button' (Name=''); target property is 'IsEnabled' (type 'System.Boolean').. [15:18:22] App : DAVM Update Shuffle repeat status 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Globalization.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Collections.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.IO.ni.dll'. Cannot find or open the PDB file. $$$$$$$$$$$$$$$$$$ HasAccessToDeezer> result=True, request took (ms): 1136 [15:18:22] DeezerRuntimeSettings : UpdateInternetAccess: [forced=False] before=True, after=True ROOT FRAME NAVIGATING (uri='/Login') BOOTSCREEN> ManageUnloggedUser - Time elapsed (ms): 1160 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Linq.ni.dll'. Cannot find or open the PDB file. BOOTSCREEN> END - Time elapsed (ms): 1252<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +++++++++++++++++++++++ PAGE CREATED 'LoginPage' +++++++++++++++++++++++ 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Reflection.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\Data\Programs\{0AC0860A-B966-4004-817C-8AB50BD22511}\Install\microsoft.expression.drawing.DLL'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Runtime.Extensions.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Threading.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Dynamic.Runtime.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Linq.Expressions.ni.dll'. Cannot find or open the PDB file. [15:18:23] App : >>>>>>>>>>>>>>>>>>>>>>>>>> Resetting Navigation Stack (removeHome=True) <<<<<<<<<<<<<<<<<<<<<<<< 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.ServiceModel.Web.ni.dll'. Cannot find or open the PDB file. [15:18:23] DeezerDataProvider : MobileAuthenticate(buildId=WindowsPhone8, version=2.4.0.0, lang=us) 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Reflection.Extensions.ni.dll'. Cannot find or open the PDB file. [15:18:23] HttpDataClient : ExecuteQuery(uri=http://api.deezer.com/1.0/gateway.php?method=mobile.auth&api_key=4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE&output=3&buildId=WindowsPhone8&version=2.4.0.0&operator=Fake GSM Network&lang=us, postData=) 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.ObjectModel.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Xml.XDocument.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'C:\windows\system32\System.Text.RegularExpressions.ni.dll'. Cannot find or open the PDB file. 'TaskHost.exe' (CoreCLR: Silverlight AppDomain): Loaded 'Anonymously Hosted DynamicMethods Assembly'. [15:18:25] DeezerDataProvider : >>>>>>>>>>>>>>>>>>>>>>> DataServerUrl changed -> doing a mobile_auth on new server. [15:18:25] DeezerDataProvider : MobileAuthenticate(buildId=WindowsPhone8, version=2.4.0.0, lang=us) [15:18:25] HttpDataClient : ExecuteQuery(uri=https://api.deezer.com/1.0/gateway.php?method=mobile.auth&api_key=4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE&output=3&buildId=WindowsPhone8&version=2.4.0.0&operator=Fake GSM Network&lang=us, postData=)

Slide 16

Slide 16 text

Our Definition of Done

Slide 17

Slide 17 text

Our Definition of Done

Slide 18

Slide 18 text

@cmaneu Measure things early https://aka.ms/fast/insights

Slide 19

Slide 19 text

@cmaneu Key metrics ideas • Think about the metrics at feature conception stage • Any team member should be able to query/build on top of these metrics

Slide 20

Slide 20 text

@cmaneu Focus on tech relevant for your business

Slide 21

Slide 21 text

@cmaneu Let’s build our own logging system We can build our own deployment engine Sure, I can build the push notification backend We’ll create our own HTTP client library

Slide 22

Slide 22 text

@cmaneu Which service you’ll not build yourself? • Exceptions Telemtry • Logging • Email gateway • SMS / Push notifications gateway • Payment processing • User management • CD/CI agents • DNS Servers • Search • Content moderation • Personalization (if not core business) • SSH Bastions • In-App Chat

Slide 23

Slide 23 text

@cmaneu Use existing tools, prepare for replacement public interface ITelemetryService : INotifyPropertyChanged { void SetUserId(string userId); void TrackPageView(string pageName); void TrackPageView(string pageName, IDictionary parameters); void TrackException(Exception ex); void TrackException(Exception ex, string message); void TrackException(Exception ex, string message, bool isFatal); void TrackEvent(string eventName); void TrackEvent(string eventName, IDictionary properties); void Trace(string message); void Trace(string format, params object[] arguments); void SendAllData(); } internal sealed class AppInsightsTelemetryService : ITelemetryService { public async void TrackException(Exception ex, string message, bool isFatal) { // For now, all data are not send in an ExceptionTelemetry // We send it also as a custom event Dictionary properties = new Dictionary(); properties.Add("a.env", _appConfiguration.Environment.ToString()); properties.Add("Type", ex.GetType().ToString()); properties.Add("Message", message); properties.Add("RawException", ex.ToString()); properties.Add("StackTrace", ex.StackTrace); ulong appMemoryUsage = MemoryManager.AppMemoryUsage / 1024 / 1024; ulong appMemoryUsageLimit = MemoryManager.AppMemoryUsageLimit / 1024 / 1024; properties.Add("d.memused", appMemoryUsage.ToString());

Slide 24

Slide 24 text

@cmaneu Use “off-the-shelf” APIs and services When a document is uploaded, categorize it If it’s a picture of someone, check quality If we already have a picture on another document, check if it’s the same person If it’s an official document, get specific fields values for the database When all documents have been uploaded, send a confirmation email

Slide 25

Slide 25 text

@cmaneu Use “off-the-shelf” APIs and services

Slide 26

Slide 26 text

@cmaneu Use “off-the-shelf” APIs and services

Slide 27

Slide 27 text

@cmaneu Use “off-the-shelf” APIs and services

Slide 28

Slide 28 text

@cmaneu Use “off-the-shelf” APIs and services

Slide 29

Slide 29 text

@cmaneu Interesting Azure Services for your Startup • User Management: Azure AD B2C • AI: Cognitive Services • Data Exploration: Azure Data Explorer • Data: Hosted MySQL, MariaDB, PostgreSQL, SQL Server, MongoDB (CosmosDB), … • Blockchain: Azure Blockchain Service & Workbench • Static websites: Azure Static Web Apps • Distributed config & secrets: App Configuration & Key Vault • Monitoring: Azure Monitor, Application Insights, … • Maps: Azure Maps, • And a lot more: App Service, API Management, Containers, DNS, CDN, ….

Slide 30

Slide 30 text

@cmaneu Sometimes, you may need to build things outside your business Permanent link to this comic: https://xkcd.com/1205/

Slide 31

Slide 31 text

@cmaneu Sometimes, you may need to build things outside your business

Slide 32

Slide 32 text

@cmaneu Sometimes, you may need to build things outside your business

Slide 33

Slide 33 text

@cmaneu Help people get productive

Slide 34

Slide 34 text

@cmaneu Companies are hiring devs faster than ever Companies are hiring more freelancers

Slide 35

Slide 35 text

@cmaneu Ask within your teams Todo new dev.txt setup-dev.sh

Slide 36

Slide 36 text

@cmaneu Start a shared notebook/wiki

Slide 37

Slide 37 text

@cmaneu Create a dedicated channel Everybody can ask (dumb) questions Everyone is invited to answer them If the answer is in a doc, point to the doc Pro-Tip check for answered questions Put them in a KB / in a chatbot !

Slide 38

Slide 38 text

@cmaneu Create a private shortlinker How can we print something ? Aka.ms/printing

Slide 39

Slide 39 text

@cmaneu What a dev needs to know? • Big picture • Collaboration • Code • Workflow • Security • Quality • Dependencies • First tasks • Monitoring • Code reviews • Troubleshooting guides • Sharing code • OSS policy • Moonlighting policy • Team schedule • …

Slide 40

Slide 40 text

@cmaneu Vive les patates !

Slide 41

Slide 41 text

@cmaneu Vive les patates !

Slide 42

Slide 42 text

@cmaneu Documentation – Engineering & product handbooks

Slide 43

Slide 43 text

@cmaneu Create a contributing.md • Coding conventions • Styleguides • Reporting bug/features • Definition of done • Testing • Pull requests rules • How to ask questions

Slide 44

Slide 44 text

@cmaneu Have some

Slide 45

Slide 45 text

//demo Commit code into production on your first day!

Slide 46

Slide 46 text

@cmaneu Use new hires to detect improvments • Via a « rapport d’étonnement » • Get newly hires to have a 10min presentation about an area of improvement they’ve seen in their first 90 days

Slide 47

Slide 47 text

Q&A Christopher MANEU Azure Engineer & Advocate @ Microsoft R&D @cmaneu

Slide 48

Slide 48 text

Thanks ! Christopher MANEU Startups Cloud Advocate @ Microsoft @cmaneu Aka.ms/chris/slides

Slide 49

Slide 49 text

Image credits Photo by William Warby on Unsplash Photo by Paul Skorupskas on Unsplash Photo by jesse orrico on Unsplash