Archive for April, 2012

Part IV: Stick Design – How to design and build better software for tomorrow?

3

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

 

In Part III, we introduced our prototype Contact Manager design. Although the application satisfied our functional requirements, we evaluated the Straw Contact Manager using our software design principles presented in Part II of the series. During the analysis, we discovered the design did not meet our criteria for well-designed software. It was not maintainable and difficult to test all code paths. We discovered many features were simply not reusable and the code was not separated into distinct layers.  In Part I of the series, we discussed the benefits of a design with an eye on the future and ability to better adapt to change. We need to address the issues discovered during our evaluation.

The Stick Contact Manager is our second design, which is based on refactoring the Straw Contact Manager. We will follow several design patterns and practices that promote our design principles and ability to adapt to change. These key patterns and practices will enable us to build better software for tomorrow.

The following is a summary of the changes that we will apply to the Straw Contact Manager for our Stick Contact Manager.

 

Dependency Injection Principle (DIP)

The Dependency Injection Principle is simply replacing concrete implementations with abstractions. A concrete implementation will couple our design to specific behavior, so we cannot change without causing a ripple effect throughout the system or enterprise. The ContactsService class contains a dependency on the ContactRepository, which is instantiated in the constructor using the new keyword. This is a candidate to apply the Dependency Injection Principle, so we are not tightly coupled to a specific implementation of the ContactRepository. If we change or introduce another ContactRepository implementation then it would require significant changes to accomplish this task. The simplest technique for identifying the candidates of the Dependency Injection Principle is the new keyword, where we are creating an instance of an object.

 

Separation of Concerns (SoC) and Single Responsibility

Next, we will follow the guidance of Separation of Concerns (SoC) to decompose a system into a layered architecture. This will promote reusability as well as improve maintainability. In general, we need to separate into distinct layers. In the Straw Contact Manager, we had one project as a console application trapping all functionality. We will refactor and move our service and data logic to a separate class library, which is one of the easiest techniques to accomplish SoC.

The Single Responsibility Principle (SRP) forces us to remain focused on a single responsibility and do not clutter our objects with more implementation. The ContactsService AddContact method is good example of violating this principle. We included the logic to send an email notification, which should be delegated to another object to handle the details. This will also allow us the reuse the notification feature throughout the enterprise, so we do not have redundant email code in multiple classes.

 

Dependency Injection (DI)

We previously introduced the Dependency Injection Principle, where we remove concrete implementations and code to abstractions or interfaces. The Dependency Injection pattern is the concept of injecting dependencies during object creation. If Dependency Injection Principle removes the object instantiation then we use Dependency Injection to inject the dependency using a constructor, setter or method style.

So…we now have the design patterns and practices as the basis for our Stick Contact Manager. The following are the results of this exercise, but you will need to download the source code to review the completed design.

First, we will move our non-user interface classes into a separate class library. This will promote reusability, so other teams can leverage the Contact Manager features as building blocks for their project. Why reinvent the wheel, when we can borrow from an existing project?

The second step is to apply the Dependency Injection Principle by creating the IContactRepository and INotificationService interfaces. The interfaces will serve as the contracts for all concrete implementations.

 

01
namespace ContactManager.Common.Repository
02
 {
03
     /// <summary>
04
     /// ContactRepository contract
05
     /// Create one or more implementations.
06
     /// </summary>
07
     public interface IContactRepository
08
     {
09
         void Save(ContactManager.Common.Model.Contact contact);
10
     }
11
 }
12

01
namespace ContactManager.Common.Services
02
 {
03
     /// <summary>
04
     /// NotificationService contract
05
     /// Create one or more implementations. Try using an abstract class
06
     /// if shared features are beneficial to the implementations.
07
     /// </summary>
08
     public interface INotificationService
09
     {
10
         void Send(ContactManager.Common.Model.Contact contact);
11
         string Message { get; set; }
12
     }
13
 }
14
 

 

We also need to refactor our concrete implementations, so they utilize the appropriate interfaces. Since we received change requests for additional notification services, we will add a new implementation for SMS Text messaging.

 

01
using ContactManager.Common.Model;
02
 namespace ContactManager.Common.Repository
03
 {
04
     /// <summary>
05
     /// Concrete implementation to persist contact to data store
06
     /// I am now separated with a single responsibility to be maintainable,
07
     /// resusable and testable!
08
     /// </summary>
09
     public class ContactRepository : IContactRepository
10
     {
11
         public ContactRepository() { }
12
 
13
         public void Save(Contact contact)
14
         {
15
             //TODO: code to persist contact
16
         }
17
     }
18
 }
19
 

01
using ContactManager.Common.Model;
02
 namespace ContactManager.Common.Services
03
 {
04
     /// <summary>
05
     /// Concrete implementation to send email notifications
06
     /// I am now separated with a single responsibility to be maintainable,
07
     /// resusable and testable! 
08
     /// </summary>
09
     public class EmailService : INotificationService
10
     {
11
        public EmailService() { }
12
 
13
        public EmailService(string smtpHost,
14
                            string sender,
15
                            string subject,
16
                            string message)
17
         {
18
             this.Message = message;
19
             this.Subject = subject;
20
             this.Sender = sender;
21
             this.SmtpHost = smtpHost;
22
         }
23
 
24
        public string Message { get; set; }
25
        public string SmtpHost { get; set; }
26
        public string Sender { get; set; }
27
        public string Subject { get; set; }
28
 
29
        public void Send(Contact contact)
30
         {
31
             string recipient = contact.EmailAddress;
32
             MailMessage msgMail = new MailMessage(this.Sender,
33
                                                   recipient,
34
                                                   this.Subject,
35
                                                   this.Message);
36
             SmtpClient smtp = new SmtpClient(this.SmtpHost);
37
             //smtp.Send(msgMail);
38
         }
39
    }
40
 }
41

01
using ContactManager.Common.Model;
02
 namespace ContactManager.Common.Services
03
 {
04
     /// <summary>
05
     /// Concrete implementation to send text notifications
06
     /// I am now separated with a single responsibility to be maintainable,
07
     /// resusable and testable!
08
     /// </summary>
09
     public class SmsService : INotificationService
10
     {
11
         public SmsService() { }
12
 
13
         public SmsService(string message)
14
         {
15
             this.Message = message;
16
         }
17
 
18
         public string Message { get; set; }
19
 
20
         public void SendContact contact)
21
         {
22
             //Send text message to mobile phone
23
         }
24
    }
25
 }
26
 
27

 

The next step is modify our constructors to accept the dependent objects at creation time. This is the Dependency Injection pattern, which will allow us to pass the object instead of creating the dependency within the class. The high-level object should not be responsible for knowing how the dependencies are created. The ContactsService will be refactored, so it is no longer responsible for creating the dependencies or including the email logic for the notification.

 

01
using ContactManager.Common.Model;
02
 using ContactManager.Common.Repository;
03
 namespace ContactManager.Common.Services
04
 {
05
     /// <summary>
06
     /// High-level concrete contacts service - called by the client
07
     /// I am not married to low-level concrete dependencies, so 
08
     /// any changes willno longer affect me. I now depend on interfaces
09
     /// or abstract classes.
10
     /// </summary>
11
     public class ContactsService
12
     {
13
         private IContactRepository _contactRepository;
14
         private INotificationService _notificationService;
15
 
16
         //dependencies are now injected using the constructor
17
         public ContactsService(IContactRepositorycontactRepository,
18
                                INotificationService notificationService)
19
         {
20
             _contactRepository = contactRepository;
21
             _notificationService =notificationService;
22
         }
23
 
24
 
25
        public void AddContact(Contact contact)
26
        {
27
             //code is simple and easy to understand!
28
             _contactRepository.Save(contact);
29
             _notificationService.Send(contact);
30
        }
31
      }
32
 }
33

 

If you compare the Straw Contact Manager to the Stick Contact Manager then you will notice the code is cleaner and easier to read. The ContactsService does not contain notification logic, so instead it is delegated to a notification object to handle the details. The ContactsService is simply managing the workflow of the request to add a contact. The AddContact method calls the IContactRepository to persist the contact information and INotificationService to send a notification to the contact. The dependencies are injected or passed into the ContactsService, so no code to create and initialize the objects is required. The constructor parameters are not concrete implementations, so we can accept any object of the specified interface type.

We accomplished so much with applying a few simple design patterns and practices. We did not change the functionality and we still satisfied our business requirements, but we have a much more efficient design with ability to adapt to change without significant impact.

At this point, we should evaluate our Stick Contact Manager design using our design principles/checklist. The following is the scorecard.

 

√ Maintainable (capacity to change)

Reusable (share)

√ Testable (capacity to test)

√ Separable (layered)

 

The maintainability of the design is much improved, which is the capacity to change. If we received a change request to add a new feature for social networking as a notification then the design would require the simple addition of a new class TwitterNotification. This change will have a minimal impact to other dependencies, since all dependencies are expecting any object of INotificationService.

What if another team would like to add the Contact Manager feature to a web application? The design is reusable, since the features are now accessible and exposed for clients.

We improved our testability, since all features have been separated and features can be tested independently. For example, we can now test the email and SMS text notification implementations. How do we test ContactsService with the notification and repository dependencies? The recommended approach is to create mock objects for the IContactRepository and INotificationService. The mock objects have no detailed implementation, but serve as objects to test the ContactsService implementation. The concrete implementations of the repository and notification service can be tested independently. The code can be downloaded to review the test project.

We removed all the details from the ContactsServce, so where did they go? The client is now the owner of the object creation that was removed from the ContactsService and other lower-level objects. So…what does the client now look like with the changes being pushed?

 

01
using ContactManager.Common.Model;
02
 using ContactManager.Common.Services;
03
 using ContactManager.Common.Repository;
04
 namespace StickContactManager
05
 {
06
     class ContactManager
07
     {
08
         static void Main(string[] args)
09
         {
10
             try
11
             {
12
                 Console.WriteLine("*** StickContactManager ***");
13
                 Contactcontact = new Contact("John Doe",
14
                                              "jdoe@somewhere.com",
15
                                              "407123456">);
16
 
17
                 //get common properties from app.config
18
                 string smtpHost = ConfigurationManager.AppSettings["Smtp.Host"];
19
                 string emailSender = ConfigurationManager.AppSettings["Email.Sender"];
20
 
21
                 //initialize dependencies
22
                 IContactRepository contactRepository = new ContactRepository();
23
                 INotificationService notificationService;
24
 
25
                 //notificationService = new EmailService(smtpHost,
26
                 //                                       emailSender,
27
                 //                                       "Hello!",
28
                 //                                       "Hello Email Contact!");
29
                 notificationService = new SmsService("Hello Text Contact!");
30
 
31
                 //inject dependencies via constructor
32
                 ContactsService service = new ContactsService(contactRepository,
33
                                                               notificationService);
34
                 service.AddContact(contact);
35
             }
36
             catch (Exception e)
37
             {
38
                 Console.WriteLine(e.Message);
39
             }
40
         }
41
     }
42
 }
43
 

As we can see, the Stick Contact Manager is a huge improvement over the previous design and satisfies our design principles. We can still improve the design and simplify the complexity of the client code. In Part V, we will refactor the Stick Contact Manager and introduce the Brick Contact Manager to address the issue depicted above. At this point, we accomplished our goals to provide a design that can adapt to change and avoid premature end-of-life. If you apply the techniques presented in the Stick Contact Manager then you will realize just a few extra steps in the design can make a significant improvement to your final product.

Source Code

Previous: Part III: Straw Design
Next: Part V: Brick Design

Part III: Straw Design – How to design and build better software for tomorrow?

0

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

In Part II, we identified the core principles of well-designed software. This checklist will enable us to evaluate a design and plan refactoring activities to eliminate deficiencies. This is our first design of the Contact Manager, which is loosely based on a Rapid Application Development (RAD) concept discussed previously.

Since the objective of this series is not focused on the concrete implementation of all methods, the code will include “TODO” comments. The series will introduce techniques to satisfy our core design principles, so this will be the Straw Contact Manager for an evolving design.

First, we will create an entity model to represent our contact domain. This is a simple Plain Old .NET Object (PONO) or Plain Old CLR Object (POCO) class with the properties representing the information required for our contact.

01
    public class Contact
02
     {
03
         public Contact() { }
04
 
05
         public Contact(string name, string emailAddress, string mobilePhone)
06
         {
07
             Name = name;
08
             EmailAddress = emailAddress;
09
             MobilePhone = mobilePhone;
10
         }
11
 
12
         public int Id { get; set; }
13
 
14
         public string Name { get; set; }
15
 
16
         public string EmailAddress { get; set; }
17
 
18
         public string MobilePhone { get; set; }
19
     }
20

Second, we will create a class to persist the contact object to a data store. We will not focus on the implementation, so you will need to use your imagination for the demonstration. In this example, we will use the Repository design pattern. The data access technologies range from ADO.NET core, ADO.NET Entity Framework (EF), Language Integrated Query (LINQ), third-party Object-Relational Mapping (ORM or O/RM) and others. This will separate the logic to interact with the data source and map the data to the entity model.

01
using StrawContactManager.Model;
02
namespace StrawContactManager.Repository
03
{
04
    ///
05
    /// Concrete implementation to persist contact to data store
06
    /// 
07
    public class ContactRepository
08
    {
09
        public ContactRepository() { }
10
 
11
        public void Save(Contact contact)
12
        {
13
            //TODO: code to persist contact
14
        }
15
    }
16
}
17

Third, a service object will handle the request from the user interface or client to save the contact information. This object will orchestrate the workflow required to complete the task, which includes calls to the repository or data access layer (DAL). The add process includes saving the contact information and sending an email welcome notification to the new contact.

01
using System.Net.Mail;
02
using StrawContactManager.Model;
03
using StrawContactManager.Repository;
04
namespace StrawContactManager.Services
05
{
06
    public class ContactsService
07
    {
08
        private ContactRepository _contactRepository;
09
 
10
        public ContactsService() 
11
        {
12
            //create dependency of concrete implementation
13
            _contactRepository = newContactRepository();
14
        }
15
 
16
        public void AddContact(Contact contact)
17
        {
18
            //persist contact using dependency
19
            _contactRepository.Save(contact);
20
 
21
            //low-level details to send notification email to contact
22
            string smtpHost = "myHost";
23
            string recipient = contact.EmailAddress;
24
            string sender = "hello@contacts.com";
25
            string subject = "Hello Contact";
26
            string message = string.Format("Hello {0}!", contact.Name);
27
 
28
            MailMessage msgMail = newMailMessage(sender,
29
                                                 recipient,
30
                                                 subject,
31
                                                 message);
32
 
33
            SmtpClient smtp = new SmtpClient(smtpHost);
34
            //smtp.Send(msgMail);
35
        }
36
    }
37
}
38

In this example, our client will be a simple console application. Since we are not focused on the Contact Manager presentation, this will be the simplest option to illustrate the design. In a subsequent post, I will provide a Model-View-Controller (MVC) implementation of the Contact Manager.

 

01
       static void Main(string[] args)
02
        {
03
            try
04
            {
05
                Console.WriteLine("*** StrawContactManager ***");
06
                Contact contact = new Contact("John Doe",
07
                                              "jdoe@somewhere.com",
08
                                              "407123456");
09
 
10
                ContactsService service = newContactsService();
11
                service.AddContact(contact);
12
            }
13
            catch (Exception e)
14
            {
15
                Console.WriteLine(e.Message);
16
            }
17
        }

We also created a project for our unit tests, which will provide coverage to ensure the classes and methods are tested. You can download the code here, which will provide the complete Straw Contact Manager solution.

01
    ///
02
    ///This is a test class for ContactsServiceTest and is intended
03
    ///to contain all ContactsServiceTest Unit Tests
04
    ///
05
    [TestClass()]
06
    public class ContactsServiceTest
07
    {
08
        ///
09
        /// A test for ContactsService Constructor
10
        ///
11
        [TestMethod()]
12
        public void ContactsServiceConstructorTest()
13
        {
14
            ContactsService target = newContactsService();
15
            Assert.IsNotNull(target);
16
        }
17
 
18
        ///
19
        /// A test for AddContact
20
        ///
21
        [TestMethod()]
22
        public void AddContactTest()
23
        {
24
            ContactsService target = newContactsService();
25
            string name = "John Doe";
26
            string emailAddress = "john.doe@myemail.com";
27
            string mobilePhone = "0001112222";
28
            Contact contact = newContact(name, emailAddress, mobilePhone);
29
            target.AddContact(contact);
30
            Assert.IsNotNull(target);
31
            //Additional asserts for validating contact was persisted
32
        }
33
    }
34

At this point, we should evaluate our Straw Contact Manager design using our design principles/checklist. The following is the scorecard.

Χ  Maintainable (capacity to change)

Χ  Reusable (share)

Χ  Testable (capacity to test)

Χ  Separable (layered)

The maintainability of the design is poor, which is the capacity to change. If we received a change request to add a new feature to send an SMS text message as a notification then the design would require significant refactoring to support this request. This change will have a ripple effect on other dependencies.

What if another team would like to add the Contact Manager feature to a web application? Again, this would require refactoring to expose the feature for other clients. The design is not reusable, since we cannot share core features.

Although we are able to create sufficient tests for the Straw Contact Manager, we have some features that are isolated and difficult to test.

Finally, our design is not layered. The candidate features for sharing are not accessible for other teams or applications. Why can’t the email notification be separated as a feature, so it is not coupled with the “AddContact” method? This would be a good example of avoiding an enterprise system containing “copy-and-paste” redundant code scattered throughout for any applications requiring email services.

As we can see, the Straw Contact Manager suffers from several deficiencies and does not sufficiently satisfy our design principles. In Part I, we discussed “How to design and build better software for tomorrow?” and the ability to better plan for change. So…what features would be helpful to promote the core design principles? The following is a good start.

    • The ability to support more notification types – email, SMS text, voice, etc.
    • The ability to change our persistent layer. As new technologies emerge, we would like to be able to implement without requiring refactoring significant portions of our design.
    • The ability to call the Contact Manager from multiple clients – console apps, web apps, mobile apps, workflows, etc.

The above are simple and reasonable change requests. So…how do we build our software to support something without knowledge or detailed requirements? The Straw Contact Manager is not a design that would accommodate these changes, so we will need to refactor. As you can see, our Straw Contact Manager can easily reach a premature end-of-life. It is too costly to maintain.

In Part IV of the series, we will refactor our Straw Contact Manager and introduce the Stick Contact Manager. Our goal is to address the current design deficiencies and better plan for change. Please check back for the next post in the series…

Previous: Part II: Software Design Checklist

Next: Part IV: Stick Design

Part II: Software Design Checklist – How to design and build better software for tomorrow?

0

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

 

In Part I of the series, we discussed designing and building software to adapt to change. This will reduce the future maintenance costs and extend the life expectancy for the system. In Part II, we will define the guiding principles for software design. This checklist will be the scorecard for our designs throughout this series.

What are the characteristics of well-designed software? The list can be extensive and somewhat subjective, but the following software design principles are well known and accepted by the community.

·         Maintainable

·         Reusable

·         Testable

·         Separable

In Part I, we discussed the impact of change on software. A maintainable design is measured by the ability of a system to change. How painful is change? We can also link the flexible characteristic with this principle, since it is closely related to change.

A reusable design encourages feature sharing, where code is separated into logical components. In this case, the feature must be accessible for consumers to promote reusability. We also would like to prevent redundant code scattered throughout the system.

If the design is testable then the code is written so features can be thoroughly tested. The agile Test Driven Development (TDD) practice requires testable code to be effective. When we follow this practice and establish a robust set of automated tests, Continuous Integration (CI) provides additional benefits with frequent integration of changes and regression testing. If we introduce a new feature and execute our tests then we can identify breaks early in the cycle. As systems evolve and become more complex, it is more difficult to identify potential breaks or bugs introduced with new features or changes.

When we apply separation to a design, we decompose a system into distinct functional layers. In general, we want a module to have a limited or single responsibility. We will discuss the design patterns that promote this concept, so it will be much clearer with examples.

Our software design checklist is complete. It contains the core principles for well-designed software. In the next part, we will start our design using a Rapid Application Development (RAD) approach. We will evaluate the design using the checklist, so we can refactor to continue improvements until we are satisfied with the results. So…show us the code!

Previous: Part I: Intoduction
Next: Part III: Straw Design

Part I: Introduction – How to design and build better software for tomorrow?

0

This series is an adaption of my “Getting Started with Dependency Injection using Spring.NET” presentation, which was a session available at the Orlando .NET Code Camp 2012. Since I received invaluable participation and feedback from the attendees, this post will include expanded material and code examples.

 

In the software development world, we all know that change is inevitable. We design and develop systems based on requirements provided today, while satisfying project objectives and delivering the final product. It is a success…or is it?

We tend to think short-term when building software. Change can prematurely render a system obsolete, too costly or impossible to maintain – basically end-of-life scenario. My current role is leading agile teams in modernizing legacy enterprise systems, while introducing processes and disciplines to prevent premature end-of-life scenarios. We design to extend the life expectancy of systems without compromising core project objectives. We cannot prevent the eventual retirement of a system or a dramatic shift in technology, although we can better plan for change to slow the process. Since we are all members of the same development community, we also want to make life easier for the next team. The role of supporting systems is challenging, especially if the system was poorly designed or maintained.

Microsoft championed the Rapid Application Development (RAD) concept, which included development tools and practices to guarantee instant gratification. We can drag a few visual controls, click a button and start writing the logic in code-behind style. After adding a few more controls and pages, we have a working web site. Unfortunately, this approach contributes to the problem.

The .NET framework was a significant step forward and the answer to the enterprise minded Java platform. Its’ open source nature breeds an active and vibrant ecosystem, which delivers fresh ideas and reliable practices to the .NET community. We see popular design patterns, tools and ready-to-use libraries like MVC, NAnt, NUnit, NHibernate Log4Net, Cruise Control and Spring ported from Java to .NET. These products will simplify our lives as developers and architects, while reducing costs, accelerating development and introducing best practices. The staunch Microsoft supporters are gradually embracing this software development paradigm. This will play an important role in our quest to design and build better software.

So…you are probably thinking that it is impossible to predict the future? True. We can look at the evolution of communications over the years as an example – hardwired phones, fax, email, mobile phones, text and social media. We probably could not predict some of the technology of today a few decades ago, but we can design our systems to better adapt to change.

In this series, we will explore some options you can implement today, so your life is not painful in the future. We will build a simple Contact Manager using the previously mentioned RAD approach, while we discuss the pros and cons of the design. The RAD Contact Manager will be the straw design, which we will continue to refactor to improve the design as we identify the deficiencies. This is the “Build a Better House” or “Three Little Pigs” format, so the final entry will be a Brick Contact Manager. The presentation and code will be provided, so you can download and follow along. I hope you enjoy!

Next: Part II: Software Design Checklist

Go to Top