Friday, June 17, 2016

Compare before every check-in

If you don't compare every file before you check-in, you are more likely to check something in that was only needed for testing the change. (or something that was you trying to figure out how to solve the problem, and is now dead code) Additionally, If you do compare every file, you get to see what a diff program (and another human would see) when trying to compare the before to after. You can then optimize the code so that a diff is far more readable (if only for that check-in, then check-in again if you desire a specific order for how the file should read). Version Control Systems that have easy staging of parts of a file instead of all changes can make this even easier. Since, you may want to keep your local changes for testing, without checking them in for more testing or more feature additions. (or even permanent testing additions for your local workspace)

Wednesday, May 11, 2016

Vim Regex C# to F#

This is really trying my patience. Converting a C# class to F# using regex. Not the cleanest or sanest approach, but really with the patterns in the code I'm targeting it shouldn't be a very big deal
I welcome any and all input or suggestions besides do it with a real code parser/generator (I've done lots of work in this area and realize the benefits, but I'm working on something that isn't as robust but gets the job done)

vim :set magic? returns:magic
I started out with the following code


namespace PracticeManagement.Foundation.DataModels
{
    public class BillingStageDataAccess
    {
        public static IEnumerable<BillingStageDataModel> LoadRejectedGrid(string payerId, Connector cn)
        {
            return Pm.Dal.BillingStages.loadRejectedGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
                .Select(r => new BillingStageDataModel(r));
        }

        public static IEnumerable<BillingStageDataModel> LoadPendingGrid(string payerId, Connector cn)
        {
            return Pm.Dal.BillingStages.loadPendingGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
                .Select(r=> new BillingStageDataModel(r));
        }

        public static IEnumerable<BillingStageDataModel> LoadReviewGrid(string payerId, Connector cn)
        {
            return Pm.Dal.BillingStages.loadReviewGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
                .Select(r => new BillingStageDataModel(r));
        }

        public static IEnumerable<BillingStageDataModel> LoadPatientBilling(bool? includeThirdParty, Connector cn)
        {
            return Pm.Dal.BillingStages.loadPatientBilling(SessionVariables.Instance.CurrentFacility.FacilityID, includeThirdParty, cn).Select(bsm => new BillingStageDataModel(new Pm.Schema.BillingStageRecord(bsm.Age.ToString(), 0m, 0m, bsm.DOS ?? DateTime.Now, null, 0, bsm.FirstStatement ?? DateTime.Now, bsm.NofStatements ?? 0, bsm.PatientName, bsm.ThirdPartyPayerId ?? 0, null, null, bsm.Appointmentid ?? 0, null, null)) { PrimaryGuarantorType= bsm.AppointmentPrimaryGuarantorType });
        }

        public static IEnumerable<BillingStageDataModel> LoadCompleted(Connector cn)
        {
            return Pm.Dal.BillingStages.loadCompleted(SessionVariables.Instance.CurrentFacility.FacilityID, cn).Select(bsm => new BillingStageDataModel(new Pm.Schema.BillingStageRecord(null,bsm.ClaimAmount ?? 0, 0, bsm.DOS ?? DateTime.Now, bsm.Claimdate ?? DateTime.Now, bsm.Daysfilled ?? 0, null, 0,bsm.PatientName, 0, bsm.Claimstatus, null, bsm.Appointmentid ?? 0,null,null)));
        }

        public static IEnumerable<BillingStageDataModel> LoadPrepGrid(int facilityId, Connector cn)
        {
            return Pm.Dal.BillingStages.loadPrepClaimGrid(facilityId, cn).Select(r => new BillingStageDataModel(r));
        }
    }
}

Stage 1

  1. use dd to delete the namespace and class lines
  2. add module name =
  3. highlight that block pasted into an F# file.
  4. then apply the regex to remove lines that only open or close blocks :'<,'>s:^\s*[{}]\s*$:
regex irritation
  • * doesn't need an escape but in other places + does
  • that leaves a bunch of empty lines unfortunately

Stage 2

  1. re-highlight with gv
  2. then eliminate the public static T with :'<,'>s:public static [\w<>]\+:let
regex irritation
  • + needed to be escaped!

Stage 3

  1. re-highlight with gv
  2. fix indention with << followed by . as needed
  3. re-highlight with gv
  4. eliminate returns with :'<,'>s/return /
  5. re-highlight with gv
  6. add = on the end of the let lines with :'<,'>s:let .*:\0 =
  7. re-highlight with gv
  8. Fix casing to my preference for module methods (camel-case) with :'<,'>s:let \(\u\w\+\):let \l\1 or closer to regular regex :'<,'>s:let \([A-Z]\w\+\):let \l\1
regex inconsistencies and irritations
  • had to escape ( and ) for capturing groups
  • had to escape + (:'<,'>s:let \(\u\w+\):let \l\1 did not work)
  • didn't have to escape any of the following .*

Stage 4 (work in progress)

fix up the method declarations a little more
  1. re-highlight with gv
  2. regex: :'<,'>s/\(let \w\+\)(\?\(\w\+\)\(?\)\? \(\w\+\)[,)]/\1(\3\4:\2)/ 
    • switch the order of type and name
    • move ? (Nullable to the front for replacement with the word `Nullable` in F#)
    • add : of the first argument on method declaration lines with
which leaves me with the following to convert so far
module BillingStages =

    let loadRejectedGrid(payerId:string) Connector cn) =

        Pm.Dal.BillingStages.loadRejectedGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
            .Select(r => new BillingStageDataModel(r));


    let loadPendingGrid(payerId:string) Connector cn) =

        Pm.Dal.BillingStages.loadPendingGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
            .Select(r=> new BillingStageDataModel(r));


    let loadReviewGrid(payerId:string) Connector cn) =

        Pm.Dal.BillingStages.loadReviewGrid(payerId, SessionVariables.Instance.CurrentFacility.FacilityID, cn)
            .Select(r => new BillingStageDataModel(r));


    let loadPatientBilling(?includeThirdParty:bool) Connector cn) =

        Pm.Dal.BillingStages.loadPatientBilling(SessionVariables.Instance.CurrentFacility.FacilityID, includeThirdParty, cn).Select(bsm => new BillingStageDataModel(new Pm.Schema.BillingStageRecord(bsm.Age.ToString(), 0m, 0m, bsm.DOS ?? DateTime.Now, null, 0, bsm.FirstStatement ?? DateTime.Now, bsm.NofStatements ?? 0, bsm.PatientName, bsm.ThirdPartyPayerId ?? 0, null, null, bsm.Appointmentid ?? 0, null, null)) { PrimaryGuarantorType= bsm.AppointmentPrimaryGuarantorType });


    let loadCompleted(cn:Connector) =

        Pm.Dal.BillingStages.loadCompleted(SessionVariables.Instance.CurrentFacility.FacilityID, cn).Select(bsm => new BillingStageDataModel(new Pm.Schema.BillingStageRecord(null,bsm.ClaimAmount ?? 0, 0, bsm.DOS ?? DateTime.Now, bsm.Claimdate ?? DateTime.Now, bsm.Daysfilled ?? 0, null, 0,bsm.PatientName, 0, bsm.Claimstatus, null, bsm.Appointmentid ?? 0,null,null)));


    let loadPrepGrid(facilityId:int) Connector cn) =

        Pm.Dal.BillingStages.loadPrepClaimGrid(facilityId, cn).Select(r => new BillingStageDataModel(r));

Tuesday, February 9, 2016

Requested Post: Dev machine setup

How do I setup a machine to develop on?

Everywhere I've gone, one of my first steps is to document every single thing I'm told to do to setup the machine for development. Not a single one of the shops where did I this, was it appreciated or possibly even used as far as I can tell. Even in the many that had badly outdated instructions for new developers, I updated them to no avail or interest.

So here's my generic procedure for a machine (mostly independent of target platform/ui)
  1. Ask about getting a 2nd monitor if there isn't one.
  2. evaluate provided keyboard/mouse
  3. evaluate if using a git layer over top of the solution would be helpful
    1. branching in git is cake
    2. branching in TFS is very painful
  4. document and do all solution/job/domain specific setup
    1. ask around about pain points in setup
  5. ensure the work solution actually runs
  6. installs
    1. setup Chrome (or Firefox)
    2. install git or git-extensions (even if the shop doesn't use git)
    3. Linqpad 
      1. download (4 and 5)
      2. register it 
      3. set it to point to the script repository created in 2
    4. SublimeText
    5. Telerik JustDecompile
    6. Windows Grep - I am considering trying out this one
  7. pull down my script repository (this has all my most reusable/interesting scripting code)
  8. write some scripting code 
    1. to help verify and/or do step 3.
    2. to help with any manual work done in switching contexts (ie. Dev/QA/Prod debugging)
  9. Consider (but not necessarily do, creating a git repo over my user profile folder)
    1. this lets me watch changes to those folders for important settings or files that I might want to keep
    2. also allows settings to roam between machines/domains
  10. Run VS code metrics analysis of work solution(s) - 
    1. ask for approval to clean the methods with any of the following criteria:
      1. over 30 cyclomatic complexity
      2. under 30 maintainability
  11. evaluate build/CI process
  12. evaluate deploy process

Additional very wise steps I need to start doing:
  • Install sonar 
    • install the C# plugin
    • test run current/latest code
      • customize violation rules and re-run
      • document metrics (lines of code, number of projects, violations)
    • setup a build process that would iterate from the beginning of solution all check-ins for code trending

VS Extensions to install:
  • VsVim
  • Web Essentials
  • Visual F# Power Tools

Other tools I might install depending on platform/ui type:

Tuesday, November 17, 2015

T4 Generates my business objects for me revisited with F#

A long time ago I wrote an article about the code I was using in T4 Generates my business objects for me. Today I've rewritten the idea with F# as the target. F# projects don't support T4 so I used a C# project to generate F# code into an F# project. The parts of the generated code
  • A readonly interface
  • A read-write interface
  • An F# record type
  • An F# module for mapping code methods (with Statically Resolved Type Parameter support aka Duck Typing or Structural Typing)
  • An F# class with INotifyPropertyChanged for WPF consumption
Benefits
  • Implementing interfaces is not allowed to be implicit so I've automated that headache.
  • INotifyPropertyChanged desires magic strings (exception in the lovely new C# 6 nameof operator) so automation makes sure the strings are correct as of the last time T4 was run
  • If I pass around the read-only interface, I don't care how far down the rabbit hole of that object goes, it's immutable, no one is modifying it
  • If I pass around the read-write interface, all the consuming methods can be ignorant of concrete types
  • I'm generating Metadata from the db into the comments on the properties (tons of untapped potential here)

View the generated code and generator t4

- Generator and generated code from new T4 to F#

Things I want to add:

  • foreign key information to the auto-generated property comments
  • consider having the Read-Write interface implement the Read-Only interface
  • figure out how to update Microsoft's Type Providers to have them implement my interfaces.
  • add an option for generating Sql Sprocs that work against these types

Friday, February 20, 2015

Get Code Coverage from VS without writing automated tests

Create a batch file somewhere in your system as such:
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\vsinstr.exe" -coverage "%1"
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\VSPerfCmd.exe" /start:coverage /output:run.coverage
start "%1" /wait "%1"
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\VSPerfCmd.exe" /shutdown
notepad "run.coverage"
echo "%1"
echo "%2"

pause
Create an External Tool Entry in your Visual Studio Tools Menu.
  • Title: RunCovered

  • Command: c:\projects\config\batches\RunCovered.bat
  • Arguments
    $(TargetName)$(TargetExt) $(BinDir)
  • Initial Directory:
    $(BinDir)

replace the command with wherever your new shiny batch file lives.

Then in trigger that External Tool on the Tools Menu.

It will launch your app, and you can then click around or do whatever is needed to activate parts of your application, and the results will be saved into the same directory as your executable file as run.coverage. Open this file in your already open Visual Studio instance, or drag and drop the file from explorer into VS.

There you have your App's coverage metrics for that run.