I is for Interface Segregation Principle.
This principle states that nothing should be forced to depend on methods that it doesn't use.
To illustrate this suppose there were a humongous class that handled making sandwiches (humongous sandwiches?). Now, as everyone knows, there are many kinds of sandwiches. There are toasted ones, open-face ones, and even bread-less ones. And while I'm not here to judge each sandwich, the point is that there are many different sandwiches and they are not all made the same way. To have each sandwich hold a reference to how to make anything but itself is wasteful. The bread-less sandwiches, as the name implies, don't have bread, so why should they know how to toast a piece of it?
Instead, each sandwich should depend on a reference to a subset of the large sandwich making class. This means that changes to how toasted sandwiches are made doesn't affect the bread-less ones, unless they are somehow also being toasted. I don't know enough about the different kinds of sandwiches.
In my own code, the closest I can come to this is the responders in my http server. I know that I've used them before, but that's alright, I think. The responders implement a very small interface. In fact, there's only one method and it's called respond. That isn't the only method that each responder has though. Some of them require additional methods to process the request cleanly and avoid an overly large respond method.
If I had pushed those methods up into the responder interface, instead of keeping them in the responders that required them, I would have been in violation of this principle. The responders that didn't use those extra methods could have just returned null or done nothing, but that would have been an unexpected behavior for anything relying on my responder interface. I'm not sure what principles that violates, but it can't be a good thing to do.
Again, if you don't agree with my description of this principle, please let me know. Also, I'm hungry again.
Thursday, March 28, 2013
D is for...
D is for Dependency Inversion Principle.
This principle states two things. The first is that "high-level modules should not depend on a low-level modules." Instead, "both should depend on abstractions." The second is that "abstractions should not depend on details." In fact, "details should depend upon abstractions." This is a principle that I thought I understood until I sat down to write this post. It seems I was getting it slightly confused with Dependency Injection.
The idea is that changes made to low-level modules should not ripple up and disturb the high-level modules resting on top of them. The high-level module should depend in an abstraction, like an interface, instead of on a specific implementation of a low-level module. There is no way to eliminate ripples of change, but they can be confined to a minimum number of modules.
I will again be referring to my http server in this example. I keep coming back to Java to explain these principles because they are much easier to see with explicit interfaces.
In my server, I have a router that holds all of the possible routes that a request can take. This lives inside of and was also initialized by my server class. In order to make my server more flexible, I passed the router (complete with routes) into the server when the server was created. This is where I confused inversion with injection. I had merely altered the order in which the server and router objects were created. For my server, as it stands, this is good enough.
In order to truly invert the dependency, I would need to define a router interface and use that in the server. The interface to the router would be a part of the server and changes to the router should not affect the interface. Doing this would allow my server to remain unchanged even if I substituted an entirely new router in. In fact, I may have to make this change in the future. I'll wait until a real need arises though.
I feel as though I may have still gotten this one wrong, so please correct me if I am mistaken.
This principle states two things. The first is that "high-level modules should not depend on a low-level modules." Instead, "both should depend on abstractions." The second is that "abstractions should not depend on details." In fact, "details should depend upon abstractions." This is a principle that I thought I understood until I sat down to write this post. It seems I was getting it slightly confused with Dependency Injection.
The idea is that changes made to low-level modules should not ripple up and disturb the high-level modules resting on top of them. The high-level module should depend in an abstraction, like an interface, instead of on a specific implementation of a low-level module. There is no way to eliminate ripples of change, but they can be confined to a minimum number of modules.
I will again be referring to my http server in this example. I keep coming back to Java to explain these principles because they are much easier to see with explicit interfaces.
In my server, I have a router that holds all of the possible routes that a request can take. This lives inside of and was also initialized by my server class. In order to make my server more flexible, I passed the router (complete with routes) into the server when the server was created. This is where I confused inversion with injection. I had merely altered the order in which the server and router objects were created. For my server, as it stands, this is good enough.
In order to truly invert the dependency, I would need to define a router interface and use that in the server. The interface to the router would be a part of the server and changes to the router should not affect the interface. Doing this would allow my server to remain unchanged even if I substituted an entirely new router in. In fact, I may have to make this change in the future. I'll wait until a real need arises though.
I feel as though I may have still gotten this one wrong, so please correct me if I am mistaken.
Wednesday, March 27, 2013
L is for...
L is for Liskov Substitution Principle
This principle essentially states that for a class N and a subclass of N called O then O can be substituted for N without breaking the program. Following this principle can help a program respect the Open/Closed principle. For this post, I have two examples. One where I successfully followed this principle and another where I fell into a classic trap.
Let's start with success. This example is again my responders in my http server. All of the responders implement a responder interface. Because they all do this, they are each interchangeable with the responder interface. Java confirms this by letting me use the interface as a function argument and not exploding when I instead pass in a specific responder.
This does not mean that all I had to do to follow this principle was to implement an interface. I had sorta violated it during a small presentation I gave on code smells, though I didn't know it at the time. During that presentation, I said that a square and a rectangle shared enough class data to be derived from a common class. After all, a square is a rectangle, right?
Without knowing it, probably because I hadn't read PPP yet, I had fallen into a classic trap. Mathematically a square is a rectangle but not in terms of setting attributes on a class. A square really only has one attribute, so updating the width also updates the height. On a rectangle, those two attributes can be updated independently.
The problem comes when I want to pass a square into a function that takes a rectangle. What should I expect setting the height to do? If it were a rectangle, then setting the height would not change the width. For a square, changing one changes the other. The confusion here is evidence that the proposed relationship between a square and a rectangle violates the Liskov Substitution Principle. Let's hope I can avoid that mistake in the future.
This principle essentially states that for a class N and a subclass of N called O then O can be substituted for N without breaking the program. Following this principle can help a program respect the Open/Closed principle. For this post, I have two examples. One where I successfully followed this principle and another where I fell into a classic trap.
Let's start with success. This example is again my responders in my http server. All of the responders implement a responder interface. Because they all do this, they are each interchangeable with the responder interface. Java confirms this by letting me use the interface as a function argument and not exploding when I instead pass in a specific responder.
This does not mean that all I had to do to follow this principle was to implement an interface. I had sorta violated it during a small presentation I gave on code smells, though I didn't know it at the time. During that presentation, I said that a square and a rectangle shared enough class data to be derived from a common class. After all, a square is a rectangle, right?
Without knowing it, probably because I hadn't read PPP yet, I had fallen into a classic trap. Mathematically a square is a rectangle but not in terms of setting attributes on a class. A square really only has one attribute, so updating the width also updates the height. On a rectangle, those two attributes can be updated independently.
The problem comes when I want to pass a square into a function that takes a rectangle. What should I expect setting the height to do? If it were a rectangle, then setting the height would not change the width. For a square, changing one changes the other. The confusion here is evidence that the proposed relationship between a square and a rectangle violates the Liskov Substitution Principle. Let's hope I can avoid that mistake in the future.
O is for...
O is for Open/Closed Principle.
This principle states that classes, modules, functions, etc. should be "open for extension, but closed for modification." In order to add new functionality to the software, one should not have to change the existing code. One should only need to add the new code with the desired functionality.
One way this principle manifests is with interfaces. Defining an interface and using that, instead of the implementations directly, allows the code that uses the interface to remain unchanged when new implementations are added. This is much easier to visualize in Java, where interfaces are explicitly defined, than in Ruby.
An example of where I have used this principle in my code is in the responders in my Java http server. Credit must go to Rick for our talk that moved me in this direction. In my server, there is a responder interface that defines a single respond method, which all responders must implement. The respond method takes in a request and returns a response. Each responder processes the requests differently. This allows me to have a FileSystemResponder, a RedirectResponder, or any kind of responder I want.
Adding these new responders does not change my existing code. The code depends on the responder interface and, as long as that interface doesn't change, my code doesn't care what kind of new responder I add. Because of this, my server can be made to respond in a new way with relatively little work. If I didn't use the interface, then my server might be limited to responding in a single way or require code changes for every responder.
Following this principle has made my server much more flexible and easily extendable.
This principle states that classes, modules, functions, etc. should be "open for extension, but closed for modification." In order to add new functionality to the software, one should not have to change the existing code. One should only need to add the new code with the desired functionality.
One way this principle manifests is with interfaces. Defining an interface and using that, instead of the implementations directly, allows the code that uses the interface to remain unchanged when new implementations are added. This is much easier to visualize in Java, where interfaces are explicitly defined, than in Ruby.
An example of where I have used this principle in my code is in the responders in my Java http server. Credit must go to Rick for our talk that moved me in this direction. In my server, there is a responder interface that defines a single respond method, which all responders must implement. The respond method takes in a request and returns a response. Each responder processes the requests differently. This allows me to have a FileSystemResponder, a RedirectResponder, or any kind of responder I want.
Adding these new responders does not change my existing code. The code depends on the responder interface and, as long as that interface doesn't change, my code doesn't care what kind of new responder I add. Because of this, my server can be made to respond in a new way with relatively little work. If I didn't use the interface, then my server might be limited to responding in a single way or require code changes for every responder.
Following this principle has made my server much more flexible and easily extendable.
Tuesday, March 26, 2013
S is for...
This is the first of five posts about my foray into the SOLID principles. I decided to start with S, but later letters may be out of order.
S is for Single Responsibility Principle.
This principle states that there should be one reason for a class or module to change. While it sounds simple enough, I have violated this principle. Like most of my examples, this one comes from my Ruby Tic-Tac-Toe application. Specifically, it comes from an early implementation of my board class.
A long time ago (January), when I began building my game board I gave to it the ability to store the positions of player pieces. Then, when I needed to draw the board, I gave it the ability to convert itself into a formatted string to print to the console. Still later, I allowed it to check itself for winners or a draw so that I could see if the game should be over. All of this functionality was packed into a single class.
Not only did I violate SRP, I did it twice in the same class. Actually, I'm sure there are a lot of other principles violated and designs mangled...but that's not the point of this. The good news is that adding features caused me to right this wrong before I was given reading on SRP.
The fix came when I was adding my Qt gui. The goal was to add another gui to my game while maintaining support for the console version. My console version benefited from the string representation of my board, but Qt (and probably ever other kind of gui) did not. I decided to move the string formatting into the console-only portion of my code. I can now see how bad this could have been. If Ruby were a compiled language, then every time my console representation changed all other versions would need to be recompiled. That doesn't sound efficient at all.
I forget exactly why, but I also moved the winner/draw checking code into its own rules class. I think I was in a cleaning mood and removing it made my board feel simpler. However that happened, I was left with a board that only kept track of the pieces on it. The only reason it would need to change in the future is if I decided to store the pieces in a different way.
I'm glad now for two reasons. The first is that I fixed my code. The second is that I understand why it was important that I fixed it. I'm going to be going back into that code soon and the easier it is to work with the better that's going to make my life.
S is for Single Responsibility Principle.
This principle states that there should be one reason for a class or module to change. While it sounds simple enough, I have violated this principle. Like most of my examples, this one comes from my Ruby Tic-Tac-Toe application. Specifically, it comes from an early implementation of my board class.
A long time ago (January), when I began building my game board I gave to it the ability to store the positions of player pieces. Then, when I needed to draw the board, I gave it the ability to convert itself into a formatted string to print to the console. Still later, I allowed it to check itself for winners or a draw so that I could see if the game should be over. All of this functionality was packed into a single class.
class Board
# square methods
def to_s
# formatting code
end
def game_over?
# rules checking
end
end
Not only did I violate SRP, I did it twice in the same class. Actually, I'm sure there are a lot of other principles violated and designs mangled...but that's not the point of this. The good news is that adding features caused me to right this wrong before I was given reading on SRP.
The fix came when I was adding my Qt gui. The goal was to add another gui to my game while maintaining support for the console version. My console version benefited from the string representation of my board, but Qt (and probably ever other kind of gui) did not. I decided to move the string formatting into the console-only portion of my code. I can now see how bad this could have been. If Ruby were a compiled language, then every time my console representation changed all other versions would need to be recompiled. That doesn't sound efficient at all.
class Board
# square methods
def game_over?
# rules checking
end
end
class ConsolePresenter
def self.format_board(board)
# formatting code
end
end
I forget exactly why, but I also moved the winner/draw checking code into its own rules class. I think I was in a cleaning mood and removing it made my board feel simpler. However that happened, I was left with a board that only kept track of the pieces on it. The only reason it would need to change in the future is if I decided to store the pieces in a different way.
class Board
# square methods
end
class Rules
def self.game_over?(board)
# checking rules
end
end
class ConsolePresenter
def self.format_board(board)
# formatting code
end
end
I'm glad now for two reasons. The first is that I fixed my code. The second is that I understand why it was important that I fixed it. I'm going to be going back into that code soon and the easier it is to work with the better that's going to make my life.
Wednesday, March 20, 2013
Overdue
It's been a while since my last post and it feels like I've done a lot of work. My web server now can parse querystrings and has threading. I've almost completed all of cob spec. I feel like I know the test suite pretty well now after going over every section and updating it. Now all of the test configuration lives in one place and it's obvious for apprentices new to the project how to set the necessary paths. Another bonus is that all of the tests live in a single suite. They're subdivided so the the threaded ones don't need to be run if you only want the single threaded tests. All in all, it's an improvement. There's still work to be done though. I need to finish up passing the test that Rylan and I wrote today.
Oh, a note on threading. I've found that more threads don't mean better performance. My server seems to do better using one thread per cpu core than 50 threads. For my current laptop that means 2 threads. I found some code though that lets me detect how many cores the jvm has available. The line is Runtime.getRuntime().availableProcessors(). That way if I run the server on a computer with more cores, I can easily take advantage of that fact.
Oh, a note on threading. I've found that more threads don't mean better performance. My server seems to do better using one thread per cpu core than 50 threads. For my current laptop that means 2 threads. I found some code though that lets me detect how many cores the jvm has available. The line is Runtime.getRuntime().availableProcessors(). That way if I run the server on a computer with more cores, I can easily take advantage of that fact.
Tuesday, March 12, 2013
Cob Spec Woes
I've been making progress on my Java server. There is a little more refactoring to go for the latest feature I implemented. After that I've got one more feature to add and I've "finished" with the single threaded portion. Finished is in quotes because two of the tests are passing but not actually testing anything. The tests for simple put and post don't actually test what they're supposed to. I made them pass by serving up an empty file at the appropriate url. That doesn't sound like a great test.
It seems like my contribution to cob spec is not going to be an additional test. It is going to be fixing the broken tests that are currently there. That reminds me, I've also got to fix the multi-threaded portion of the tests. Then I can start on threading each request that comes in. I've got a lot of green tests but so much more work to do. It is interesting though because I've never had to dig into code that I didn't write so much before. It's a much different experience than only dealing with one's own code. There's also a much steeper learning curve.
It seems like my contribution to cob spec is not going to be an additional test. It is going to be fixing the broken tests that are currently there. That reminds me, I've also got to fix the multi-threaded portion of the tests. Then I can start on threading each request that comes in. I've got a lot of green tests but so much more work to do. It is interesting though because I've never had to dig into code that I didn't write so much before. It's a much different experience than only dealing with one's own code. There's also a much steeper learning curve.
Monday, March 4, 2013
Serving Images
Today I tried to finish up serving images up over my server. I had previously managed to read files into a byte array. Sending that over to the client was easy, but I had to route the request first. That turned out to be easier than I though. For now, I'm checking if the file exists and returning the appropriate response headers. If it doesn't, I return 404 header. One nice thing about reading everything into a byte array is that I don't have to do separate processing for text or images. So I am able to serve html files as well now.
I still haven't settled on how I want to handle 404s though. I can either do them as a file that is read or I can generate them in my server. Not sure which is better but I'm leaning towards files. That would allow me to specify two locations, a default and an override location. That would allow someone running my server to create their own custom messages.
Tomorrow looks to be finishing this up and probably moving on to directory responses. It seems a logical jump from serving files. I'll also be working on my presentation on code smells. I still need some good examples and I'm finding it hard to write code that it bad in the specific ways I want. Maybe something to do would be to look at old code that I wrote in college. That sounds scary though.
I still haven't settled on how I want to handle 404s though. I can either do them as a file that is read or I can generate them in my server. Not sure which is better but I'm leaning towards files. That would allow me to specify two locations, a default and an override location. That would allow someone running my server to create their own custom messages.
Tomorrow looks to be finishing this up and probably moving on to directory responses. It seems a logical jump from serving files. I'll also be working on my presentation on code smells. I still need some good examples and I'm finding it hard to write code that it bad in the specific ways I want. Maybe something to do would be to look at old code that I wrote in college. That sounds scary though.
Subscribe to:
Posts (Atom)