Ben Keeping
Friday, 12 July 2013
??? Agile ???
I've been trying to do Agile for as long as I can remember. OK, the last 7 years, but that's like a long time to me.
My gut feelings are these:
- Books are great. read them. Absorb them. I've got a shedload of books on 'Agile' and I've read about 2% of them.
- Books/courses are shite when compared to sitting next to someone who has been there, done that. Why? Because real world problems are not the problems in the book. The guy next to you can help you with your problem today.
- If you're working for a company that says 'I want us to go Agile' ... it'll probably fail. If any of these apply, it will defintely fail:
- You have a PM that has MS Project
- You have a PM that talks to you in terms of 'resource available'
- You have a PM
- You don't talk to the client daily (be that verbally, through emai, skype etc)
- You have a company that deals with its client through legal contracts that specify deliverables on specific dates
- You work in an environment where every system change is negotiated through email / change requests / workflows
- ... and a lot more
Now that's a big list.
And most companies will be able to tick a box there.
You, as a developer, can make you're life easier, and more enjoyable by driving agile techniques within your team, and within those constraints, but it ain't agile. Its partial-agile.
And for a long time its the most I could have. And that was cool. In itself.
But, the last three months, I've been working on a pretty shit-hot team, with an amazing client.
We do this :
We use a board. (AgileZen, Pivotal, Trello). They raise issues/features. They prioritise them on a daily basis (ie when they add something).
We communicate mainly via email(rare) and the board (They are several timezones away from us - YES- remote !) and a chat client (hipchat).
We do the features/issues. The features/issues are so small that each team member pushes 4 or 5 a day.
Small changes == small bugs == small signoff.
Every time we push to master, it goes live (auto-magically).
Yes.
Live.
No getout.
That's it.
If you can get to a place where you have small features, with daily contact with your client, and you push code live 30 times a day - you'll be happy.
You won't care about whether or not you are 'Agile' or not - you will just have a decent workflow. Which builds trust. Which minimises deadline requests. Which makes for happy clients, and happy developers.
It's not for everyone, I realise, but its the most 'Agile' I've ever felt.
Companies that say 'We can't automate our deploy', or 'The developers can't talk to the client' or 'We can't deploy live' or 'We can't break down features that small' .... they don't want to be agile. They want to think they can agile.
3 things you need:
- Automated deploy, every time you commit (its important)
- Small feautures (you can still have epics)
- Access to the client
That's it kids !
And remember - no book or course can replace the experience of your own failure.
Happy coding peeps !
Thursday, 7 June 2012
Stop ! Collaborate & Listen
I'm on a contract with a team where the front-end (an ASP.NET MVC) site is being written by an external company (we'll call them Websites Inc).
Webites Inc don't want to collaborate. They won't come into our offices (not even on the last week of a deliverable), they won't give us skype access or phone numbers of their developers.
I'm a contractor - I can't force my host company to get these guys to collaborate - to put the proverbial boot down as it were. To make them understand why collaboration is *so* important.
Ouch.
So I'm looking at Website Inc's code, and its not the best to be fair.
They're making some basic coding mistakes.
They're repeating themselves in code.
They're peppering their code with try/catch blocks.
They're returning different views from actions depending on whats happening.
They're wrapping stuff unnecessarily.
They're building in their own authenitcation layer (even though our api deals with it)
They're not naming controllers after resources
They're using controllers as a dumping ground for actions
etc etc etc
With a few friendly chats and discussions we could sort this stuff out really quickly.
But they won't collaborate.
So whats a chap to do ?
Well, I refactored it.
If someone refactored my code without discussing it I'd be pretty narked. I'd be pissed that they had not discussed why it was done, or why I was breaking MVC etc.
If we'd collaborated, it could have been a learning experience for both of us.
And that's the point - collaboration between software teams, and within software teams leads to cleaner, more maintainable code. Both sides learn something.
The way it is right now - no collaboration - can only lead to hurt feelings, and ruined relationships.
Its 2012. When will companies realise that collaboration & sharing leads to better software?
Monday, 7 May 2012
What is a software architect ?
I currently contracting at the moment, as a 'developer' or 'programmer'.
I applied for a role the other day that I felt was entirely within my skillset - agile, asp.net mvc, tdd.
When I called the recruitment agent, he questioned whether or not I had any recent hands-on development experience.
Which I thought was weird, because I've had over 10 years relentless development experience.
After I'd spoken to him, I realised why he'd asked - its because the last two roles on my CV had the word 'Architect' in them.
Speaking to other people, software 'architects' seem to be percieved often as people that don't code, and design systems from above - think word documents, visio diagrams and the like.
Which is weird, because I'd always thought as a 'architect' as being something different :
1) They have an overall say on the software architecture (when the team has differing opinions and someone has to make a call)
2) They involve themselves on a day-to-day basis with coding (ie pushing features and pairing)
3) They act as mentors to other devs on the team that need help
4) They act as a facilitator to external pressures on the team (ie a sh*t umbrella)
5) They act as a mediator within the team for discussions about architecture on the team
But this role, how I see an 'architect', means having a team that is :
1) Capable of pro-active discussions about software & design2) Capable of decision making, for the benefit of the team and project
3) Capable of accepting responsibility for the software (and hardware) architecture
4) Capable of being responsible for the delivery of the software
Which I guess, is where me and the recruitment agent left each other on how we define 'architect' within a company.
Being a 'software architect' was one of the hardest jobs I ever did - and also one of the most rewarding. But it certainly meant I still remember how to code.
Thursday, 19 April 2012
ASP.NET MVC4 Web API / appharbor / IIS / http status codes
You're being a good RESTful developer, and using http status codes correctly.
You're sending back 400 BadRequest when validating user input, you're using 403 when somebody does something their not allowed to do, and 401 to issue authentication required.
You're sending nice friendly, informative error messages for those 4xx responses.
And then you deploy to appharbor, which is running on IIS 7, and you're app stops sending back those nice formatted error messages.
Weird, you think ... works locally !
You spend hours trying to figure it out. And then you finally ask @appharbor, and they let you know about a crazy HttpContext setting.
What it is, is IIS7 being mental. And stomping on your response body.
What you need to do is for every response that is not 2xx or 3xx, you need to do this :
HttpContext.Current.Response.TrySkipIisCustomErrors = true;
*** UPDATE ***
Khalid (see comments below) has pointed out that you can do this in Web.config instead, which is a better. Cheers fella ! See http://blog.aquabirdconsulting.com/?p=359
Example:
<system.webserver>
<httpErrors existingResponse="PassThrough"/>
</system.webserver>
*** END UPDATE ***
But where to put it ? Well, whereever works for you.
I follow this pattern in all my controllers :
public class ExampleController : ApiController
{
public HttpResponseMessage Delete(long id)
{
return this.Try(() =>
{
_organisationService.Delete(id);
return 204.Response();
});
}
}
Where 'Try' is a method that catches known exceptions (ie can't find an entity, input is invalid etc etc)
public static HttpResponseMessage Try(this ApiController controller, Func<HttpResponseMessage> operation)
{
try
{
return operation.Invoke();
}
catch (EntityNotFoundException e)
{
return 404.Response(MessageResponse.From(e.Message));
}
catch (ForbiddenException e)
{
return 403.Response(MessageResponse.From(e.Message));
}
catch(PermissionsException e)
{
return 403.Response(MessageResponse.From(e.Message));
}
catch (ValidationException e)
{
if (e.HasMultipleErrors())
{
return 400.Response(e.Errors);
}
return 400.Response(MessageResponse.From(e.Message));
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
return 500.Response(MessageResponse.From(e.ToString()));
}
}
and I have this extension method, where I put in the magic IIS hack :
public static HttpResponseMessage<T> Response<T>(this int code, T content)
{
HttpContext.Current.Response.TrySkipIisCustomErrors = true;
switch (code)
{
case 200:
return new HttpResponseMessage<T>(content, HttpStatusCode.OK);
case 201:
return new HttpResponseMessage<T>(content, HttpStatusCode.Created);
case 204:
return new HttpResponseMessage<T>(content, HttpStatusCode.NoContent);
case 400:
return new HttpResponseMessage<T>(content, HttpStatusCode.BadRequest);
case 401:
return new HttpResponseMessage<T>(content, HttpStatusCode.Unauthorized);
case 403:
return new HttpResponseMessage<T>(content, HttpStatusCode.Forbidden);
case 404:
return new HttpResponseMessage<T>(content, HttpStatusCode.NotFound);
case 500:
return new HttpResponseMessage<T>(content, HttpStatusCode.InternalServerError);
default:
throw new Exception(string.Format("Do not understand http code {0}", code));
}
}
Thursday, 22 March 2012
Cloud Foundry / Iron Foundry app & service limits
If you're running Cloud Foundry (or Iron Foundry) locally (ie the "Micro" or MCF VMs), and you get this error when provisioning a service or application :
Error 504: Too many Services provisioned: 4, you're allowed: 4
Or
Error 601: Too many applications: 4, you're allowed: 4
Then you need to alter the config on your MCF instance.
This can be done by editing /var/vcap/jobs/cloud_controller/config/cloud_controller.yml
and altering the default values displayed below :
admin_account_capacity:
memory: 1024
app_uris: 32
services: 4
apps: 4
default_account_capacity:
memory: 512
app_uris: 8
services: 4
apps: 4
Tuesday, 13 March 2012
ASP.NET MVC4 Web API
I'm not going to do full comparison, because I've not used web api in anger yet, and I don't want to be arguing for or against either frameworks, but here is some info on how to do some of the stuff you're going to want to know if considering a move from OpenRasta to ASP.NET MVC4's Web API (or perhaps just starting out in the resful framework space and have chosen Web API).
Pipelines
One thing I love about OpenRasta is the pipeline stuff - very easy.
But I have to say, Web API's making it pretty easy too ...
Note I'm injecting in a service ... its as easy as it should be
public class MyPipelineInterceptor : System.Net.Http.MessageProcessingHandler
{
readonly ISomeService _service;
public MyPipelineInterceptor(ISomeService service)
{
_service = service;
}
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
{
return response;
}
}
Dependancy Resolution
Again pretty darned easy, and I have to say (sorry Seb), easier to inject your favourite DI framework than OpenRasta 2's.
This is using Structuremap :
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
t =>
{
try
{
return ObjectFactory.GetInstance(t);
}
catch (Exception)
{
return null;
}
},
t =>
{
try
{
return ObjectFactory.GetAllInstances(t).Cast<object>();
}
catch (Exception)
{
return new List<object>();
}
}
);
Pretty easy to configure :
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyPipelineInterceptor(ObjectFactory.GetInstance<ISomeService>()));
Handlers
Handlers are minimal, and feel a lot like OpenRasta's.
Instead of OperationResult you have HttpResponseMessage.
The routing is handled automagically via a single call
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
public class ValuesHandler: ApiController
{
readonly ISomeService _someService;
public ValuesHandler(ISomeService someService)
{
_someService = someService;
}
public HttpResponseMessage Get()
{
return new HttpResponseMessage(new[] {"value1", "value2"}, HttpStatusCode.OK);
}
public HttpResponseMessage Get(int id)
{
return new HttpResponseMessage("value1", HttpStatusCode.OK);
}
public HttpResponseMessage Post(string value)
{
return new HttpResponseMessage(HttpStatusCode.Created);
}
public HttpResponseMessage Put(int id, string value)
{
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
public HttpResponseMessage Delete(int id)
{
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
}
Pipeline injection
So one of the patterns we use (see https://github.com/agilex/agilex.persistence.openrasta) is injecting a repository into OpenRasta's CommunicationContext's PipelineData before any request, and disposing it after every request (kinda AOP style).
Chucking *global* resources into your pipeline is easy in Web API too ... in your interceptor (the first class in this post) :
request.Properties.Add("thing", new MyThing());
And then you can just access the properties in your handler/controller too, or on the response method on your pipeline interceptor.
So overall, pretty impressive so far.
As I said, I've not used it in anger yet, so not sure how it stacks up with trickier usuage (like complex model binding, or one-to-many route relationships - ie /users/123/orders), but to be fair, considering the model binding stuff is from asp.net mvc, and the routing is pretty similar, I'm sure it will be fine.
Sunday, 4 March 2012
Alternative to MVC Routing
It's on Nuget as "Mvc.Routing"
So instead of registering routes like this :
routes.MapRoute(
"foobar route",
"foo/{someParam}/bar",
new { controller = "Foo", action = "Bar" }
);
You can just call :
Routing.Register(typeof(MvcApplication).Assembly);
And then tag your controllers :
public class FooController : Controller
{
[Get("foo/{someParam}/bar")]
public ActionResult Bar(string someParam) {
// whatever
}
}
There are attributes for Get, Post, Put, Patch and Delete
The attributes behave like the normal HttpGet, HttpPost (etc) attributes - ie if you tag an action as Get(), then you can't post to it
You can use them in conjunction with the normal Http* attributes, for example :
public class FooController : Controller
{
[Get("foo/new")]
public ActionResult New() {
// whatever
}
[HttpPost]
public ActionResult Create(Bar bar) {
// whatever
}
}
If you don't use the HttpGet / HttpPost attributes for your actions, you can still register routes like so :
public class FooController : Controller
{
[Route("foo/{id}")]
public ActionResult View(Guid id) {
// whatever
}
[Route("foos")]
public ActionResult List() {
// whatever
}
}
Testing your routes is also pretty simple, below is an example using Mspec (Machine.Specifications) :
[Subject(typeof(TestController), "Given a test controller has marked the Index method as Get")]
public class when_registering_routes : register_route_context
{
Establish context = () =>
{
theExpectedRouteUrl = "all/routes/are/mine";
theExpectedActionName = "Index";
theExpectedControllerName = "Test";
};
Because of = () =>
{
Routing.Register(typeof(TestController).Assembly);
theRoute =
RouteTable.Routes.Select(x => x as Route).Where(x => x.Url == theExpectedRouteUrl).FirstOrDefault();
};
Behaves_likeroute_should_be_registered;
}
See the project specs here for more examples : https://github.com/benjaminkeeping/Mvc.Routing/tree/master/src/Mvc.Routing.Specs/registration