Sunday, January 04, 2009 #

Do I put this method into a New Class? Decisions Decisions…

Technorati Tags: ,,

These days I’m working a lot more on not just code features, but also more architecture from scratch.  That is, creating many new Abstract classes, Non-Abstract classes, Interfaces and utilizing more and more Design Patterns.  Thus every field, member, property, etc. created in the class or interface heirarchy tree becomes very important in how you define them and where you define them as well as any dependencies that they may be carrying.  You try to create a class or interface structure with as least # dependencies as possible, so that a change to one object will not affect the other (thus a good separation of concerns in your design).  You’re not just creating a class here and there, but you’re creating the architecture (class trees, foundations for which developers on the team will utilize later). 

With that said, decisions often come down to the simplest & smallest forms when you look at architecting classes or interfaces. It’s not all about the big decisions every time.

The goal is to create good software right?  At least that is what your team & management should have in mind other than just meeting deadlines to please the customer & spitting out code at lightening speed which seems to be the expectations today from the business which often turns into horrible architecture (code & run) as a result.  I’m an advocate of true Agile methodology but not really into Extreme programming personally.

So what defines good software?  An excellent measurement to continually check your code by running it through the ISO/IEC 9126 Standard list which states a very nice list that measures the following in terms of design and determining if your software is meeting business requirements. 

I’m going to reference a table from the book Microsoft® .NET: Architecting Applications for the Enterprise (PRO-Developer) based on the  ISO/IEC 9126 Standard:

(I also appended some of my own thoughts in parenthesis below, and highlighted what I thought was most important from a technical standpoint)

Functionality

- Indicates what the software does to meet expectations

- It is based on requirements such as suitability, accuracy, security, interoperability, and compliance with standards and regulations defined by the customer

Reliability

- Indicates the capability of the software to maintain a given level of performance when used under special conditions

- It is based on requirements such as maturity, fault tolerance, and recoverability

- Maturity is when the software doesn’t experience interruptions in the case of internal software failures

- Fault tolerance indicates the ability to control the failure and maintain a given level of behavior

- Recoverability indicates the ability to recover after failure

Usability

- Indicates the software’s ability to be understood by, used by, and attractive to users. 

- It dictates that the software be compliant with standards and regulations for usability

Efficiency

- Indicates the ability to provide a given level of performance both in terms of appropriate and timely response and resource utilization

Maintainability

- Indicates the software’s ability to support modifications such as corrections, improvements, or adaptations.

- It is based on requirements such as testability (unit testable), stability, ability to be analyzed, and ability to be changed (example: can you easily change out the current DL and create for example your own custom DL?)

Portability

- Indicates the software’s ability to be ported from one platform to another and its capability to coexist with other software in the environment and sharing common resources

Now anyone could easily just skim over the bolded list and really never understand them unless they take time and really care to engage in this list and apply to the development shop. It’s easy to just gloss over the bullets above and say “yea, yea, I know what they mean”.   But do you really?  I bet you that you don’t unless you really take the time to understand what each is and in context to creating maintainable and extensible code.  And I bet if you think you do know, that it’s most likely not even being applied in terms of a team standard or some form of checks & balances on your team often.  If it is, I applaud you and the team.  This would be a very good list for code reviews as well as part of a team standards doc.  While it’s general, it also specifies specifics as you can see above so that there is no confusion what they mean at a high level.

In my opinion, every development lead or manager should ALWAYS use this list as part of your overall tools to make sure that your shop is producing is GOOD software and underlying code and patterns support these points above.  And I think one of the best ways to start doing this is to analyze your code base to see if it’s easily Unit Testable as it stands today.  If not, then you have some work to do to refactor or make sure new classes or interfaces are going foward.   Checking if it’s unit testable is a very good measure to see if your code is maintainable and extensible at the same time.  Using the SharePoint API with DataSets is not easily unit testable.  It’s tightly coupled which goes completely against unit testable frameworks.  That’s just one example of bad software.

Now for a simple example at work the other day where a small routine decision in architecture really becomes an all too common very important decision for extensibility, testability, and maintainability hit me again.  I am currently working on creating a small framework that will allow us to utilize a third party REST API in order to offer some new features & functionality to our customers for a very good reason via our public e-commerce website.  This project probably will consist of around 20-40 classes or so, and maybe a couple interfaces if it makes sense for some code that we may be able to reuse between some projects.  Fairly small but definitely challenging and complex to say the least based on some of the things we’ll have to incorporate on our side and also get working on the SOA endpoint side of things.

Anyway, it came down to when I created an APIRequest.cs class in my project.  This class would represent an HTTP API method call request to the SOA API server in order to call a method over to the SOA REST API.  This class will not only hold the data (fields) in the request but help to form the request string itself.   I had to make a decision whether or not to put a method of mine SendAPIRequest() in my APIRequest.cs class or move it to a separate class that would do the sending processing related work for sending the request itself. 

In the end, I thought about the Single Responsibility Principal (part of the SOLID Principal) that a friend had reminded me of.  That principal states that a class should only have a single responsibility.  And the responsibility that I defined for my APIRequest class was only to hold the state of a request (the data) and to form the string for the request.  If you find your class starting to do other things (via methods) that doesn’t really make sense to the original class’s purpose (and hence it’s name should also communicate its purpose), then it’s time to break that method(s) or those fields out into a new class.  Breaking it out into a new class made sense was to represent the request data, not to do the work sending the actual request.  So that called for a separation of logic into a new class to handle the actual work to send the request.  This ensured that I was satisfying the SRP principal as well as are easily testable in the future.

That is just one example of a simple decision that I had to make but in the overall scheme of things is a very important decision to:

1) Ensure quality software is produced not only for the business

2) Ensure that the “team” can change the code easily and maintain those classes later without affecting each other (breaking change) down the road

I would not put this method in a utility class because I know that for sending the request, I’m going to need several methods that separate out the logic to do so possibly.  And I also want the fexibility to test the logic as well as extend that functionality later for sending a request.  I want that extensibility to be there in the future so by putting that method in a regular class, not a utility class.  I’m very careful about Utility classes.  You do not want to use a Utility class as a bucket to put all of your business logic in.  They should be held in logical classes unless those utilities are general enough to be reused elsewhere or does not make sense anywhere else.  Do not put all your business logic methods in Utilities is what I’m saying.  You’ll end up with one Utility class with 1000+ lines in it which makes it a big pile, hard to read, and non-testable.  That’s why we use classes, inheritance, and thus separate concerns in terms of logic.  Utility classes have their place but be careful what and how much you put in them.

Conclusion:  Such a small decisions have huge impacts later down the road and one of them is determining where certain class methods should lie in your overall class structure.


posted @ Sunday, January 04, 2009 10:28 PM | Feedback (2)