Saturday

My 7 principles to design the architecture for a software project

My 7 principles to design the architecture for a software project.

Making Good Software

Software architecture is quite a grey area. It involves taking decisions that you are not likely to revisit in the future. These decisions usually involve frameworks, programming languages, application servers, databases, e.t.c.


Software architecture is about coming up with the foundation from where developers are going to build up the application. This also includes: development environments: (source control, building tools, IDEs…), QA environments, Continuous integration environments, etc.


Bad architectural decisions can make the development of your project a complete failure, and are the most difficult decisions to revert.


Good architecture, in the other hand, for most projects, doesn’t really bring any advantage, it only allows for its normal development. Good architecture usually remains hidden under normal circumstances.



When designing the architecture, is essential to avoid bad decisions that are going to tax your development in the future. What follows is a list of principles to help you come up with safe and scalable architectures.


1.- Start with the minimal necessary architecture.


Avoid unnecessary complexity like unnecessary new technologies or frameworks.


Any architectural element needs to have a very good reason to be used in the project. If the benefits or necessity of an architectural element can’t be proved, then that architectural element should be removed.


2.- Consider the specifics of your project: Constraints and risks.


Defining the architecture is something that has to be adapted to the constraints and risks of your specific project.


You shouldn’t aim for the same kind of architecture if it is a start-up or a project for a multi-national company. You should also consider the expertise of your team, if they are very experienced in a particular programming language/framework… you should probably use it even if it is not the one you prefer.


Risk areas, like a requirement to have some service with a high availability, are going to require additional considerations in the architecture that you need to keep in mind.


Constraints and risks are the element that are going to move you away from your comfort zone, but they need to be looked at, to make sure that if necessary, they get addressed from the architecture.



3.- Grow as you need.


Delay any architectural element as much as you can, especially if they are complex.


Sometimes requirements seems to call for complex integrations/frameworks… like rules frameworks, ESBs… for these cases, I find it better to ignore them at the beginning and try to complete the first end-to-end scenario as soon as possible. When this first scenario is completed, then grow from there, one step at a time, adding new functionality as requested by the user. This way, it will become obvious if that architectural element is really necessary, and if it is, it will also be obvious how you should integrate it with the rest of the architectural elements in your project.


4.- Deliver continuously.


Continuous delivery is the vehicle to allow you to refine your architecture as you go.


Continuous delivery is based in four principles:


Deliver soon: The purpose of delivering soon is to shorten the feedback cycles with the customer, allowing for changes in the requirements if necessary.


Deliver many times: Delivering many times guarantees that the feedback cycle is smooth.


Bug free: The code must be clean of critical bugs.



Production ready: It should be deployable at any time.


 5.- Require a customer.


Having someone acting as a customer, making decisions about priorities and signing off releases is critical for the good development of your project.


Failure to have someone representing correctly the role of the customer causes misdirection in the development and consequently causes that the final product developed won’t meet expectations.


6.- Avoid waste.


Architecture can lead to an excess production of artefacts, inexperienced architects may pretend to foresee the entire architecture of the application and have it specified in paper.


This is especially true in companies following waterfall like processes, and sometimes it cannot be avoid, forcing the architects to produce such and such document/diagram.


Excessive initial architecture/design, aka Big design upfront (BDUF), is not only bad because is wasteful, its main risk is to let the development team believe that they cannot deviate from the original specifications, making it very difficult to be adaptive to future changes.


7.- Maximise feedback and transparency



Feedback and transparency guarantees no surprises for the customer, which in turn helps building a more trustworthy and productive relationship.


Maximising the feedback and transparency are one of the ultimate goals of the development process for any project, this allows for early and informed reaction when change is necessary, whether something is going wrong, or whether the customer wants to introduce a change in the specifications.

Friday

Cache Attibute

  
using System;
using System.Reflection;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using PostSharp.Aspects;

namespace Business.Shared.Attributes
{
[Serializable]
public sealed class CacheAttribute : OnMethodBoundaryAspect
{
// This field will be set by CompileTimeInitialize and serialized at build time,
// then deserialized at runtime.
private string _methodName;

// Method executed at build time.
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
_methodName = method.DeclaringType.FullName + "." + method.Name;
}

private string GetCacheKey(object instance, Arguments arguments)
{
// If we have no argument, return just the method name so we don't uselessly allocate memory.
if (instance == null && arguments.Count == 0)
return _methodName;

// Add all arguments to the cache key. Note that generic arguments are not part of the cache
// key, so method calls that differ only by generic arguments will have conflicting cache keys.
var stringBuilder = new StringBuilder(_methodName);
stringBuilder.Append('(');
if (instance != null)
{
stringBuilder.Append(instance);
stringBuilder.Append("; ");
}

for (int i = 0; i < arguments.Count; i++)
{
stringBuilder.Append(arguments.GetArgument(i) ?? "null");
stringBuilder.Append(", ");
}

return stringBuilder.ToString();
}

// This method is executed before the execution of target methods of this aspect.
public override void OnEntry(MethodExecutionArgs args)
{
// Compute the cache key.
var cacheKey = GetCacheKey(args.Instance, args.Arguments);

// Fetch the value from the cache.
var cacheMgr = CacheFactory.GetCacheManager();
var value = cacheMgr.GetData(cacheKey);

if (value != null)
{
// The value was found in cache. Don't execute the method. Return immediately.
args.ReturnValue = value;
args.FlowBehavior = FlowBehavior.Return;
}
else
{
// The value was NOT found in cache. Continue with method execution, but store
// the cache key so that we don't have to compute it in OnSuccess.
args.MethodExecutionTag = cacheKey;
}
}

// This method is executed upon successful completion of target methods of this aspect.
public override void OnSuccess(MethodExecutionArgs args)
{
var cacheKey = (string)args.MethodExecutionTag;

var cacheMgr = CacheFactory.GetCacheManager();
cacheMgr.Add(cacheKey, args.ReturnValue);
}
}
}

test smtp server with powershell

Send-MailMessage -SMTPServer smtp.domain.com -To [email protected] -From [email protected] -Subject "This is a test email" -Body ...