CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Ian Cooper [MVP]

  • Learning On A Project

     There has been a fair amount of activity in the blogsphere to Roy's original post about increasing TDD adoption. Roy updates some of the reaction here and here. Udi comments on my reaction that the most important thing is to being writing tests and then learn how to write them better. Udi questions whether it is right for us to expect customers to allow us to learn on their time. And Casey Charlton makes a similar point in comments on Tim's blog. There has been a fair amount of discussion as to how we teach TDD over at the TDD mailing list too.

    I have not changed my position in response to these comments, but I did want to talk a little about change and learning.

    Embrace Change

    The XP strapline was 'Embrace Change' and it remains, to me, at the core of key alt.net ideals like Continuous Improvement. Our field is contantly changing. New technologies, practices, and methodologies emerge with alarming frequency. Sometimes the pace of new developments can seem frightening. We can have two reactions to such change: resist it or embrace it. The danger with resisting is that we stagnate, stuck in the comfort zone of what we know. I see a lot of resistance to ideas like TDD simply because people do not feel comfortable with changing practices. Alt.Net is for me about the idea of embracing change, of continuous improvement. Embracing change for its own sake has its own dangers of course. The urge to try the latest thing can lead us into peril if we fail to critically evaluate its value to us.

    My experience is that change usually occurs when the pain of existing practice becomes so great that it pushes aside the resistance to change. There must be a better way, we think. My experience of test-first development is that the pain of the test and debug phase at the end of waterfall projects pushes people to look for solutions. Solving issues here improves delivery, reduces cost, and increases customer satisfaction. As the cost of that phase rises and projects slip due to the uknowable length of making the project fit for release, the customer begins to feel the pain of older approaches. The promise of test-first approaches, building quality into the manafacturing process instead of in a seperate QA step, becomes attractive enough that people trial the new ideas. There is business value in agile processes, which can be demonstrated by solving the typical pain problems that organizations not using agile development practices have.

    My point on the most important step being to start testing, over worrying about following best testing practice is that the value of building quality in can be quickly seen. Once a team realizes that value in test first approaches they will buy in to learning how to do them better. But its that first buy in that counts. People worry about whether test-first is about testing or design. It's simply about quality - which includes both of those and more.

    Of course there is a leap of faith on the first project. My experience is of pilot projects which trial these new approaches and compare results against existing processes to persuade key decision makers of their value. Often we try new techniques or technologies on lower-profile or even internal to IT projects to assess their value over high risk high profile work. This is not always the case. Once we buy into newer technologies or practices we may choose to up our game and improve our use of them on high profile projects because people have the motivation on them to try something new.

    While I agree with the idea that developers have an obligation to their own professional development, there is always a difference between learning a new skill  and improving our ability with that skill through practice. I can read volumes on TDD best practices, but it is only for trying it out in anger, at some scale, that I can master it. For many, it is only practice that provides the encouragement to learn more. This kind of practice always has to be on the job, in this and in every other field. You can do all the book learning and training you want - ultimately you have to practice to master a skill. We train our developers when we want them to work with new third-party products that provide us with document management, rules, feeds etc. Why would we not want to train them in better practices? I have and continue to give training at my current organization and would expect to continue to do so. I have received training from my current organization. This is occurs in all professions.

     At a discussion in our recent London altnetconf Alan Dean pointed to the observation that agile practices often depend on agents of change, and they can ebb and flow within those organizations with the arrival and departure of such agents. The key to change is often individuals who learn and practice new techniques, or who bring experience of those techniques from other organizations. I love working with new people who have strong agile backgrounds because they bring with them fresh ideas and new perspectives to challenge me.

    But to gain from thier experience we have to accept that we will need people to accept change and work in new ways. And they may not get it right at first. There will be a learning curve.That for me is why reflection workshops/sprint reviews are so important. They create the discipline of examining our use of practices and techniques and encourage us to get better at them. So the team that picks up TDD and just does it has plenty of opportunity to see the pain of talking to the Db or touching the file system, look for solutions and correct their course. Will there be additional cost to learn. Of course! But the cost of not learning is far higher.

     

     

  • Learning and craftsmanship

    Roy has a pretty thoughful post on the barrier to entry for most developers with Test-Driven Development. I hope I am not doing Roy a disservice by summarizing it as: we have made TDD unapproachable to many by making it more and more complex.

    I would agree with many of the points that Roy makes about returning to the basics when approaching TDD. I still find Kent Beck's book captues the essence of TDD. It also contain wisdom that when I return to it makes me realize that much of what I assumed were new ideas were all there in Kent's original book on the topic. I like the clarity of the Four-Phase Test and its cousin Act/Arrange/Assert. I agree that we should prefer testing the state of the class we are testing over its behavior.

    But I do not think that another naming taxonomy for techniques to swap out depended-on components is going to do anything more than muddy the waters. Maybe you don't like Gerard's Test Doubles but they do catalogue a lot of what is out there in the wild. The naming conventions behind test doubles are not the issue most people encounter. The problem they hit is that in reality there are hard-to-test areas and people look for help in overcoming them.

    After I learnt TDD I wrote, by my current standards, poor unit tests. I wrote tests that touched the Database. I wrote tests that touched the file system and called across the network. I wrote tests that checked private methods. I wrote tests that shared fixture or had dependencies between them. I put mocks everywhere, replacing every depended upon component.  And I suffered with fragility, slowness, an unmaintainable code for my mistakes. But I needed to make those mistakes. Because it was only by making the mistake that I could understand the need for and value of a solution.

    We live in a fairly lucky time for software craftsmanship. The wisdom of the masters of our trade is published in accessible formats for all of us to read. So when we need to learn at the feet of the masters we do not have to look for opportunities to work alongside them, we can find their wisdom in the form of patterns, principles, and practices published in books or on the web. I started my career in a period where this kind of knowledge was much less accessible, and the only way to discover a better solution was to find one yourself or work with someone who knew of a different approach. We live in fortunate times. But the ease with which we can find best practice often masks the fact that understanding the value of that advice usually requires us to have experienced the pain beforehand.

    When I teach TDD one point I try to flag is that the first step is to start writing tests. Not to worry about how good those tests are, but to start writing tests. Once you are writing tests and experiencing the pain that comes from poor tests, you will appreciate the value of some of the best practices out there. Because then you understand them as solutions to problems not just more complexity. But first, just start writing tests. The difficulty with the software community is that experienced practitioners can overwhelm newbies by flooding them with information on 'how to do it right'. The problem is that the most important step is not doing it right, but doing it at all. As a result newbies suffer from the kind of analysis paralysis that BDUF usually brings: should I be using a fake here, should I be using a mock? Instead we need to embrace the TDD solution to analysis paralysis of making it work and then making it right. Get your code under test, then worry about refactoring your test code. Over time you will learn enough to write better test code first time around. Your ability to see what Kent calls the 'obvious implementation' widens to include these new techniques.

    We still need to do this today. On my current project we are still looking at the best way to test our controllers. Our existing test code works but is fragile and we need to review where we check the controller's action by checking state and where we use mocks to check the interaction with the domain because the controller has no state that we can check. Right now, in some places, we use the state of the domain to check the controller's action, and it is hurting us with test fragility as the test depends on too much. So we need to make it right. And in doing so we will increase our understanding of when to use mocks.

    There is no shame in making a mistake, only in not from learning from it.

    Don't be put off by patterns and practices and assume you have to master all of them before you can begin work. They are there to help you when you need a solution.

    Make it work, then make it right.

     

     

     

     

     

  • AltNetConf Reflections

    With the smoke clearing from the altnetconf this weekend I thought I might reflect a little on the ambience.

    Once again I was really pleased with how the Open Space format turned out. We find that we do not get any presentations as a result. Instead we just get conversations between interested parties. There is a lot more active participation as a result. A lot more voices.

    I was impressed by the open mindedness that everyone displayed. At a simple level I was impressed by how open newbies were to the Open Spaces process. But more than that I was impressed by how willing everyone was to listen, and to share both their pain as well as their triumphs. There was little chest-thumping 'we are alt.net because we do this' and a lot more 'how do you guys make x work'. I picked up valuable advice around acceptance testing following some openess on my part around the issues we had. There was a lot of feedback from people saying that they found a lot of value in the openess of that conversation, the understanding that other people struggled at times, that everyone was learning to some extent. Gojko used the phrase 'group therapy', which was a good summary about how much of this felt.

    While a lot of people were using the usual alt.net suspects in terms of tools and frameworks (Castle Stack, JQuery Resharper,Cruise Control - or increasingly Team City) there was a lot more emphasis on principles and practices than tools.

    My biggest concern for alt.net remains that it becomes the new orthodoxy leading to alt.alt.net. The open minded nature of the conversation this weekend was encouraging in that regard. People seemed keen to improve and to learn, not just play the same old tunes. There has been some traffic on this site of late about what alt.net means. I still believe that the XP idea of 'Embrace Change' remains at the heart of alt.net.

     

  • Alt.Net Conference London and DDD 7 voting

    It never rains conferences but it pours.

    Tonight and tomorrow is the 2nd London Alt.Net conference. It has been just over 6 months since the last one, so it will be interesting to see where everyone is this time around. I have no idea what will come up, and I am really interested to get a feel for what memes are current. I'm guessing there will be a lot of talk about architectures using MVC and JQuery. We are using that strategy (Monorail instead of ASP.NET MVC) and Jeremy has posted in a similar direction, so I'm guessing that may be a poster child. But I expect to be suprised.

    In addition voting is now up for Developer day at the end of November, so folks can choose the agenda for that one. We opened the session submission for a lot longer this time around, and as a result there are an embarrisingly large number of sessions available. There are a healthy range of Alt.Net topics in the list. As we focus on UK resident speakers, this speaks volumes about a healthy UK community. If you are planning on attending, vote now for the session that you would like to see.

     

     

     

     

  • TDD and Hard To Test Areas, Part 2

    It's been a while. I have been heads down on a new project (more about that some other time), and have not got around to posting. Without further ado here is the follow up post to TDD and Hart To Test Areas, Part 1

    Depend upon Abstractions

    The Gang of Four’s first principle is to program against abstractions not implementations. If we use abstractions then we can solve the hard-to-test problem by implementing the abstraction in terms of the hard-to-test dependency in production, but with a simple-to-test dependency in test.  So we could use an IDatabase to abstract out our interaction with the Db, using concrete Ado.Net classes in production, but replace it with an in-memory collection for testing. Jeremy Miller summarizes this approach as ‘isolate the ugly stuff’.

    We need to show some rationality here. No one wants IString, everyone wants IDatabase, and we probably don’t need an ICustomer, but we might. The advantage of TDD is in flushing out where ICustomer is useful by exercising the SUT.  So when designing for testability we need to think about which dependencies we want to allow to be concrete, and which won’t don’t. Different schools of programming make different value judgments here. Classicist approaches tend to avoid replacing all dependencies, focusing instead on ones that are needful to support extensibility and layering.

    Design principles should help us identify when to use interfaces and these tend provide the opportunities we need to use abstractions to isolate hard-to-test code.

    Layers

    A layered architecture also creates a need for abstractions. While the layers must communicate, like a layer cake higher lays may depend on lower-layers but not vice-versa. To effect this, higher layers in our architecture should depend on an abstraction exposed by the lower layer, not a concrete type. The two layers can communicate via the agreed contract, but the higher layer has no dependency on the lower layer. Robert Martin's Dependency Inversion Principle states that High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

    This dovetails with hard-to-test areas as layer boundaries often co-inside with hard-to-test areas such as the UI or access to external systems. So using abstractions when we layer helps us to achieve testability. To ensure cohesion we often talk to a façade when we cross a layer boundary, which hides the complexity of the other layer, and this again simplifies testing, by removing the need to create the objects that implement the façade as part of our test setup.

    Open-Closed Principle

    In Agile Principles, Patterns, and Practices in C# Robert Martin describes the Open-Closed Principle as “Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.

    To achieve this ‘impossible thing before breakfast’ we use polymorphism. By creating an abstraction (either explicitly by using an interface or abstract base class, or implicitly by marking methods as virtual), we both define a contract allows us to define how we interact with that type - it is closed for modification – but allows many concrete implementations of that type –  we are open for extension. Note that an abstract type

    Seams

    The extension points provided by abstractions are ideal for testing as they allow us to replace depended upon components for testing. Michael Feathers calls these points seams: A seam is a place where you can alter behavior in your program without editing in that place. A virtual method can be especially useful in legacy code to create a point of extensibility to test code, where we cannot reasonably extract or introduce an interface to allow us to do so. 

    Test Doubles

    The concept of replacing a hard-to-test implementation with an easier to test one was originally called mocking. This term has become overloaded so Gerard Meszaros has suggested replacing it with the term Test Double of which a Mock is only one category. The term Test Double is meant to convey the idea of the Stunt Double who replaces the actor for dangerous scenes. There are two different scenarios in which we want to use a Test Double.

    • Where we need to control the inputs into a SUT, but there is no observation point for us to do so. For example, if we access a repository in our SUT to return an entity from the Db, such as a Customer, so that we can retrieve some value from the Customer, we need to have some way of controlling what is returned from our repository as that forms an input into the SUT.
    • Where we need to monitor the outputs from a SUT, but there is no observation point for us to do so. For example if we are calling an external web service from our SUT then we want to monitor the arguments sent to that service, but we don’t want to actually make the call.

    Working with Indirect Inputs

    Controlling the inputs from the Depended On Component (DOC) to the System Under Test (SUT) is needed when because we want to control the flow of execution within the SUT, but we do not care about the outputs to that DOC. We may want to control execution to allow the ‘happy path’ but we might want to control execution to test the error path too, by providing appropriate input.

    The need to control indirect inputs occurs because where we have difficulty setting up the values returned by the DOC to the SUT. Often this occurs because the DOC is in hard-to-test area (Db, file system, across network or process/AppDomain boundary). Such a DOC should generally be represented by an abstraction – depend upon abstractions – we have seam for our test in replacing the ‘ugly stuff’ in the DOC with a test double.

    There are two patterns for replacing a DOC when we need to work with indirect input: stub and fake

    Stub

    A stub is a light-weight implementation of an interface. With a stub we just want it to return some values in response to a method call or property access on the DOC that allows the method on the SUT to continue processing. A lot of ‘mocking’ frameworks now have first class support for stubs.

    In the following example an Insurance Product is our SUT which uses the DOC of a rating service and asks the DOC for the version of the rating plan that is in force. Here we are using Rhino Mocks support for automatically generating a stub.

        [TestClass]

        public class Using_A_Stub_To_Replace_A_Depended_Upon_Component

        {

            public IRatingService ratingService;

            [TestInitialize]

            public void Should_Use_A_Stub_To_Replace_Rating_Service()

            {

                ratingService = MockRepository.GenerateStub<IRatingService>();

            }

     

            [TestMethod]

            public void Should_Return_The_Version_Of_The_Product_Being_Used()

            {

                //setup

                Product product = new Product(ratingService);

                const int RATING_PLAN_VERSION = 5;

                ratingService.RatingPlanVersion = RATING_PLAN_VERSION;

     

                //exercise

                int ratingPlanVersion = product.GetRatingPlanVersion();

     

                //verify

                Assert.AreEqual(RATING_PLAN_VERSION, ratingPlanVersion, "Expected the rating plan to be the one from the rating service");

            }

        }

        public class Product

        {

            public IRatingService ratingService;

            public Product()

            {

                ratingService = null;

            }

            public Product(IRatingService ratingService)

            {

               this.ratingService = ratingService;

            }

            public int GetRatingPlanVersion()

            {

               return ratingService.RatingPlanVersion;

            }

        }

    We use a test stub where we need to control the indirect inputs from a DOC to the SUT, but we do not need to verify the indirect outputs. A stub can be useful to force execution of certain paths in the SUT, by returning values that direct the SUT down that path. This can be useful for error testing.

    Fake

    A stub returns a value to the SUT from the DOC, but cannot stand in place of the DOC. It is often incomplete and usable only in the context it was set up for. A fake is in contrast is a lightweight version of the DOC. It behaves in a similar fashion to the original. We commonly use a fake where we have multiple interactions with the DOC in the SUT i.e. load and retrieve or because we need a test double across a number of test fixtures and we want to remove duplicate stubs. Fake or in-memory database and fake web service are common uses.

    In this example we want to replace a service that we depend upon that manages endorsements, with a fake. Whereas the stub is dumb the fake has the semantic of the DOC. The FindEndorsements method on the fake loops through its collection of endorsements and returns those that match the required type. However, while our production implementation might source its list of endorsements from a Db, our fake just uses an in-memory collection. This isolates us from an y Db issues like shared fixture or slow tests.

        [TestClass]

        public class Using_A_Fake_To_Replace_A_Depended_Upon_Conponent

        {

            IEndorsementService endorsementService;

           

            [TestInitialize]

            public void Create_A_Fake_For_The_Endorsement_Service()

            {

                endorsementService = new FakeEndorsementService();

            }

            [TestMethod]

            public void Should_Return_Count_Of_Mandatory_Endorsements()

            {

               //setup

                var product = new Product(endorsementService);

                const int NO_OF_MANDATORY_ENDORSEMENTS = 12;

                endorsementService.Endorsements.AddRange(CreateMandatoryEndorsementList(NO_OF_MANDATORY_ENDORSEMENTS));

                const int NO_OF_OPTIONAL_ENDORSEMENTS = 2;

                endorsementService.Endorsements.AddRange(CreateOptionalEndorsementList(NO_OF_OPTIONAL_ENDORSEMENTS));

     

               //exercise

                var mandatoryEndorsements = product.FindMandatoryEndorsements();

     

                //verify

                Assert.AreEqual(12, mandatoryEndorsements.Count, "Expected the number of mandatory endorsements to equal those added") ;

            }

            private List<Endorsement> CreateEndorsementList(int noOfEndorsements, EndorsementType type)

            {

                List<Endorsement> endorsements = new List<Endorsement>();

                for (int i = 0; i < noOfEndorsements; i++)

                {

                    endorsements.Add(new Endorsement(type));

                }

                return endorsements;

            }

            private List<Endorsement> CreateMandatoryEndorsementList(int noOfEndorsements)

            {

                return CreateEndorsementList(noOfEndorsements, EndorsementType.Mandatory);

            }

            private IEnumerable<Endorsement> CreateOptionalEndorsementList(int noOfEndorsements)

            {

                return CreateEndorsementList(noOfEndorsements, EndorsementType.Optional);

            }

    }

     

    public class Product

    {

            public IEndorsementService endorsementService;

            int productId;

            public IRatingService ratingService;

     

            public Product()

            {

                ratingService = null;

            }

     

            public Product(IRatingService ratingService)

            {

               this.ratingService = ratingService;

            }

     

            public Product(IEndorsementService endorsementService)

            {

                this.endorsementService = endorsementService;

            }

     

            public List<Endorsement> FindMandatoryEndorsements()

            {

                return endorsementService.FindEndorsements(productId, EndorsementType.Mandatory);

            }

     

            public int GetRatingPlanVersion()

            {

               return ratingService.RatingPlanVersion;

            }

     }

        public class FakeEndorsementService : IEndorsementService

        {

            private List<Endorsement> endorsements;

            public List<Endorsement> Endorsements

            {

                get

                {

                    return endorsements;

                }

                set

                {

                    endorsements = value;

                }

            }

     

            public List<Endorsement> FindEndorsements(int productId, EndorsementType endorsementType)

            {

                List<Endorsement> matchingEndorsements = new List<Endorsement>();

                foreach (Endorsement endorsement in endorsements)

                {

                    if (endorsement.Type == endorsementType)

                        matchingEndorsements.Add(endorsement);

                }

                return matchingEndorsements;

            }

         }

     

    Checking on Indirect Outputs

    We need to check outputs where what we send to the DOC needs to be tested. Usually this occurs because we have no means to retrieve the message that was sent to the DOC by the SUT in the verification phase of our test, but need to verify that message to ensure that our code works correctly. In other words we are not testing a change in state to our SUT, but a message sent to a DOC.

    When we need to record the messages from the SUT to the DOC there are two options: a spy and a mock.

    Spy

    A spy allows us to record the changed state of the DOC and then use an assertion to confirm that state within our test.

    As such it dovetails well with the normal test model. A spy is especially valuable where we do cannot predict all of the values passed to the DOC ahead of time, and instead need to confirm them, often against the state of the SUT when the test has finished exercising the code.

    A self-shunt can be a quick way to implement a spy. The test fixture implements the interface for the DOC and records any interactions in fields on the class. Confirmation then involves testing the fields. Be aware that shared fixture state means that you need to use an explicit setup to clear that shared state if more than one test uses the same fixture.

    In the following test we check the document job passed to the document service when we bind a document. Within the demo we are just checking for the existence of the job, but in a real test we could examine the job to determine if it met our expectations of what should be generated.

        [TestClass]

        public class Use_A_Test_Spy_To_Replace_A_DOC : IDocumentService

        {

            public DocumentJob job;

            [TestMethod]

            public void Should_Call_Document_Service_With_Document_Job()

            {

                //setup

                var submission = new Submission(this);

                //exercise

                submission.GenerateQuoteLetter();

                //verify - a real test would do more testing around what the job contains!

                Assert.IsNotNull(job);

            }

     

            public void FufillDocumentRequest(DocumentJob job)

            {

                this.job = job;

            }

         }

     

       public class DocumentJob

        {

        }

     

        public class Submission

        {

            private IDocumentService service;

     

            public Submission(IDocumentService service)

            {

                this.service = service;

            }

     

            public void GenerateQuoteLetter()

            {

                DocumentJob job = new DocumentJob();

                service.FufillDocumentRequest(job);

            }

        }

     

    Mock

    A mock is useful when we want to confirm the sequence and number of messages to the DOC, specifically the method calls and the arguments passed to them.  A mock is intrusive in that it specifies the interaction that the SUT should have with the DOC and confirms that the interaction meets that specification. It is thus less amenable to refactoring because it has knowledge of the implementation of the SUT.

    Mocks tend to be implemented using frameworks, so that makes them cheap to write, but the problem here can be a temptation to use mocks out of their appropriate context just because we have a framework for them. The issue here is we can end up with over-specified software that is difficult to refactor, because the tests lock in our implementation choices.

    Using ‘loose replay’ semantics, which allow mocks to respond without raising an error if calls are not made, can reduce the coupling between specification and implementation where appropriate.

    A mock differs from a spy in that a mock forces us to specify the expected interaction before we exercise the SUT, not after. It may be better to use a spy where you are uncomfortable with the test specifying the implementation of the SUT.

     In this, contrived, example we call an external OFAC service to search for our customer. We don’t return the result, but set a flag which is used in later rules. We want to test our output to the OFAC service, which is third-party to confirm that our interaction is correct.

         [TestClass]

        public class Use_A_Mock_To_Replace_A_DOC

        {

            private IOFACService oFACService;

            private MockRepository mocks = new MockRepository();

     

            [TestInitialize]

            public void Create_A_Mock_OFAC_Service()

            {

                oFACService = mocks.CreateMock<IOFACService>(); //strict replay semantics

            }

           

            [TestMethod]

            public void Should_Call_OFAC_Service_When_Validating_Client()

            {

                //setup

                Account newClient = new Account();

                newClient.FirstName = "Ian";

                newClient.Surname = "Cooper";

               

                using(mocks.Record())

                {

                    Expect.Call(oFACService.SearchSDNList(newClient.ToString())).Return(true);

                }

     

                //exercise

                using (mocks.Playback())

                {

                    newClient.KnowTheCustomer(oFACService);   

                } //verify

             }

        }

     

        public class Account

        {

            private bool onWatchList;

            public string FirstName {get;set;}

            public string Surname {get;set;}

     

            public void KnowTheCustomer(IOFACService oFACService)

            {

                onWatchList = oFACService.SearchSDNList(ToString());

            }

     

            public override string ToString()

            {

                return FirstName + " " + Surname;

            }

     

        }

     

    Inversion of Control

    Note that in order to replace the DOC with a stub; we must support Dependency Injection i.e. the instance of the DOC used by the DOC must be supplied to it.

    We could do this directly in our code; before we create the object we create its dependencies. The problem here is duplicating all that code to create our dependencies.

    We could create a service locater that we can ask for instances of common dependencies. This removes the duplicate code, and allows us to, for example, provide different implementations of the DOC but creates an additional dependency for the class, on the Service Locater.

    Finally we could use an Inversion of Control (IOC) container. With an IOC container we ask the container for the finished object. Inversion of Control is sometimes called the Hollywood Principle or “don’t call us, we’ call you”. We are using IOC in this context because we no longer have a dependency on a Service Locater, but hand off to an assembler and ask it to inject our dependencies. The framework creates us instead of us creating using the framework. Using an Inversion of Control container, such as Windsor, simplifies the creation of objects with their required dependencies.

     

  • Alt.Net UK September

    We are pleased to announce that the Alt.Net UK Conference will be returning in September, and that there will be room for more attendees this time!

    The plan is host the event at Conway Hall in London and our thinking is to follow the same sort of schedule as we did in February:
    - Evening planning session on Friday 12th September, following by a trip to a bar to socialise.
    - The Open Spaces sessions all day on Saturday 13th September

    This time we are thinking of starting off Saturday with a Park Bench to get the juices flowing.

    We are very open to listening to feedback from the community if you think that there are ways that we can improve on the conference experience.

    We would especially like to have more testers, technical authors and usability folk attend to foster cross-pollination of ideas.

    User registration will start from Friday 11th July at 07:00 UK time so the early birds will get the worm!

    The following social hubs have also been set up: Upcoming, Facebook, FriendFeed and LinkedIn. Don't forget that you can subscribe to the AltNetUk News River.

    Finally, we are currently looking for sponsorship, so if you know of an organisation that would be interested to be associated with the conference in return for a little lucre, we would love to hear from you / them! (The conference is non-profit)

    Conchango and redgate have generously agreed to be launch sponsors - but more is needed, especially as we have to pay for Conway Hall this time.

    Ian Cooper, Ben Hall and Alan Dean

    PS Thanks to David Laribee for his help in getting us set up on alt.net

  • TDD and Hard to Test Areas, Part1

     

    TDD and Hard-To-Test Areas

    I wanted to talk about the issues that people get when they begin working with TDD, the same issues that tend to make them abandon TDD after an initial experiment. Those are the 'hard-to-test' areas, the things production code needs to do, that those presentations and introductory books just don't seem to explain well. In this post we will start with a quick review of TDD, and then get into why people fail when they start trying to use it. Next time around we will look more closely at solutions.

    Review

    Clean Code Now

    TDD is an approach to development in which we write our tests, before writing production code. The benefit of this are:

    • Tests help us improve quality: Tests give us prompt feedback. We receive immediate confirmation that our code behaves as expected. The cheapest point to fix a defect is at the point you create it.
    • Tests help us spend less time in the debugger. When something breaks our tests are often granular enough to show us what has gone wrong, without requiring us to debug. If they don’t then we probably don’t have granular enough or well-authored tests. Debugging eats time, so anything that helps us stay out of the debugger helps us deliver for a lower cost.
    • Tests help us produce clean code: We don’t add speculative functionality, only code for which we have a test.
    • Tests help us deliver good design: Our test proves not just our code, but our design, because the act of writing a test forces us to make decisions about the design of the SUT.
    • Tests help us keep a good design: Our tests allow us to refactor – changing the implementation to remove code smells, while confirming that our code continues to work. This allows us to do incremental re-architecture, keeping the design lean and fit while we add new features.
    • Tests help to document our system: If you want to know how the SUT should behave examples are an effective means of communicating that information. Tests provide those examples.

    Automated tests lower the cost of performing these tests. We pay a cost once, but because we can then re-run our tests at a marginal cost they help us keep those benefits throughout the system lifetime. Automated tests are ‘the gift that keeps on giving’. Software spends more of its life in maintenance than in development, so reducing the cost of maintenance lowers the cost of software.

    The Steps

    The steps in TDD are often described as Red-Green-Refactor

     Red: Write a failing test (there are no tests-for-tests, so this checks your test for you)

    Green: Make it pass

    Refactor: Clear up any smells in the implementation resulting from the code we just added.

    Where to find out more

    Kent Beck’s book Test-Driven Development, By Example remains the classic text for learning the basics of TDD.

    Quick Definitions

    System Under Test (SUT) – Whatever we are testing, this may differ depending on the level of the test. For a unit test this might be a class or method on that class. For acceptance tests this may be a slice of the application.

    Depended Upon Component (DOC) – Something that the SUT depends on, a class or component.

    What do we mean by hard-to-test?

    The Wall

    When we start using TDD we rapidly hit a wall of hard-to-test areas. Perhaps the simple red-green-refactor cycle gets begins to get bogged down when we start working with infrastructure layer code that talks to the Db or an external web service. Perhaps we don’t know hot to drive our UI through a xUnit framework. Or perhaps we had a legacy codebase, and putting even the smallest part under test quickly became a marathon instead of short sprints.

    TDD newbies often find that it all gets a bit sticky, and faced with schedule pressure, drop TDD. Having dropped it they lose faith in its ability to deliver for them and still meet schedule pressure. We are all the same, under pressure we fall back on what we know; hit a few difficulties in TDD and developers stop writing tests.

    The common thread among hard-to-test areas is that they break the rhythm of development from our rapid test and check-in cycle, and are expensive and time-consuming to write. The tests are often fragile, failing erratically and difficult to maintain.

    The Database

    • Slow Tests: Database tests run slowly, up to 50 times more slowly than normal tests. This breaks the cycle of TDD. Developers tend to skip running all the tests because it takes too long.
    • Shared Fixture Bugs: A database is an example of a shared fixture. A shared fixture shares state across multiple tests. The danger here is that Test A and Test B pass in isolation, but running Test A after test B changes the value of that fixture so that the other test fails unexpectedly. These kinds of bugs are expensive to track down and fix. You end up with a binary search pattern to try and resolve shared fixture issues: trying out combinations of tests to see what combinations fail. Because that is so time consuming developers tend to ignore or delete these tests when they fail.
    • Obscure Tests: To avoid shared fixture issues people sometimes try to start with a clean database. In the setup for their test they populate the Db with any values they need, and in the teardown clean them out. These tests become obscure, because the setup and teardown code adds a lot of noise, distracting from what is really under test. This makes tests hard to read as they are less granular, and thereby harder to find the cause of failure in.  The Db setup and teardown code is another point of failure. Remember that the only test we have for out tests themselves is to write a failing test. Once you get too much complexity in your test itself it can become difficult to know if your test is functioning correctly.  It also makes them harder to write. You spend a lot of time writing setup and tear down code which shifts your focus away from the code you are trying to bring under test, breaking the TDD rhythm.
    • Conditional Logic: Database tests also tend to end up with conditional logic – we are not really sure what we are going to get back, so we have to insert a conditional check to see what we got back. Our tests should not contain conditional logic. We should be able to predict the behavior of our tests. Among other issues, we test our tests by making them fail first. Introducing too many paths creates the risk that the errors are in our test not in the SUT.

    The UI

    • Not xUnit strength: xUnit tools are great at driving an API, but are less good at driving a UI. This tends to be because a UI runs in a framework that the test runner would need to emulate, or interact with. Testing a WinForms app needs the message pump, testing a Web Forms app needs the ASP.NET pipeline. Solutions like NUnitAsp have proved less effective at testing UIs than scripting tools like Watir or Selenium, often lacking support for features like JavaScript on pages.
    • Slow Tests: UI tests tend to be slow tests because they are end-to-end, touching the entire stack down to the Db.
    • Fragile Tests: UI tests tend to be fragile, because they often fall foul of attempts to refactor our UI. So changing the order and position of fields on the UI, or the type of control used will often break our tests. This makes UI tests expensive to maintain.

    The Usual Suspects

    We can identify a list of the usual suspects, who cause issues for successful unit testing.

    • Communicating Across a Network
    • Touching the File System
    • Requires the Environment to be configured
    • An out-of-process call (includes talking to Db)
    • UI

    Where to find out more

    XUnit Patterns: Gerard Meszaros' site and book are essential reading if you want to understand the patterns involved in test-driven development

    Working with Legacy Code: Michael Feathers' book is the definitive guide to test-first development in scenarios where you are working with legacy code that has no tests.

    Next time around we will look at how we solve these issues.

     

    Posted Jul 07 2008, 04:10 PM by Ian Cooper with 31 comment(s)
    Filed under: ,
  • Showing some support for LINQ to SQL

    While I have finished my series on LINQ to SQL I wanted to talk about some of the reaction. In his summary post of 30 June Roger Jennings mentions his concerns that because the SQL Server Data Programmability group, who are bringing us Entity Framework v1, now owns LINQ to SQL we will not see the kind of development I asked for in my last post of my Architecting LINQ to SQL series. Indeed Matt Warren's comment in this post, that the provider model for LINQ to SQL was disabled before release is troubling for what it implies about internal politics over data access strategies in Redmond and might confirm concerns I had a long time ago.  Looking at the the Data Platform team's blogs and site, LINQ to SQL seems almost forgotten.

    I would like to see MS give this product the support it deserves. I would like to see a commitment from the Data Platform team to stop its focus on talking LINQ to SQL down as a RAD tool and tallking up its advantages for use in the OO approaches to software development. For example  I would like to see the Data Platform team talking about LINQ to SQL's support for POCO strategies, lazy loading, etc. and pointing out to customers who request those features. There needs to be more acknowledgement that if you want them you should consider LINQ to SQL. Right now their only response is to repeat that those features will be in Version 2 of the EF. Well, an MS ORM supports those features today, you should point that out to your customers, and give advice on how to achieve it. As of now, in my opinion, LINQ to SQL is their best development tool for OO an approach to development and they need to reflect its strengths in the advice they give, not just focus on its weaknesses when compared to EF. 

    Martin Fowler posted some time ago about different schools of software development. Perhaps one solution for the conflict over the future of these tools is for MS to accept that it has (at least) two audiences and build a product for the OO folks and one for the data-first folks. In that case LINQ to SQL would be a better start for the OO folks because it already contains so much of what they need, it may represent a better starting point for supporting them.

    People feel sorry for the Entity Framework team for the criticism in the open letter. For my part I feel sympathy for the LINQ to SQL team, who fell foul of product strategy decisions with ObjectSpaces and seem to have done so again. Considering how well they understood the OO approaches we wanted, unlike the EF team, the team are unsung for their efforts. The Alt.Net community in particular should give them wider support for having, unlike the Entity Framework team, recognized the needs of those developers taking an OO approach to development. it does not give us everything, but credit where it is due.

    Today, while I would not recommend using the Entity Framework I would recommend looking at LINQ to SQL. Everything needs evaluation for your own needs, but unlike EF, LINQ to SQL is a better contender for OO approaches today.

    Sasha points out when looking at how LINQ to SQL is suprising people who had been misinformed as to what if offered and how we should use it, the noise in the blogsphere from Entity Framework supporters seems to have drowned out the value of LINQ to SQL as an ORM. Indeed I believe the Data Team's own pitching of LINQ to SQL as a RAD tool is an underestimates the product.

    As a community, as people begin to realize the suprising power of LINQ to SQL, I would like to see us dispel many of the myths that seem to have grown up around that product. I would like to see us put pressure on the Data Platform team to provide the support for LINQ to SQL that we want going forward. Community reaction is everything and if the LINQ to SQL community remains silent in the face of the more vocal, but probably less numerous, EF community, we won't get the product we deserve.


    Posted Jul 02 2008, 07:57 AM by Ian Cooper with 28 comment(s)
    Filed under:
  • Architecting Linq to SQL, part 10

     Previously: Architecting Linq to SQL, part 9

    End of the line

    This is intended to be the last part in this series and I wanted to take the opportunity to talk about a number of related if diverse topics. I would like to look at what I would like to see in the next version, and talk about when and where I intend to use Linq to SQL and other ORMs such as NHibernate.

    I will try to get some of the code that goes with this series up onto google code over the coming months, schedules permitting. Roger Jennings requested that I give more than a trivial example of how to do messaging for n-tier scenarios. I'm flattered by Roger's confidence, though I feel that Greg or Udi would be better placed to do a introductory piece on messaging. But if there is demand I will give it a try.

    What would I like to see in the next version?

    The following are, I think, the priorities:

    Support for Value Types. In a fine grained object model we may have classes that are not entities (have a distinct identity independent of their state). A common example would be Money, which has a value and currency. We do not want to map these to rows in a table, but to columns. Right now with Linq to SQL we have to represent money as two fields, amount and currency in an entity. We would like to represent them as one type, which can be mapped independently. As an aside a lot of systems overuse primitive types directly. Often we have something that is not a string or an int even if we can represent it as such. Our systems become clearer if we can wrap these primitives in a name appropriate to the domain such as ShippingReference. This only works if we can map value types easily. This is fairly straightforward if we assume that the column names used by these value types remain the same on any entity that stores them.

    Support for changing loading options. As of today we can only alter the default loading behavior of a DataContext before we use it. This assumes that we can determine what we want to eager load once for a context. The reality is that we may want to set this before we run any query. So it must be possible for us to set eager loading options each time we run a query. An alternative would be to do something more akin to Hibernate's HQL language's ability to add a fetch to the query expression so that we can tell the query to load the relationship eagerly.We also want support for eager loading multiple child associations, not just the one we have now.

    Support for ordered relationship types. Right now an association is treated as a set - an unordered collection. However often are children are ordered, particularly being in a map where we have both a key and a value. The key should be both a primitive type and another entity or value type. While this type of mapping is less common in the relational world, within our domain we often want to use ordered mappings, and support for mapping these to relational tables gives us increased flexibility when mapping domain to Db.

    Support for table per sub-class mapping.  Sometimes we do not want to allow fields on sub-classes to be nullable. Unfortunately this is a requirement of table-per-class-hierarchy mapping strategies. Allowing table per sub-class, using a shared key strategy would allow us to avoid this issue. Table per-subclass with shared key avoids some of the performance issues from moving away from a single table, which might be incurred if we took a union approach to combining data from multiple tables to support subclassing.

    There are also some things I would like to see, though I am less optimistic that they will happen

    Expose the provider model. Allow LINQ to SQL to target multiple Dbs. It exists but was never exposed at RTM. I suspect the resources were not allocated because the Entity Framework became the way to work if you had a non-SQL Server back end. Given EF not being positioned as an ORM let's open it up so we can take LINQ to SQL forward.

    Include an explicit in-memory provider. This will make TDD a breeze.  Once we have an in-memory provider it would be easy to swap out the Db for unit testing purposes.

    Support for second-level caching. MS now has a second level caching technology in Velocity. It would be nice to see support for working with a second level cache within LINQ to SQL (the first level cache is the identity map).

    What I would be cautious about in the next version 

    There are also some things that I would be disappointed about a disproportionate amount of much effort being expended on:

    Support for serialized entities. I hope I have managed to explain why serializing an entity across tiers is a bad architectural style. Instead of corrupting LINQ to SQL with support for this practice, I would like to see an emphasis from the patterns on practices team on dissuading people from approaching n-tier design in this style. We do not want to pollute entities with change tracking or serialize a DataContext.

    More advanced designer options. I appreciate that some folks like designers, but I think that they may be a red herring here. If you work domain-first then you might as well use attributes to mark up your domain model, or hand code your xml mappingfile. If you are going to work in a data first approach, I would push extending SQLMetal with those capabilities instead of a designer.

    In the data first case the design is done in the RDBMS, not in the domain model, so by the time we get to LINQ to SQL we are just generating our entity model from our Db. All the designer gives us is the ability to select a sub-set of tables to generate. A fairly simplistic UI, such as a dropdown list to add tables, could configure the options for a SQLMetal call. Flashy drag and drop layout seems a little bit wasteful. Even better if the property based approach is just a wrapper around a SQLMetal call that makes that command you have configured available. That allows folks to use the command they have created throough the designer in their build scripts to call SQLMetal. This would give more resources for the new functionality people want from their data-first designer such as file per entity, update an existing set of files for changes etc.

    I understand this may not be popular, but command line tools are cheaper to author and can deliver a lot more bang for your buck if your team has limited resources. In addition a designer can blind you to an over-complex approach to mapping. If you cannot easily map by hand, if you require that designer, then I believe that you may have lost your way.

    I understand that these suggestions will be unpopular with some people, but both of them represent dead ends to me, that do not provide us with the ability to write better software. Of course your mileage may vary.

    Linq to SQL over Entity Framework for your ORM

    For my part, and that is of course based of my school of software development, LINQ to SQL is a better ORM than the Entity Framework. That may come as no shock to the EF team who have a bigger vision for their product than ORM. For me, LINQ to SQL get a lot right: support for persistence ignorance, single mapping file that is by-hand authorable, lazy loading as a default strategy. If MS intends to provide an offering in the ORM space, as opposed to whatever space the EF is defining, and thus fulfill the vision that Anders gave us of simplifying the development experience by having data access as part of the language. To me LINQ to SQL is the best MS contender for the crown. Given the resources, LINQ to SQL could become a great tool. I hope that MS continue to allocate a fair share of resources to it.

    LINQ to SQL vs. NHibernate

    To be honest, I have to say that my next project will use NHibernate for its persistence technology instead of LINQ to SQL. Why? It is a large project, with a significant number of entities, and we want to support fine-grained object models and table per sub-class mapping strategies. We also wanted the insurance of being able eager fetch on a query-by-query basis and have a 2nd level cache. It is an old adage but 'there is no silver bullet'. I'm picking one tool out of the kit, it does not mean the others are not valuable.

    At the same time LINQ to SQL still forms part of our strategy, because we believe it to be simpler to approach for many projects.So we also have and will be using LINQ to SQL. If anything LINQ to SQL replaces WORM for us which we used for a number of projects where we had good table to entity affinity. Ironically perhaps WORM was an implementation of the proposed interface for ObjectSpaces. ObjectSpaces was the MS ORM for .NET 2.0, that never saw the light of day. ObjectSpaces became LINQ to SQL, and Matt has full the story here, so it seems a natural inheritor. Let us hope it does not meet the ObjectSpaces fate of being sidelined for a more grandiose vision of data access.

    A valid question might be to ask why I want improve LINQ to SQL, why I do not just tell everyone to use NHibernate. Some of this is a recognition of the market, many people will not use a non-MS ORM and LINQ to SQL is is a solid ORM. Pragmatically we are likely to get more .NET developers who know LINQ to SQL available in the market place than NHibernate developers. But I also believe that with the expressiveness of LINQ MS have a real chance to move the ORM market forward in the .NET space. LINQ to SQL is like ASP.NET MVC, it is a welcome acknowledgement from MS of what developers want, and we should commend them when they do get it right.

    I will be posting a series on NHibernate going forward, so that you can make your own judgements on which to use and when.

     

  • Alt.Net events in London