I recently worked with a client who wanted a reasonably large subsystem added to Optimizely that would add automated management to their content. While cutting the code for this, I found myself writing similar code across multiple classes. I had to write it that way: 1) The client was currently on CMS11 and didn’t have access to newer language features; 2) The hierarchy of the classes prevented me from inserting a common ancestor. Thankfully, .NET has expanded the functionality of interfaces, so we can take advantage of those within Optimizely.
Original Interface
using OptimizelySDK.Entity;
namespace Teapot.Interfaces.Services
{
public interface IExperimentation
{
public OptimizelyUserContext CreateUserContext(UserAttributes userAttributes = null, EventTags eventTags = null);
public string GetUserId();
public void TrackEvent(string eventKey);
}
}
Interface with .NET Default Implementation
using OptimizelySDK.Entity;
using Perficient.Infrastructure.Interfaces.Services;
using System;
namespace Teapot.Interfaces.Services
{
public interface IExperimentation
{
public OptimizelyUserContext CreateUserContext(UserAttributes userAttributes = null, EventTags eventTags = null);
public string GetUserId(ICookieService cookieService)
{
var userId = cookieService.Get(“opti-experiment-testA”);
if (userId == null)
{
userId = Guid.NewGuid().ToString();
cookieService.Set(“opti-experiment-testA”, userId);
}
return userId;
}
public void TrackEvent(string eventKey);
}
}
Using Default Implementation
If the default implementation is called often, it makes for some ugly code. This can be remedied with a bit of syntactic sugar in the class by leveraging the interface:
{
return (this as IExperimentation).GetUserId(_cookieService);
}
Leave A Comment