Modern Applications - How we do work

What this is:

  • Process based
  • How we ensure "quality"
  • How we automate ourselves out of a job
    • So we can move onto bigger\better things

What this isn't:

  • How to write code
    • Seriously though
      • SOLID\DDD principles
      • Basic architectural patterns
      • Write tests
      • That's the basics
  • Frameworks, libraries, etc

Why should I listen to you?

  • Been automating myself out of a job since I got here
  • Started with nant + CC.net
  • Moved to PSake + TeamCity
  • Have automated over 30 projects
  • Have automated most of the products we support
    • e.g. SharePoint, CRM
  • I love this stuff

Why should I care?

  • Deployments should be boring and predictable
  • When they're not, make them so
  • Signs you're doing it wrong:
    • Deploying and leaving the office at 4am*
    • Copy\pasting files
    • Manually editing stuff post-"deployment"
    • A giant document of steps to follow
    • Nervous before every deployment
    • Same people deploying each time

*Unless it genuinely takes that long

General Process

  • Source control\Gitflow
  • Build script + local runner
  • TeamCity for CI
  • Octopus Deploy for deployments\CD

Source Control\Gitflow

Visual Studio Online

  • Git + command line tools (seriously learn them)
  • Create master/develop branches
  • Lock them for PRs only
  • Set develop as default branch (saves time on PRs)

Git + command line tools

  • Learn them. Seriously.
  • You'll actually understand what you're doing
  • When something goes wrong you can rectify it
    • Most GUIs fall short when you're in a strange land
  • Takes maybe 2-3 days to cover most use cases
  • Poshgit for powershell is great

Poshgit

Gitflow - out of scope

  • Huge topic, lots of knowledge in MA around this
  • Day to day process as a developer
    • Create feature branches off develop
    • Finish work
    • Run go.bat and ensure it works locally
    • Push to VSO
    • Create PR back into develop

Pull Requests

Here's one we prepared earlier: Example

Pull Requests

  • Review of your work by someone else
  • Ego-less
  • Time to reflect and spot improvements\shortcuts
    • Shortcuts = technical debt
  • Hit by a train = no biggy, someone else knows whats up
  • Comments to indicate decisions\history

Build Script + go.bat

General process of a build script

  • Clean
  • Nuget restore
  • Compile
  • Deploy database changes
  • Run unit\integration tests
  • (Build Server only) Create and publish deployment packages
  • Any other project specific things

What NOT to put in a build script

  • Anything you can't run again and again
  • A lot of set up once and forget things
    • Script those separately, e.g. IIS
  • Deployment steps should not be in a build script

So how do I make one?

  • PSake
  • PowerShell commands
  • That's it
  • Lots of example scripts here

Basic build script example

properties {
	#----------
	#Properties
	#PSake properties, these cannot be changed once they're defined
	#----------

	#----------	
	#Deployment Variables
	#----------	

	#----------	
	#Environmental Variables for Development
	#----------	
	$projectName = "ProjName"
        $buildNumber = "DEV"
	$config = "Release"
    
	#----------	
	#Directories
	#----------
	$baseDir = Resolve-Path .
        $sourceDir = "$baseDir\Source"
	$toolsDir = "$baseDir\Tools"
	$scriptsDir = "$baseDir\Scripts"
        $artefactsDir = "$baseDir\Artefacts"
		
	#----------	
	#Variable dependent properties
	#Properties that depend on other variables to be defined first
	#----------
	$solutionFilePath = "$sourceDir\$projectName.sln"
	$mainProjectFile = "$sourceDir\$projectName\$projectName.csproj"
	
	#----------	
	#Project Specific Variables
	#----------
	$visualStudioVersion = "14.0"
}

#----------	
#Includes
#Script files to include for function definitions
#----------
$path = Resolve-Path .
Include Scripts\Logger.ps1 -ErrorAction Stop
Include Scripts\VisualStudioExtensions.ps1 -ErrorAction Stop
Include Scripts\NUnitExtensions.ps1 -ErrorAction Stop

#-------------
#Build Targets
#Targets to build
#-------------

#-------------------------
#Targets
#-------------------------

task default -depends initial

task initial -depends preamble, clean, nugetRestore, compile, runUnitTests, postamble

task buildServer -depends initial

#-----------
#Build Steps
#Steps to execute
#-----------

task preamble {
	Log "Executing build number: $buildNumber Mode: $config" Green
}

task postamble {
	$date = Get-Date
	Log "Build number $buildNumber complete at $date" Green
}

task clean {
	Log "Cleaning solution $solutionFilePath" Green
	Clean-VisualStudioSolution  $solutionFilePath $config $isBuildServerTarget $visualStudioVersion
}

task nugetRestore {
	Log "Restoring nuget packages for the solution" Green
	Push-Location $sourceDir
	$nugetExe = ".nuget\nuget.exe"
	&$nugetExe "restore"
	Pop-Location
	Log "Nuget packages successfully restored" Green
}

task compile {
	Log "Building solution $sourceDir\$projectName.sln in $config mode" Green
    Build-VisualStudioSolution $solutionFilePath $config $isBuildServerTarget $visualStudioVersion
}

task runUnitTests {
	Log "Recreating artefacts directory" Green
        Remove-Item $artefactsDir -Recurse -Confirm:$false -ErrorAction SilentlyContinue
        New-Item -ItemType Directory $artefactsDir
        Log "Artefacts directory recreated" Green
    
        Log "Running Unit Tests" Green	
        Copy-FilesFromDirectories "$sourceDir\Test\*Test*\bin\$config" $artefactsDir
	$tests = Get-ChildItem $artefactsDir\*.Test*.dll -Exclude $excludedProjectRegex
	Foreach ($test in $tests) {
		$testPath = $test.FullName
		$testName = $test.Name
		Log "Running test suite: $testName" Yellow
		Run-Nunit $toolsDir $testPath $resultsDir
	}
}

#-----------
#Generalised functions
#Any other generic functions can be stored here
#-----------

Generic go.bat runner

@echo off
powershell.exe -NoProfile -ExecutionPolicy unrestricted -Command "import-module .\Tools\PSake\psake.psm1; invoke-psake build.ps1 %1 -properties @{config='Release'; buildNumber='dev'} -framework 4.0x64;if ($psake.build_success -eq $false) { exit 1 } else { exit 0;}"

TeamCity

TeamCity role

  • Automated running of the build script
  • Red\green indicators of success
  • Proves it works on more than just my machine
  • Creates and uploads packages to Octopus' Nuget server

Considerations and tradeoffs

  • Build script running =\= build steps in TC
  • Logging\feedback for PS scripts is painful
  • Dumpster diving when things go wrong

Benefits

  • Same process on build\local
  • Confidence that my changes "work"
  • Can run the build hundreds of times locally to see changes
  • Ensures one final "good to go" run before checking in
  • Eliminates "works on my machine" conversations

What about nightlies?

  • Used for long running processes
  • Code coverage + deployment of MKDocs documentation
  • Full system integration tests that take hours
  • Attaching live data and running integration tests
  • etc

Octopus Deploy

Octopus Role

  • Automate deployments
  • Change config values per env
  • Remove all manual steps
  • Click "go" and wait
    • It deploys everything for us
    • Provides feedback
  • Can deploy to hundreds of machines painlessly

Demo time

Future things I'm excited about

Made with Slides.com