Pricing on Purpose – What I learned

If you find your business commoditizing its services and trying to compete on price alone then maybe it’s time to take a step back and figure out what truly differentiates you from your competition.  There’s only one “you”, so what makes “you” different in the eyes of your customers?

If your business value to your customers is not just being the lowest price service then be careful of the customer that chooses you on price alone.  Any customer making a decision to use you on price alone will easily leave you for a competitor when they in turn offer a cheaper price.

This is just 1 tidbit that I’ve picked up by reading the book Pricing on Purpose by Ronald Baker.  There’s a wealth of information in this book that can help any size business gain maximum profit by realizing the value they are providing their customers and pricing accordingly.

As a software developer I realize that the value I offer my customers is not my hands but is actually my mind.  The value that I offer my customers is not the piece of code but the outcome the customer realizes from using the piece of code.

As a business owner, I have been able to change my perception of price and value which is allowing me to change my pricing model to be value based as opposed to hourly or cost plus.

Angular Array Filter Framework

We are currently working on an Angular application that has many different types of domain specific objects all of which have a common set of base attributes, “isDeleted” and “title” to name a few.

[code language=”javascript”]
export interface EntityDomainModelBase {
code: string;
title?: string;
isDeleted?: boolean;
}
[/code]

There are a few areas within the application that will need to filter arrays of the domain specific objects by both some domain specific attributes and also by the base attributes.  A base Angular “pipe” class was created to encapsulate the plumbing of the filter and the filter logic for the common base attributes, along with the delegation to the domain specific subclass.

[code language=”javascript”]
import { PipeTransform } from ‘@angular/core’;

import { EntityDomainModelBase } from ‘./api/DomainModelBase’;

export class DomainModelArrayFilterPipeContext {
viewDeleted: boolean;
searchTerm: string;
}

export class DomainModelArrayFilterPipe<typeOfEntity extends EntityDomainModelBase>
implements PipeTransform
{
transform(entities: typeOfEntity[], ctx: DomainModelArrayFilterPipeContext) {

if (!ctx)
return entities;
if (!entities || !entities.length)
return entities;

return entities.filter((item: typeOfEntity) => {
return (ctx.viewDeleted == undefined || item.isDeleted == ctx.viewDeleted)
&& (ctx.searchTerm == undefined || ctx.searchTerm == ”
|| item.title.toLowerCase().indexOf(ctx.searchTerm.toLowerCase()) >= 0
|| this.checkTerm(item, ctx.searchTerm)
);
});
}

/*
implement in domain specific filter class to filter on domain specific attributes
*/
checkTerm(item: typeOfEntity, searchTerm: string): boolean { return true; }
}
[/code]

A domain specific subclass was then created and used like any other “@pipe” attributed class. This domain specific pipe implementation also filters through an array of persons for a specific name.

[code language=”javascript”]
@Pipe({ name: ‘domainSpecificObjectFilter’ })
export class DomainSpecificFilterPipe extends DomainModelArrayFilterPipe<SomeDomainModel> {
checkTerm(item: SomeDomainModel, searchTerm: string): boolean {
return item.persons.filter(p => p.name.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0).length > 0;
}
}
[/code]

The filter classes above are then used to filter a list of domain specific objects and draw the appropriate HTML.

[code language=”html”]
<ng-container *ngFor="let event of (events | eventsFilter:filterContext)">
[/code]

With this design any number of domain specific filtering scenarios can be addressed without having to duplicate the common argument checking and array filtering logic.

Angular Dirty Tracking of Object Graphs

I am currently working on a CRUD app in Angular and needed to implement dirty tracking of an object graph.  All the examples I have found work well on the “input” properties to a component, or for simple objects using the “KeyValueDiffer”.

I started implementing the logic based upon this post Angular Change Detection but As soon as I tried to edit a collection or property of the root object I would need to do traverse the nested objects and arrays.

I then decided to keep it simple and just compare JSON strings of the original object and any changes that occur to it during the edit cycle.  This approach would allow the user to change a property back to it’s initial state using normal editing procedures.  Editing an “input” and then just changing the text back would reset the dirty, adding a collection item then removing it after add would reset the dirty, etc.

[code language=”javascript”]
updateDirty(): boolean {

var currentJson: string = JSON.stringify(this.entity);
this.isDirty = currentJson != this.originalJson;

return this.isDirty;
}

editStart(entity: typeOfEntity) {
this.entity = entity;
this.isDirty = false;

this.originalJson = JSON.stringify(entity);
}
[/code]

Angular Constants Injected Server Side from ASP.NET CSHTML

Most answers on the internet work well for JIT compilation, refer to the stack overflow article here;  Stack Overflow Question

We are using JIT compilation for development and AOT for deployment. I couldn’t find a good way to make the standard approach work with AOT. For reference I followed the AOT cookbook here… Angular AOT cookbook.

The approach below will not work for server side rendering but should suffice for both JIT and AOT client side rendering.

1) In the razor view, _layout.cshtml for example, just put a script block and set a JSON object on the window interface. I placed this block within the “head” tag but doesn’t really matter. The values for the JSON keys can be determined by any razor syntax.

[code language=”javascript”]
window.appContext = {
userName: ‘@("test".ToUpper())’,
isAdmin: @(1 == 1 ? "true" : "false")
};
[/code]

2) Create an app context service and wire up in appropriate module and inject into components for usage, if you need help with this just comment and I’ll supply more info.

[code language=”javascript”]
import { Injectable } from ‘@angular/core’;

/*
must match definition in SCRIPT tag that is seeded from razor
*/
interface IAppContext {
userName: string;

isAdmin: boolean;
}

/*

*/
@Injectable()
export class AppContextService implements IAppContext {

userName: string;

isAdmin: boolean;

constructor() {
var appContextBootstrap: IAppContext = (<IAppContext>(<any>window).appContext);

this.userName = appContextBootstrap.userName;
this.isAdmin = appContextBootstrap.isAdmin;
}

}
[/code]

3) reference and use the app context service throughout the application.

[code language=”javascript”]
import { Component } from ‘@angular/core’;

import { AppContextService } from ‘./appContext.service’

@Component({
moduleId: module.id,
selector: ‘story-app’,
templateUrl: ‘app.component.html’
})
export class AppComponent {
AppConfig: any;
constructor(private appContext: AppContextService) { }

ngOnInit() {

alert(‘hi – ‘ + this.appContext.userName);
}
}
[/code]

Linq to SQL DBML TFS Merge Strategies

I know linq is a somewhat outdated framework but it’s super simple to use and still gets the job done for us. It’s been used for several years on our current project and we have always run into some issues when merging between 2 branches. The DBML and designer files would get all out of wack during the merge process and would require a lot of tweaking to make correct.

We created a project called “DBML Organizer” that we would run on the source .DBML and .layout files that would sort the XML alphabetically. From there the TFS merge logic would handle pretty much all cases.

The following code can be copied and pasted and used as is.

[code language=”csharp”]
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace DbmlOrganizer
{
class Program
{
static void Main(string[] args)
{
var path = args.Length > 0 ? args[0] : @"path to some folder with the .dbml files";

Directory.GetFiles(path, "*.dbml", SearchOption.TopDirectoryOnly).ToList().ForEach(f => FormatDbml(f));
Directory.GetFiles(path, "*.dbml.layout", SearchOption.TopDirectoryOnly).ToList().ForEach(f => FormatDbmlLayout(f));

Console.WriteLine("any key to continue");
Console.ReadKey();
}

private static void FormatDbmlLayout(string layoutFile)
{
var xml = XElement.Load(layoutFile);

var classShapes = (from cs in xml.Descendants("classShape")
orderby cs.Descendants("DataClassMoniker").First().Attribute("Name").Value
select cs).ToList();
classShapes.ForEach(cs => cs.Remove());

var nestedChildShapes = xml.Descendants("nestedChildShapes").FirstOrDefault();
if (nestedChildShapes == null)
return;

nestedChildShapes.Add(classShapes);

if (!File.GetAttributes(layoutFile).HasFlag(FileAttributes.ReadOnly))
{
xml.Save(layoutFile, SaveOptions.None);
Console.WriteLine("Processed Layout- " + layoutFile);
}
else
{
Console.WriteLine("Layout ignored because of read-only- " + layoutFile);
}
}

private static void FormatDbml(string dbmlFile)
{
Action<XNamespace, XElement> tableFormatter = (ns2, tableXml) => {
var type = tableXml.Descendants(ns2 + "Type").FirstOrDefault();

var columns = SortXml(ns2, tableXml, "Column", "Name").ToList();
type.Add(columns);
};

XNamespace ns = "http://schemas.microsoft.com/linqtosql/dbml/2007";

var xml = XElement.Load(dbmlFile);

var connection = xml.Descendants(ns + "Connection").FirstOrDefault();

var tables = SortXml(ns, xml, "Table", "Name").ToList();
tables.ForEach(t => tableFormatter(ns, t));

var functions = SortXml(ns, xml, "Function", "Name").ToList();

// don’t change the order of the function params, etc.
//functions.ForEach(f => FormatDbmlFunction(ns, f));

connection.AddAfterSelf(functions);
connection.AddAfterSelf(tables);

if (!File.GetAttributes(dbmlFile).HasFlag(FileAttributes.ReadOnly))
{
xml.Save(dbmlFile, SaveOptions.None);
Console.WriteLine("Processed DBML – " + dbmlFile);
}
else
{
Console.WriteLine("DBML ignored because of read-only- " + dbmlFile);
}
}

private static IEnumerable<XElement> SortXml(XNamespace ns, XElement parent, string elementName, string attributeName)
{
var elements = (from c in parent.Descendants(ns + elementName) orderby c.Attribute(attributeName).Value ascending select c).ToList();
elements.ForEach(e => e.Remove());
return elements;
}

}
}
[/code]

 

New Website

Over the past several years I have spent way too much time on trying to figure out how to build my website.  Because I’m a web developer by day I thought that’s how my site should be built.  I have tried many approaches throughout the years and was never satisfied and was never able to actually complete the project.

After several discussions with some colleagues of mine, I finally decided that the benefits of a WordPress marketing site was absolutely the best way for me to go.  Writing and sharing posts are my priority; which is why this task was taking so long.

In a single afternoon I was able to search and buy a theme, customize it to my liking, and then deploy for the world to see.  I was totally psyched to have finally achieved what I’ve been trying to build all in a single afternoon with such ease.

So, without further adieu, I finally present the official site for BaSys, Inc.   This site is hosted on Studio Express using the Digital Pro theme.

Now I can actually create the content that I have been waiting to share.

Enjoy!

Planning and Events Product

In 2017, EmpireCLS wanted to simplify the management of events. An event was a large number of people being driven to and from venues. A venue would be for as little as a single day or up to several days or weeks long. This was an extremely manual process and required many staff hours to manage and validate.

We developed the entire MVP using a “no DB” approach. In order to cut down on the friction of any type of database we used in memory repositories to track all data. A generic set of classes were used to manage the memory repository and offered simple migration to full DB support. We used domain models from the repositories as the application view of data, the repositories would then map the domain models into whatever storage we wanted; mongo, SQL, etc.

We used Typewriter to generate our client typescript code based upon the web API interface, API models, and domain models. By authoring a few templates in Typewriter we would have all of the client-side Angular HTTP services, DTO’s, and view models generated for us. This streamlined the development process immensely.

Technologies… C#, asp.net MVC, asp.net Web API, Angular, Typewriter

SQL Server Archiving Software

In 2015, EmpireCLS had a 1 Terabyte database that was difficult to manage. A restore of this database would take several hours which would not be suitable as a disaster recovery option.

We analyzed the database and usage and were able to use a custom partitioning scheme to keep rolling windows of table and index data on a monthly basis. We were able to then roll off the windows after a certain time period.

Daily backups would only occur on the active filegroups and inactive filegroups would be treated as read-only. The restore of the last active filegroup would then take minutes because it was extremely small.

Another goal of this partitioning was the need to move filegroups around the network easier and being able to restore individual filegroups without affecting disk performance. It was determined that restoring the terabyte backup would not only take a long time but would saturate the SAN that EmpireCLS was using. By only needing to restore 10GB backups these issues were removed.

An more technical explanation can be found here…SQL Server Custom Partitioning

On Demand Product

In 2016, EmpireCLS wanted to build a new product to tackle on-demand for the corporate customer. This product was to have a no-touch integration with their 400+ affiliate network and provide real-time availability of inventory through the EmpireCLS customer app.

We developed the entire MVP using a “no DB” approach. In order to cut down on the friction of any type of database we used in memory repositories to track all data. A generic set of classes were used to manage the memory repository and offered simple migration to full DB support. We used domain models from the repositories as the application view of data, the repositories would then map the domain models into whatever storage we wanted; mongo, SQL, etc.

We used Typewriter to generate our client typescript code based upon the web API interface, API models, and domain models. By authoring a few templates in Typewriter we would have all of the client-side Angular HTTP services, DTO’s, and view models generated for us. This streamlined the development process immensely.

The project was put on hold indefinitely after a simplified POC was delivered to the executive team.

Technologies… C#, asp.net MVC, asp.net Web API, AngularJS, Typewriter

Logical Locking Software

In 2015, EmpireCLS needed a way to alleviate the physical locking issues that they were facing when users edited a reservation. The legacy Linux system was using a physical database lock that would stay active when a user attempted to edit a reservation, this lock would remain in effect until the user explicitly released it or their process was killed by an admin. Because killing the process became the normal procedure the user that had the lock would lose any in process edits. This problem directly impacted daily operations, automated booking feeds, and the IT staff.

We built a cross platform logical locking framework that would enforce the same edit semantics that the EmpireCLS staff had grown accustomed to but would allow supervisors to release locks without the need of killing a process and losing the in process changes for a user.

This implementation required both a Linux and Windows code base so we used C# / Mono to create the cross platform libraries.

Technologies… C#, C, Linux, asp.net, Mono