Skip to content

Instantly share code, notes, and snippets.

@fnbk
Last active February 15, 2021 22:09
Show Gist options
  • Save fnbk/500d4d201e8d9de5898ead04826713ef to your computer and use it in GitHub Desktop.
Save fnbk/500d4d201e8d9de5898ead04826713ef to your computer and use it in GitHub Desktop.
#
# IOSP - Integration Operation Segregation Principle
#
Code is separated into functions of logic (operation) and non-logic (integration) - Ralf Westphal
IOSP calls for a clear separation:
* Operation: a method contains logic, transformations, control structures or API invocations
* Integration: a method only contains calls to other methods within its code base
If a method contains both logic and calls to other methods, the total behavior will be no longer clear. The instructions are blurred over a possibly very deep hierarchy. Furthermore this kind of method has a tendency to grow unlimited.
That explicit separation has many positive effects:
* Methods tend to stay short.
* More than 10, 20 or 30 lines of pure logic or exclusively method calls “feel strange”.
* As mixing is not allowed small methods will be extracted.
Operation Fuctions:
* Short logic methods are easy to test as they don’t have many dependencies.
* Short logic methods are relatively easy to understand.
* The methods name can drive the meaning.
Integration Functions:
* Short integration methods are very well understandable and reveal what happens at first glance.
* Correctness of integrations can be reviewed easily. Basically just the process order needs to be double-checked. Compiler and unit-tests of operations do the rest.
* Integrations can be nicely expanded by inserting additional method calls. Understandability stays.
#
# Integration
#
(does not contain any logic but exclusively calls other methods within its code base)
private Job CreateJob(Order order)
{
var computer = GetComputer(order.ComputerName, order.CustomerId);
computer.CustomerId = GetCustomerId(order.CustomerId, computer.CustomerId);
var serverAddress = GetServerAddress(order.ComputerName, computer.CustomerId);
var deploymentType = GetDeploymentType(order.MaterialNumber, computer.CustomerId);
var job = NewJob(order, computer, serverAddress, deploymentType, jobActions);
return job;
}
#
# Operation
#
(contains exclusively logic, transformations, control structures or API invocations)
private (string returnValue, string errorNumber) ValidateOrderPosition(OrderPosition orderPosition)
{
string returnValue = "Order accepted.";
string errorNumber = "99999";
if (string.IsNullOrWhiteSpace(orderPosition.ComputerName))
{
returnValue = "Computer name must not be empty!";
errorNumber = "2";
}
else
{
if (string.IsNullOrWhiteSpace(orderPosition.MaterialNumber))
{
returnValue = "Material number must not be empty!";
errorNumber = "3";
}
else
{
if (orderPosition.MaterialNumber.IndexOf("-") != -1)
{
returnValue = "Material number must not contain a dash!";
errorNumber = "4";
}
foreach (Site site in orderPosition.Sites)
{
returnValue = $"{returnValue}-{site.Name}"
}
}
}
return (returnValue, errorNumber);
}
#
# Dirty (mixed) Example
#
(integrations and operations are mixed)
private async Job CreateJob(order order)
{
Job job = new Job
{
ActivationTime = order.ClientLocalStartTime,
ComputerName = order.ComputerName,
orderId = order.Id,
Status = "created"
};
if (ValidateComputer(order, null, _serverSecret))
{
Computer computer = GetComputer(order.ComputerName, order.CustomerId);
string serverAddress = GetServerAddress(order.ComputerName, computer.CustomerId);
if (!string.IsNullOrWhiteSpace(serverAddress))
{
List<JobAction> actions = await CheckForLocalOsdReleaseAndCreateActionAsync(order, computer);
if (!actions.Any())
{
actions = await CheckForApplicationBundleAndCreateActionsAsync(order, computer);
}
if (!actions.Any())
{
actions = await CheckForCollectionAndCreateActionsAsync(order, computer);
}
if (!actions.Any())
{
actions = await CheckForApplicationAndCreateActionsAsync(order, computer);
}
foreach (JobAction action in actions)
{
action.SiteServer = serverAddress;
}
job.JobActions = actions;
}
else
{
job.Status = "Failed, site server not found.";
}
}
}
#
# Clean Example
#
private Job CreateJob(Order order)
{
var computer = GetComputer(order.ComputerName, order.CustomerId);
computer.CustomerId = GetCustomerId(order.CustomerId, computer.CustomerId);
var serverAddress = GetServerAddress(order.ComputerName, computer.CustomerId);
var deploymentType = GetDeploymentType(order.MaterialNumber, computer.CustomerId);
var jobActions = CreateJobActions(deploymentType, order, serverAddress, computer);
var status = "created";
Job job = new Job()
{
ActivationTime = order.ClientLocalStartTime,
ComputerName = order.ComputerName,
OrderId = order.Id,
JobActions = jobActions,
Status = status,
};
return job;
}
#
# Branching Strategies
#
* If-Else
* Local Functions (pass functions as a parameters -> callback functions)
* Try-Catch
* Monads
#
# If-Else Example
#
private Job CreateJob(order order)
{
var errorMessage = ValidateComputer(order.ComputerName);
if (errorMessage != "")
{
return new Job()
{
ActivationTime = order.ClientLocalStartTime,
ComputerName = order.ComputerName,
orderId = order.Id,
Status = errorMessage,
};
}
var computer = GetComputer(order.ComputerName, order.CustomerId);
computer.CustomerId = GetCustomerId(order.CustomerId, computer.CustomerId);
var serverAddress = GetServerAddress(order.ComputerName, computer.CustomerId);
var deploymentType = GetDeploymentType(order.MaterialNumber, computer.CustomerId);
return new Job()
{
ActivationTime = order.ClientLocalStartTime,
ComputerName = order.ComputerName,
OrderId = order.Id,
JobActions = CreateJobActions(deploymentType, order, serverAddress, computer),
Status = "created",
}
}
#
# Try-Catch Example
#
private Job CreateJob(order order)
{
Job job = new Job()
{
ActivationTime = order.ClientLocalStartTime,
ComputerName = order.ComputerName,
orderId = order.Id,
};
try // happy path
{
var computer = GetComputer(order.ComputerName, order.CustomerId);
computer.CustomerId = GetCustomerId(order.CustomerId, computer.CustomerId);
var serverAddress = GetServerAddress(order.ComputerName, computer.CustomerId);
var deploymentType = GetDeploymentType(order.MaterialNumber, computer.CustomerId);
job.JobActions = CreateJobActions(deploymentType, order, serverAddress, computer);
job.Status = "created";
}
catch (ComputerNotValid ex) // bad path
{
job.Status = "Failed, computer invalid";
}
catch (ComputerNotFound ex) // bad path
{
job.Status = "Failed, computer not found";
}
catch (NoSiteServerAddress ex) // bad path
{
job.Status = "Failed, computer has no site server address";
}
return job;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment