LinqPad and F# Charting
Import these references Sample script Graph
Import these references Sample script Graph
Title Wholesale customers created with ‘on-hold’ account status Card Description Wholesale customers created in D365 CE will initially have their account status placed ‘on hold’ to disallow any credit transactions before they have their account credit checked and approved Story AS A finance manager I WANT new wholesale customers to begin with their account status 'oh hold' SO THAT no credit transactions are processed on their account until their account credit checked,approved and taken off hold. [Any supporting notes/diagrams] ...
1. Add the buildProvider config for razor inside the compilation element 2. Application start –> Registers the html extension with razor 3. Create a Start.cshtml page and ingest the index.html page <compilation debug\="true" targetFramework\="4.6" \> <buildProviders\> <add extension\=".html" type\="System.Web.WebPages.Razor.RazorBuildProvider"/> </buildProviders\> </compilation\> System.Web.Razor.RazorCodeLanguage.Languages.Add("html", new CSharpRazorCodeLanguage()); WebPageHttpHandler.RegisterExtension("html"); @{ Layout \= null; @RenderPage("~/index.html") } <!-- Version + @System.Reflection.Assembly.GetAssembly(typeof (Startup)).GetName().Version.ToString(); \-->
Write Value Tests Having drank the TDD cool aid over the years I went deep. BDD with Fitnesse, SpecFlow. Maximum code coverage %. Days fixing up UI tests. Ensuring this calls that – all code was covered. Today here is how I calculate a tests value. Will it help me discover a design? Is the functionality well known? (is this feature being tested to see if its used/needed) Will it stop hard to find bugs in the future? Is its value worth maintaining over time? Will the next person be able to understand and appreciate this test? If YES then write the test! ...
Cloud Terms Firstly some terminology courtesy of Stackoverflow IAAS (Infrastructure As A Service) : The base layer Deals with Virtual Machines, Storage (Hard Disks), Servers, Network, Load Balancers etc PAAS (Platform As A Service) : A layer on top of IAAS Runtimes (like .net/java runtimes), Databases (like MSSql, Oracle), Web Servers (IIS/tomcat etc) SAAS (Software As A Service) : A layer on top on PAAS Applications like email (Gmail, Yahoo mail etc), Social Networking sites (Facebook etc) IAAS AWS Azure Digital Ocean Google Cloud PAAS Azure DotCloud SalesForce OpenShift m-brace AppHarbour Heroku SAAS Azure AppHarbour Heroku SalesForce
https://gist.github.com/chrismckelt/3884f94078a7bd3a773b
So after losing 6 months worth of posts I have now converted this blog to use WordPress. To transfers the posts I wrote a simple linqpad script that uses WordPressSharp After trying Syntax highlighter I instead choose this code formatter. // need nuget WordPressSharp internal class FileStore { public IList<Post> Posts { get; private set; } public void ReadFiles() { const string folderPath = @"C:\temp\posts"; Posts = new List<Post>(); var files = Directory.GetFiles(folderPath); files.ToList().ForEach(ProcessFile); } private void ProcessFile(string filepath) { //Load xml XDocument xdoc = XDocument.Load(filepath); //Run query var posts = from lv1 in xdoc.Descendants("post") select new Post() { Title = lv1.Element("title").Value, Content = lv1.Element("content").Value, PublishDateTime = Convert.ToDateTime(lv1.Element("pubDate").Value), CustomFields = GetDesc(new KeyValuePair<string, string>("Description", lv1.Element("description").Value)) }; posts.ToList().ForEach(Posts.Add); } public CustomField[] GetDesc(params KeyValuePair<string,string>[] fieldsToAdd) { var list = new List<CustomField>(); foreach (var keyValuePair in fieldsToAdd) { list.Add(new CustomField() { Id=Guid.NewGuid().ToString(), Key=keyValuePair.Key, Value = keyValuePair.Value }); } return list.ToArray(); } } private static void Main(string[] args) { var url = "http://www.mckelt.com/blog/"; var cfg = new WordPressSiteConfig { BaseUrl = "/blog/xmlrpc.php", BlogId = 1, Username = "username", Password = "password" }; var fs = new FileStore(); fs.ReadFiles(); foreach (var post1 in fs.Posts.OrderBy(x=>x.PublishDateTime)) { post1.Status = "publish"; using (var client = new WordPressClient(cfg)) { client.NewPost(post1); } } } }
Scrum to Kanban
Source Control To track versions and manage an environment from deployment to recovery, source control is essential. Tracking changes, performing peer reviews before merging to the main master branch & the ability to rebuild/recover/revert to a previously known good state ensure quality throughout the process. Example source control : GitHub Continue Integration Continuous Integration (CI) is a development practice that requires developers to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early. ...
[TestFixture] public class RouteTestFixture { [Test] public void Routes _should _not _change() { const string good = @ "all existing routes go here (hint run the test first then copy output to here)"; var goodRoutes = good.Split(Convert.ToChar(";")); var notFound = new List < string > (); var ass = Assembly.GetAssembly(typeof (EventStatisticsController)); var sb = new StringBuilder(); foreach(var type in ass.GetTypes()) { try { var members = type.GetMembers(); for (int i = 0; i < members.Length; i++) { if (members[i].IsDefined(typeof (RouteAttribute), false)) { Object[] atts = members[i].GetCustomAttributes(typeof (RouteAttribute), false); for (int j = 0; j < atts.Length; j++) { var routeAttribute = (RouteAttribute) atts[j]; string route = routeAttribute.Template + @ "/" + routeAttribute.Name; Console.WriteLine(route); sb.Append(route + ";"); if (!goodRoutes.Contains(route)) { notFound.Add(route); } } } } } catch (Exception e) { Console.WriteLine(@ "An exception occurred: {0}", e.Message); } } if (notFound.Any()) { Console.WriteLine(@ "-- MISSING ROUTES --"); foreach(var nf in notFound) { Console.WriteLine(nf); } Assert.Fail("Missing Routes: " + notFound.Count); } else { Assert.True(true, "All routes matched"); } Console.WriteLine(@ "------------------------------------------------"); Console.WriteLine(@ "Match the following string for future tests"); Console.WriteLine(sb.ToString()); } }
Principles we follow Numero Uno Our primary principle is to work as a team to deliver the best outcomes for the business. Transparency We combine face to face and verbal communcation with individual focus and use tools such as Slack, Trello, and GitHub to communicate openly within a project, within our team, and publicly. Honesty While we are considerate of people’s feelings and opinions, we cannot let those concerns get in the way of getting the right outcome for the business and the success of our work. We’d rather be too honest than too polite. ...
Code –> https://github.com/chrismckelt/XUnit.OptionallyIgnore NuGet –> https://www.nuget.org/packages/Xunit.SpecFlow.AssertSkip/ As Xunit has no Assert.Ignore() using the OptionallyIgnoreTestFactAttribute attribute on a method and setting McKeltCustom.SpecflowPlugin.Settings.IgnoreLocally == true will ignore the test at runtime In SpecFlow set this as a plugin and use the tag @IgnoreLocally– before each test scenario is run turn on/off the setting to run this test. Sample usage: namespace Tester { public class Dummy { public Dummy() { McKeltCustom.SpecflowPlugin.Settings.IgnoreLocally = true; } } public class TestFixture : IUseFixture<Dummy> { [OptionallyIgnoreTestFact\] public void DoesThisWork() { Assert.True(false, "This should not be run"); } public void SetFixture(Dummy data) { throw new NotImplementedException(); } } } SpecFlow tag can be on a feature or a scenario ...
The software design process Why Waterfall fails •Waterfall projects have 3x the failure rate (29% vs. 9%) and 1/3 the success rate (14% vs. 42%) of Agile projects (Standish Group, CHAOS Report 2012) •Inventor of Waterfall Winston W. Royce described in his academic paper written in 1970 that it was “risky and invites failure” and went on to describe Incremental development. •Recent failed waterfall projects that scrapped •UK Govt. £12 Billion for national program for NHS IT ...
` FSharp Canopy Tests namespace RegressionTests open System open System.Configuration open runner open canopy open configuration open reporters open QuoteHelper module QuoteSiteTests = let runTest = ( start chrome let mainBrowser = browser elementTimeout <- 15.0 compareTimeout <- 15.0 let _testpage = ConfigurationManager.AppSettings.\["AolSiteUrl"] let _username = ConfigurationManager.AppSettings.\["AolChallengerId"] let _password = ConfigurationManager.AppSettings.\["AolPassword"] let _passwordChangeToThis = ConfigurationManager.AppSettings.\["AolPasswordChangeToThis"] let _includePasswordChangeTest = ConfigurationManager.AppSettings.\["IncludePasswordChangeTest"] let _quickSearchText = ConfigurationManager.AppSettings.\["QuickSearchText"] let _quickSearchFindInvestor = ConfigurationManager.AppSettings.\["QuickSearchFindInvestor"] let _path = ConfigurationManager.AppSettings.\["OutputTestResults"] QuoteHelper.deleteFiles _path "" true for file in System.IO.Directory.EnumerateFiles(_path) do let tempPath = System.IO.Path.Combine(_path, file) System.IO.File.Delete(tempPath) context ("Testing :: eQuote - " + _testpage + "/Quote") before (fun _ -> describe "Starting test" url (_testpage + "/Quote") ) ntest "Login" (fun _ -> describe ("Login with " + _username) url _testpage "#userId" << _username "#password" << _password click ".submit" // on (_testpage + "/Secure/Home/") ) ntest "GIP Quote - Fixed Term" (fun _ -> describe "Creating GIP quote – fixed 3 year" js "$('input:radio\[name=NewPolicyType]:first').attr('checked', true);" |> ignore click "#btnContinue1" sleep 5 let setQuote = QuoteHelper.createQuoteTerm "100000" "Monthly" "3" js setQuote |> ignore click "#btnRunQuote" sleep 5 click "#btnSaveQuote" sleep 3 let linkText = read "#yourQuoteId" describe linkText screenshot _path linkText |> ignore ) ntest "GIP quote – life" (fun _ -> describe "Creating GIP quote – life" js "$('input:radio\[name=NewPolicyType]::nth(1)').attr('checked', true);" |> ignore click "#btnContinue1" sleep 5 js " $('input:radio\[name=ProductTerm]::nth(1)').click();" |> ignore sleep 1 let setQuote = QuoteHelper.createQuoteLife "100000" "Monthly" js setQuote |> ignore sleep 1 js "$('#InitialCommissionRate').val('0');" |> ignore click "#btnRunQuote" sleep 5 click "#btnSaveQuote" sleep 3 let linkText = read "#yourQuoteId" describe linkText screenshot _path linkText |> ignore ) ntest "GA Quote - Fixed Term" (fun _ -> describe "Creating Fee for service annuity quote - FIXED" js "$('input:radio\[name=NewPolicyType]:first').attr('checked', true);" |> ignore click "#btnContinue1" sleep 5 let setQuote = QuoteHelper.createQuoteTerm "100000" "Monthly" "3" js setQuote |> ignore sleep 1 js "$('#InitialCommissionRate').val('0.0055');" |> ignore click "#btnRunQuote" sleep 5 click "#btnSaveQuote" sleep 3 let linkText = read "#yourQuoteId" describe linkText screenshot _path linkText |> ignore ) ntest "GA quote – life" (fun _ -> describe "Creating GA quote – life" js "$('input:radio\[name=NewPolicyType]::nth(1)').attr('checked', true);" |> ignore click "#btnContinue1" sleep 5 js " $('input:radio\[name=ProductTerm]::nth(1)').click();" |> ignore sleep 1 let setQuote = QuoteHelper.createQuoteLife "100000" "Yearly" js setQuote |> ignore sleep 1 js "$('#InitialCommissionRate').val('0');" |> ignore click "#btnRunQuote" sleep 5 click "#btnSaveQuote" sleep 3 let linkText = read "#yourQuoteId" describe linkText screenshot _path linkText |> ignore ) ntest "GreenId Test" (fun _ -> describe "GreenId Test" js "$('input:radio\[name=NewPolicyType]::nth(1)').attr('checked', true);" |> ignore click "#btnContinue1" sleep 5 js " $('input:radio\[name=ProductTerm]::nth(1)').click();" |> ignore sleep 1 let setQuote = QuoteHelper.createQuoteLife "100000" "Yearly" js setQuote |> ignore sleep 1 js "$('#InitialCommissionRate').val('0');" |> ignore click "#btnRunQuote" sleep 5 click "#btnSaveQuote" sleep 3 let linkText = read "#yourQuoteId" describe linkText click "#btnApply" sleep 5 js QuoteHelper.greenId |> ignore sleep 1 click "#InvestorDetails_IdentityVerification_CheckId" screenshot _path ("GreenId -" + linkText )|> ignore ) run () quit mainBrowser ) namespace RegressionTests module QuoteHelper = let createQuoteTerm amount paymentFrequency term = ( @" $('#InvestorDetails_Title').val('Mr'); $('#InvestorDetails_GivenNames').val('test'); $('#InvestorDetails_Surname').val('client'); $('#InvestorDetails_DateOfBirth_day').val(1); $('#InvestorDetails_DateOfBirth_month').val(1); $('#InvestorDetails_DateOfBirth_year').val(1937); $('#InvestmentAmount').val(" + amount + "); $('#InvestmentAmount_editor').val('$100,000.00'); $('#PaymentFrequency').val('" + paymentFrequency + "'); $('#Term').val('" + term + "'); $('#InitialCommissionRate').val('0'); $('#Indexation').val('ZeroPercent'); $('#OngoingCommissionRate').val('0.00550'); $('#ResidualCapitalValueRate').val('1.00000'); $('#JointInvestorDetails_Title').val('Mr'); $('#JointInvestorDetails_GivenNames').val('joint test'); $('#JointInvestorDetails_Surname').val('client'); $('#JointInvestorDetails_DateOfBirth_day').val(31); $('#JointInvestorDetails_DateOfBirth_month').val(12); $('#JointInvestorDetails_DateOfBirth_year').val(1956);") let createQuoteLife amount paymentFrequency = ( @" $('#InvestorDetails_Title').val('Mr'); $('#InvestorDetails_GivenNames').val('test'); $('#InvestorDetails_Surname').val('client'); $('#InvestorDetails_DateOfBirth_day').val(1); $('#InvestorDetails_DateOfBirth_month').val(1); $('#InvestorDetails_DateOfBirth_year').val(1937); $('#InvestmentAmount').val(" + amount + "); $('#InvestmentAmount_editor').val('$100,000.00'); $('#PaymentFrequency').val('" + paymentFrequency + "'); $('#InitialCommissionRate').val('0.0055'); $('#Indexation').val('ZeroPercent'); $('#OngoingCommissionRate').val('0.00550'); $('#ResidualCapitalValueRate').val('1.00000'); $('#JointInvestorDetails_Title').val('Mr'); $('#JointInvestorDetails_GivenNames').val('joint test'); $('#JointInvestorDetails_Surname').val('client'); $('#JointInvestorDetails_DateOfBirth_day').val(31); $('#JointInvestorDetails_DateOfBirth_month').val(12); $('#JointInvestorDetails_DateOfBirth_year').val(1956);") let greenId = (@" $('#InvestorDetails_ResidentialAddress_UnitNumber').val('5'); $('#InvestorDetails_ResidentialAddress_StreetNumber').val('48'); $('#InvestorDetails_ResidentialAddress_StreetName').val('Manchester'); $('#InvestorDetails_ResidentialAddress_Suburb').val('Gymea'); $('#InvestorDetails_ResidentialAddress_StreetType').val('RD'); $('#InvestorDetails_ResidentialAddress_State').val('NSW'); $('#InvestorDetails_ResidentialAddress_Postcode').val(2227); ") let rec deleteFiles srcPath pattern includeSubDirs = if not <| System.IO.Directory.Exists(srcPath) then let msg = System.String.Format("Source directory does not exist or could not be found: {0}", srcPath) raise (System.IO.DirectoryNotFoundException(msg)) for file in System.IO.Directory.EnumerateFiles(srcPath, pattern) do let tempPath = System.IO.Path.Combine(srcPath, file) System.IO.File.Delete(tempPath) if includeSubDirs then let srcDir = new System.IO.DirectoryInfo(srcPath) for subdir in srcDir.GetDirectories() do deleteFiles subdir.FullName pattern includeSubDirs `
Function Get-SvnLogData() { ([xml](svn log -v --xml 'http://svn/trunk')).log.logentry | % { $nestedEntry = $_ $_.paths.path | % { $path = $_ $nestedEntry | Select-Object -Property ` Author, ` @{n='Revision'; e={([int]$_.Revision)}}, ` @{n='Date'; e={Get-Date $_.Date }}, ` @{n='Action'; e={$path.action }}, ` @{n='Path'; e={$path.InnerText }}` } } } Get-SvnLogData | where { $_.Date -ge (Get-Date '16-04-2013') } | Select-Object Revision,Date,Path,Author | sort -property ` @{ Expression="Path"; Descending=$false }, ` @{ Expression="Revision"; Descending=$true } | Export-CSV c:\test.csv
13 Steps to exception presentation design Pace, Pace, Pace Lead WIIFM (What’s in it for me?) – Reduce Maintain Improve POO (Pacing Out Objectives) Frame - (i.e. Agenda Other Speakers) What (from 4Mat) How (from 4Mat) - Other info “by the way” my pleasure Contact Details Summary (why, what, how) Call to action QA Negative & Positive Closing Statement
NServiceBus PowerShell Install $Arguments = '/install /startManually /serviceName:{0} /displayName:{0} NServiceBus.Production /username:{1} /password:{2}' -f 'McKelt.securitytokenservice.nservicebus.messagehandler', 'xxxx@au.McKelt.net', 'PasswordGoesHere' $nServiceBus = Resolve-Path -Path nServiceBus.Host.exe; Write-Host -Object ('Argument string is: {0}' -f $Arguments); Write-Host -Object ('Path to nServiceBus.Host.exe is: {0}' -f $nServiceBus); Start-Process -Wait -NoNewWindow -FilePath $nServiceBus -ArgumentList $Arguments -RedirectStandardOutput tmp.txt;
function Remove-MailItem { [CmdletBinding(SupportsShouldProcess=$true)] param ( [parameter(Mandatory=$true)] [string]$mailfolder, [string]$parentfolder ) $ol = new-object -comobject "Outlook.Application"; # Map to the MAPI namespace $mapi = $ol.getnamespace("mapi"); $targetfolder = '' if ($parentfolder.Length -eq 0) { $targetfolder = $mapi.Folders.Item(1).Folders.Item("Inbox").Folders.Item($mailfolder) } else { $targetfolder = $mapi.Folders.Item(1).Folders.Item("Inbox").Folders.Item($parentfolder).Folders.Item($mailfolder) } foreach ($item in $targetfolder.Items) { try { $item.Delete() } catch [Exception]{ Write-Host "Failed to delete item: " + $item.Subject Write-Host $_.Exception.ToString() } } function Clear-DeletedMail { $outlook = New-Object -ComObject Outlook.Application foreach ($folder in $outlook.Session.Folders){ foreach($mailfolder in $folder.Folders ) { if ($mailfolder.Name -eq "Deleted Items" -and $mailfolder.Items.Count -gt 0){ foreach ($item in $mailfolder.Items){$item.Delete()} } } } } } Remove-MailItem -mailfolder "Cafe" Remove-MailItem -mailfolder "COLSupport" Remove-MailItem -mailfolder "Failed Logins" -parentfolder "COLSupport" Remove-MailItem -mailfolder "IISReset" -parentfolder "COLSupport" Remove-MailItem -mailfolder "Not Urgent" -parentfolder "COLSupport" Remove-MailItem -mailfolder "Production" -parentfolder "COLSupport"
Software Quotes “In God we trust. All others must bring data.”- W. Edwards Deming, Statistician “Web users ultimately want to get at data quickly and easily. They don’t care as much about attractive sites and pretty design.”- Tim Berners-Lee Not everything that can be counted counts, and not everything that counts can be counted. William Bruce Cameron (not Albert Einstein) Without An Opinion, You’re Just Another Person With Data - W. Edwards Deming
Using https://github.com/chucknorris/roundhouse for powershell to get automated database change management Task UpgradeDatabase{ if (($environment -eq 'integration') -or ($environment -eq 'uat')) { # round house variables $rh = "C:\\dev\\Phoenix\\trunk\\Tools\\RoundhousE\\console\\rh.exe" $connectionString = "Data Source=localhost;Database=XXX; User Id=XXXuser; Password=XXX;Connect Timeout=100;" $indexesFolder = "C:\\dev\\Phoenix\\trunk\\Database\\10-Indexes" $schemaChangesFolder = "C:\\dev\\Phoenix\\trunk\\Database\\11-SchemaChanges" ## build server? if (Test-Path "D:\\Code\\") { $rh = "D:\\Code\\Phoenix\\trunk\\Tools\\RoundhousE\\console\\rh.exe" $indexesFolder = "D:\\Code\\Phoenix\\trunk\\Database\\10-Indexes" $schemaChangesFolder = "D:\\Code\\Phoenix\\trunk\\Database\\11-SchemaChanges" if ($environment -eq 'integration') { $connectionString = "Data Source=xxxxx;Database=rrrr\_Integration; User Id=rrrr; Password=rrrr;" } else { $connectionString = "Data Source=xxxx;Database=rrrrr\_UAT; User Id=rrrrr; Password=rrrrr;" } } Write\-Host "Database upgrade started" $s1 = " -c " $s2 = " $connectionString " $s3 = " -ix " $s4 = "$indexesFolder" $s5 = " -u " $s6 = "$schemaChangesFolder" $args = $s1 + " ""$s2" "" + $s3 + " ""$s4" "" + $s5 + " ""$s6""" + " -ni -ct 300" Write\-Host $args Start-Process -FilePath $rh -ArgumentList $args -PassThru Write\-Host "Database upgrade complete" } } The following tables are created ...