I'm new to DDD and I am working on my first project, which is for an online golf outing registration process. my requirements are pretty simple. users register for the outing and can optionally add a foursome. they can also sponsor a hole with a message and a few other things, but i want to hash our the foursome stuff first.
so, my first though my aggregate contains the a registration entity, foursome value object (which contains a team name and 4 player value objects).
when designing the api, i'm thinking the following pseudo code:
Registration reg = new Registration();
Foursome foursome = reg.CreateFoursome("My Team");
foursome.Player1.Assign("John Doe", 5, ShirtSize.XL);
reg.Register();
My question is, one of the internal components of the aggregate is being exposed to the client code, so am I opening my self up for issues? any flaws with this simple design or alternative apis?
any help would be great as i am in a state of analysis paralysis right now!
thanks
Lets start with Aggregate definition:
A cluster of associated objects that are treated as a unit for the
purpose of data changes. External references are restricted to one
member of the Aggregate, designated as the root. A set of consistency
rules applies within the Aggregate's boundaries.
Aggregate is a group of objects that you would not want multiple users to edit at the same time because it can break domain invariants. Aggregate is also a life cycle unit. It is hard to answer your question without knowing what these invariants, consistency and life cycle rules are. Would creating two Foursomes on the same Registration be bad? Would Foursome with unassigned Player1 be invalid/inconsistent? Would not calling Register on Registration object will 'corrupt' it? If one of the the answers is true then you should not expose your objects like that. This code should be hidden inside your aggregate.
It also looks like Foursome is not a Value Object because it is mutable. It maybe an entity that should be protected by Registration aggregate root.
// PlayerInfo is a value object
public static Registration CreateNew(String foursomeName, PlayerInfo player1, ...) {
if (foursomeName == null) {
throw new ArgumentNullException("foursomeName");
}
if (player1 == null) {
throw new ArgumentNullException("player1");
}
Registration reg = new Registration();
Foursome foursome = reg.CreateFoursome("My Team");
foursome.Player1.Assign(player1);
if(player2 != null) {
foursome.Player2.Assign(player2);
}
reg.Register();
// return consistent and valid Registration instance
return reg;
}
Again, this can be not what you want, it really depends on your domain model. Maybe your Aggregate root should be an entity like FoursomeRegistartion. Maybe Players are aggregates themselves if they can exist outside Foursome/Registration boundary. As others have said, it is hard to get model right the first time. Have a first implementation and refactor continuously.
For a first shot it isn't bad. It is important when starting design not to get too hung up on the small details. How much time you spend worrying about the robustness of the design is going to be primarily a factor of the project's importance. You will continually learn as you build, and over time, your old code will require refactoring to enable new details.
Take for instance, your FourSome class I assume has four players. Could you instead have a Team class which has a Size constraint, such that a Players collection could be constrained to that number of players? Should there be a Player class (or perhaps that is the type of Player1?)?
The answers to these questions will have implications toward the extensibility of your system.
I encourage you to write each of your scenarios into tests (you could use user stories or use cases too, but developers like to write code), and as you write the tests, fill in the Registration, Player, and Foursome/Team class implementation to make the tests succeed. As you expand your system, your tests will change, and so will your design.
Post Addition 1:
Domain driven design is intended to be an approach to developing the classes and data structures your application will use such that it "models" the problem domain. In your case, you are working with a Golf Outing Registration system. Therefore, as you think about the entities which might make up such a system, you might describe how a Team Captain registers his/her Team (including other Players) by providing his Registration. The registration might be for an Event, which itself may have details such as Organizer, Sponsor, etc. As you see, each of the "capitalized" names become your entities (classes). At least for the first draft of your design. As you discover more information about the relationships between your classes, especially in how they interact (a Player is added to a team), you will flesh out the methods of your class.
During this process you can inadvertently introduce design flaws. For instance, a FourSome is, technically, a type of Team limited to four players. Does it make sense to derive a class from Team and set a limit of four players, or does it make sense to put a constraint on Team? That is a design decision determined by... your business rules and you. Is it a mistake to take one approach over the other? Time will tell, as you will need to constantly refactor in order to expand the system.
You will find many patterns during your design process that may make your design process easier, but a new designer typically does not have the experience to recognize when to use them. If you do, kudos to you. You will not find a perfect design the very first time you are designing. I still look back (15 years now) at designs I thought were awesome, and shake my head at my youthful exuberance.
You should describe your problem (to yourself or on paper). Underline the nouns. They are your candidate classes. Tell a story for each user interaction with the system, and the verbs should get you started toward what the methods are on each class. Avoid using the Registration to do all the work, but separate the responsibility of the classes to where it is appropriate. For instance, you can add a player to a team, or you can have a player add itself to a team. Determining where that responsibility lies should be guided (but not dictated) by the SRP, among other design guidance.
Finally, there is no right answer in design. I could tell you based on my extensive design experience but limited golf experience what I THINK it should be, but ultimately your best design depends on the features, scope, and design goals (like extensibility). Start with your best shot, write tests against it, and your design flaws will emerge before you know it. :D
Post-Revision 2:
I think you are reading too much into Eric Evan's guidance. I don't believe he is saying that you can't expose Player from Foursome.
Related
In some projects I see that a dummy record is needed to create in Db in order to keep the business logic go on without breaking the Db constraints.
So far I have seen its usage in 2 ways:
By adding a field like IsDummy
By adding a field something called ObjectType which points a type: Dummy
Ok, it helps on what needs to be achieved.
But what makes me feel alert on such solutions is sometimes you have to keep in mind that some dummy records exist in the application which needs to be handled in some processes. If not, you face some problems until you realize their existence or until someone in the team tells you "Aha! You have forgotten the dummy records. You should also do..."
So the question is:
Is it a good idea to create dummy records to keep business logic as it is without making the Db complain? If yes, what is the best practice to prevent developers from skipping their existence? If not, what do you do to prevent yourself from falling in a situation where you end up with an only option of creating a dummy record?
Thanks!
Using dummy records is inferior to getting the constraints right.
There's often a temptation to use them because using dummy records can seem like the fastest way to deliver a new feature (and maybe sometimes it is), but they are never part of a good design, because they hide differences between your domain logic and data model.
Dummy records are only required when the modeller cannot easily change the Database Definition, which means the definition and/or the data model is pretty bad. One should never end up in a situation where there has to be special code in the app layer to handle special cases in the database. That is a guaranteed maintenance nightmare.
Any good definition or model will allow changes easily, without "affecting existing code".
All business logic [that is defined in the Database] should be implemented using ANSI SQL Constraints, Checks, and Rules. (Of course Lower level structures are already constrained via Domains/Datatypes, etc., but I would not classify them as "business rules".) I ensure that I don't end up having to implement dummies, simply by doing that.
If that cannot be done, then the modeller lacks knowledge and experience. Or higher level requirements such as Normalisation, have been broken, and that presents obstacles to implementing Constraints which are dependent on them; also meaning the modeller failed.
I have never needed to break such Constraints, or add dummy records (and I have worked on an awful lot of databases). I have removed dummy records (and duplicates) when I have reworked databases created by others.
I've never run across having to do this. If you need to do this, there's something wrong with your data structure, and it's going to cause problems further down the line for reporting...
Using Dummies is dumb.
In general you should aim to get your logic right without them. I have seen them used too, but only as an emergency solution. Your description sounds way too much like making it a standard practice. That would cause more problems than it solves.
The only reason I can see for adding "dummy" records is when you have a seriously bad app and database design.
It is most definitely not common practice.
If your business logic depends on a record existing then you need to do one of two things: Either make sure that a CORRECT record is created prior to executing that logic; or, change the logic to take missing information into account.
I think any situation where something isn't very easily distinguishable as "business-logic" is a cause for trying to think of a better way.
The fact that you mention "which points a type: Dummy" leads me to believe you are using some kind of ORM for handling your data access. A very good checkpoint (though not the only) for ORM solutions like NHibernate is that your source code VERY EXPLICITLY describes your data structures driving your application. This not only allows your data access to easily be managed under source control, but it also allows for easier debugging down the line should a problem occur (and let's face it, it's not a matter of IF a problem will occur, but WHEN).
When you introduce some kind of "crutch" like a dummy record, you are ignoring the point of a database. A database is there to enforce rules against your data, in an effort to ELIMINATE the need for this kind of thing. I recommend you take a look at your application logic FIRST, before resorting to this kind of technique. Think about your fellow dev's, or a new hire. What if they need to add a feature and forget your little "dummy record" logic?
You mention yourself in your question feeling apprehension. Go with your gut. Get rid of the dummy records.
I have to go with the common feeling here and argue against dummy records.
What will happen is that a new developer will not know about them and not code to handle them, or delete a table and forget to add in a new dummy record.
I have experienced them in legacy databases and have seen both of the above mentioned happen.
Also the longer they exist the harder it is to take them out and the more code you have to write to take into account these dummy records which could probably have been removed if you just did the original design without them.
The correct solution would be to update your business logic.
To quote your expanded explanation:
Assume that you have a Package object and you have implement a business logic that a Package without any content cannot be created. YOu created some business layer rules and designed your Db with relevant constraints. But after some years a new feature is requested and to accomplish that you have to be able to create a package without a contnent. To overcome this, you decide to create a dummy content which is not visible on UI but lets you to create an empty package.
So the at one time to a package w/o content was invalid thus business layer enforced existence of content in a package object. That makes sense. Now if the real world scenario has changed such there is now a need VALID reason to create Package objects without content it is the business logic layer which needs to be changed.
Almost universally using "dummy" anything anywhere is a bad idea and usually indicates an issue in implementation. In this instance you are using dummy data to allow "compliance" with a business layer which is no longer accurately representing the real world constraints of the business.
If package without content is not valid then dummy data to allow "compliance" with business layer is a foolish hack. In essence you wrote rules to protect your own system and then how are attempting to circumvent your own protection. On the other hand if package without content is valid then business layer shouldn't be enforcing bogus constraints. In neither instance is dummy data valid.
I know, this probably wins the award for longest and most confusing question title. Allow me to explain...
I am trying to refactor a long-running batch process which, to be blunt, is extremely ugly right now. Here are a few details on the hard specifications:
The process must run several times (i.e. in the tens of thousands);
Each instance of the process runs on a different "asset", each with its own unique settings;
A single process consists of several sub-processes, and each sub-process requires a different slice of the asset's settings in order to do its job. The groups are not mutually exclusive (i.e. some settings are required by multiple sub-processes).
The entire batch takes a very long time to complete; thus, a single process is quite time-sensitive and performance is actually of far greater concern than design purity.
What happens now, essentially, is that for a given asset/process instance, a "Controller" object reads all of the settings for that asset from the database, stuffs them all into a strongly-typed settings class, and starts each sub-process individually, feeding it whichever settings it needs.
The problems with this are manifold:
There are over 100 separate settings, which makes the settings class a ball of mud;
The controller has way too much responsibility and the potential for bugs is significant;
Some of the sub-processes are taking upwards of 10 constructor arguments.
So I want to move to a design based on dependency injection, by loosely grouping settings into different services and allowing sub-processes to subscribe to whichever services they need via constructor injection. This way I should be able to virtually eliminate the bloated controller and settings classes. I want to be able to write individual components like so:
public class SubProcess : IProcess
{
public SubProcess(IFooSettings fooSettings, IBarSettings barSettings, ...)
{
// ...
}
}
The problem, of course, is that the "settings" are specific to a given asset, so it's not as simple as just registering IFooSettings in the IoC. The injector somehow has to be aware of which IFooSettings it's supposed to use/create.
This seems to leave me with two equally unattractive options:
Write every single method of IFooSettings to take an asset ID, and pass around the asset ID to every single sub-process. This actually increases coupling, because right now the sub-processes don't need to know anything about the asset itself.
Create a new IoC container for each full process instance, passing the asset ID into the constructor of the container itself so it knows which asset to grab settings for. This feels like a major abuse of IoC containers, though, and I'm very worried about performance - I don't want to go and implement this and find out that it turned a 2-hour process into a 10-hour process.
Are there any other ways to achieve the design I'm hoping for? Some design pattern I'm not aware of? Some clever trick I can use to make the container inject the specific settings I need into each component, based on some kind of contextual information, without having to instantiate 50,000 containers?
Or, alternatively, is it actually OK to be instantiating this many containers over an extended period of time? Has anybody done it with positive results?
MAJOR EDIT
SettingsFactory: generates various Settings objects from the database on request.
SubProcessFactory: generates subprocesses on request from the controller.
Controller: iterates over assets, using the SettingsFactory and SubProcessFactory to create and launch the needed subprocesses.
Is this different than what you're doing? Not really from a certain angle, but very much from another. Separating these responsibilities into separate classes is important, as you've acknowledged. A DI container could be used to improve the flexibility of both Factory pieces. The implementation details are, in some ways, less critical than improving the design, because once the design is improved, implementation can vary more readily.
When designing both the domain-model and class-diagrams I am having some trouble understanding what to put in them.
I'll give an example of what I mean:
I am doing a vacations scheduler program, that has an Administrator and End-Users. The Administrator does a couple of things like registering End-Users in the program, changing their previleges, etc. The End-User can choose his vacations days, etc.
I initially defined an Administrator and End-User as concepts in the domain-model, and later as classes in the class-diagram.
In the class-diagram, both classes ended up having a couple of methods like
Administrator.RegisterNewUser();
Administrator.UnregisterUser(int id);
etc.
Only after some time I realised that actually both Administrator and End-User are actors, and maybe I got this design totally wrong. Instead of filling Administrator and End-User classes with methods to do what my Use-Cases request, I could define other classes from the domain to do them, and have controllers handle the Use-Cases(actually, I decided to do one for each Use-Case). I could have a UserDatabase.RegisterNewUser() and UserDatabase.UnregisterUser(int id);, for example, instead of having those methods on the Administrator class.
The idea would be to try to think of the whole vacation-scheduler as a "closed-program" that has a set of features and doesn't bother with things such as authentication, that should be internal/protected, being that the only public things I'd let the outside world see would be its controllers.
Is this the right approach? Or am I getting this totally wrong? Is it generally bad idea to put Actors in the domain-model/class-diagrams? What are good rules of thumb for this?
My lecturer is following Applying UML and Patterns, which I find awful, so I'd like to know where I could look up more info on this described actor-models situation.
I'm still a bit confused about all of this, as this new approach is radically different from anything I've done before.
I would not say that your design, as you speculate, is totally wrong, in fact Administrator and End-User are valid domain objects that should be represented somehow in the Class Diagrams. Just because you identify those two entities as actors doesn't mean they should be excluded from the Domain, remember, your domain is your scope, or "relevant context", that is, the set of useful objects that play a relevant role in your solution.
You may start with basic objects that comprise your model, just write them down, without further analysis, like brain storming...
Vacation
Location
Travel Agent
Schedule
User
Reservation
Reservation Service (This can be an interface for accessing the vacation reservation stuff)
Then try to establish the relationships between those objects, if you can not find any relationship that means you are not choosing the right objects, if they are part of the same problem domain then they must be related somehow.
After some time, you will discover that there are objects missing, try to encapsulate as much as possible, and represent the correct abstractions, Design Patterns might help you out with that.
When every possible object is represented with all its properties and methods, then you should have a fully, although not yet finished, functional design.
I know you should have a lot of theory in your mind, so get going, without fear, I myself have used this approach successfully many times at work.
Finally get a copy of UML Distilled
Regards,
I think you should learn more about domain modeling and process of getting from use cases to class diagrams. Actors as classifiers can be part of class diagrams, however for class diagrams used for analysis and design are modeling the system you develop and an actor is external entity. When you are using use cases and use case diagrams, the goal is to identify functional and non-functional requrements, therefore define the scope of the system to develop and external entities - roles or systems - interacting with the system you are developing. In use case diagrams you can find sometimes a box representing system boundary, which encompasses all use cases, which will be realized in your system, but actors are out of the box. When domain modeling, you usually forget about the system altogether, because you want to capture the way the domain works. Often special diagrams and modeling elements are used for domain modeling. As I said, the point is to understand the domain in which the system will be used. Class diagrams in the analysis and design phase describe the system you are developing, so no actors can be inside.
I'm working on a kind of a HMI application and is creating objects to define a specific machine. Lets say this is a car for the sake of argument.
A object for the engine is obvious. There are a few common sensors on the engine, and this is a few objects mounting to a few properties on the engine object. The throttle property is a input of course.
The car has atleast one door. Each door can have a window, it can be openable and it may be electrically operated. If it's electrically operated it will depend on power from the car to operate.
Now, should I expose the door as a property on the car object, or would it be most sensible to keep it private and having the car object operate the door in OpenDoor and RollDownWindow functions? What about events? Should I expose events on the engine, example LowOnOil event, or should I deal with it in the car object witch in turn could have an event like EngineIsLowOnOil?
How would you do this?
This, and all similar questions, can be answered by considering why you are building the model. There is absolutely no point in creating a model in isolation from the problem you are trying to solve, and in general it is not possible to do so.
For example, if you are building an electronic fuel injection control, system, the number of doors on the car (and posibly even the car itself) is of no interest, and should not be modelled.
Let us explore a little your example of opening the door of a car (say the front left). One could take several approaches (including those which you suggest):
Car.OpenFrontLeftDoor
Car.OpenDoor(FRONTLEFT)
Car.Door(FRONTLEFT).Open
Car.Part(DOOR_FRONTLEFT).Open
Car.Part(DOOR_FRONTLEFT).DoAction(OPEN)
None of them is right or wrong, it depends on the situation. I am sure there are many more ways too.
Number 1 is very much a hard-coded function approach. This would be good for very simple, fixed situations. But it would become unmanageable if your model needs to accomodate variation.
Number 5 is taking a parameterised approach. The latter is a lot more flexible and requires a greater design nous to pull off but could be overkill for a simple problem.
Also bear in mind that your car object can present an external interface different to the internal implemenation. For example, you could use approach 5 internally but present an interface such as in 1, and translate the function calls under the hood (no pun intended).
Ultimately the ability to make decisions like this comes from experience. Expose yourself to good OO design, read books, examine the source code of good software. And above all, try different designs out and see for yourself what works and why.
Einstein said "Make it as simple as possible, but no simpler."
Start with an empty object. As you develop the entire model, add to the object only those attributes that are NECESSARY.
I think this is a very generic question that is hard to answer. My best answer would be "It depends on your needs and the problem domain you are trying to solve".
In the scenario you have given I usually tend to think about it in a real life situation.
So the door is not private to the car i.e. the door of the car is publically accessible. The car does not open the door (unless it is a pretty cool car!) a User would open the door. Hence the door should probably be a public property of the car.
In terms of exposing the events, it really depends on whether you intend on handing them. For example, the OnLowOil event is probably an event you would want to be handled i.e. notify the user who would then perhaps do Car.Engine.FillOil
If in doubt, consider the problem from a different approach: "How would I test these objects?" "How would I test the window?" "What would make testing easiest?" Being a lazy programmer, that's a very important question for me to answer. I want writing the tests to be dirt simple, yet highly effective in proving that my code works.
In your case, you have a car with doors that can open and close, and the doors have windows that can open and close, and they may or may not be electrically operated. How would you test the "window-down" function? Is the window's existence dependent upon the engine? Is it even dependent on the car, or is it really dependent only on the door? Do different doors have different shaped windows with different rules or different amounts of travel? Do different doors use identical electric motors to drive the windows, or are the window motors different for left-mounting versus right mounting?
And consider that a customer may give you a requirement that says "the windows only work when the engine is running", but is that really true? In most cars the windows work when the car's power switch is turned to "on". Put another way, is the window operation dependent on a spinning crankshaft in an engine, or is it actually dependent on 12 volts of electricity? So do you really need an engine instance in a car to test a window, or do you just need a battery?
Once you start asking those questions, you're likely to conclude that a power window is deserving of its own set of tests (up/down/part-way/full-travel/etc.), so it becomes a good candidate for being its own class. The number of different doors might be complex, so you figure a "door factory" might be an appropriate class to create that can manage all the different kinds of doors. Testing things in isolation is always easier: look at the harder questions about what the engine throttle setting should be to test the window-up function? What about the transmission gear, or the door open/close state? All these permutations make it hard to test, even though they have no bearing on whether the window works or not. So all these lead me to think the window classes should be tested standalone as much as possible. In the real world, you'd only need 12 volts to test a power window mounted in a door. So in your modeled world, you'd only need a mock or fake power supply object to provide the modeled power, not an engine object or a transmission gear. It's a simpler test.
After you take those sorts of ideas into consideration, you start realizing that passing dependencies in the tests (here's a power supply for the window test) makes them easy to test; thus the way to assemble the real components in your model would mean encapsulating construction in factories would make for the easiest way to create your car; so building the car might suggest the abstract factory pattern be used to inject all the dependencies into the car.
You might even start with a simple-but-brittle Car class with a hard coded Engine and hard coded Doors, and then refactoring it to add tests like those above. You would likely still end up with independent Car, Door, and Window objects, and an abstract factory pattern to create them all based on the model of car being built. This idea is called "emergent design."
I like to keep things simple. In your Domain/Objects think of how you would speak about the object to determine what way to model it, would you say my car needs oil or my car's engine needs oil?
It depends on the domain. The Domain for a car factory would refer to cars differently than a car rental Domain.
I would have numberous window properties for each window and events off them, and a window state/position as well.
There are no right or wrong models; there are models that are more or less useful for your specific purpose.
As others have said, think first on what information is relevant to your needs. And then discard the rest. That process of removing unnecessary detail is called abstraction. If we didn't perform abstraction, our models would be identical to the real-world entities that they represent! Which would be useless, since the ultimate goal of modelling is obtaining a simplified version of reality that allows us to reason about it in its absence.
I think there are several people here making the same point, but I will try again.
You are asking questions like should I or should I not expose "Door Opened" event. There is no answer to this question other than with another one: how are you going to use it
Ultimately the model is the means not the goal and as such the model cannot be defined outside the context. Even (especially) if you are building your model to sell it as a standalone product you have to think how your customers will use it which - again - is a discussion about context.
Trying answering such questions based one anything else (gut feel?) will be an exercise in counting demons on the end of the needle
I apologize for the subjectiveness of this question, but I am a little stuck and I would appreciate some guidance and advice from anyone who's had to deal with this issue before:
I have (what's become) a very large RESTful API project written in C# 2.0 and some of my classes have become monstrous. My main API class is an example of this -- with several dozen members and methods (probably approaching hundreds). As you can imagine, it's becoming a small nightmare, not only to maintain this code but even just navigating the code has become a chore.
I am reasonably new to the SOLID principles, and I am massive fan of design patterns (but I am still at that stage where I can implement them, but not quite enough to know when to use them - in situations where its not so obvious).
I need to break my classes down in size, but I am at a loss of how best to go about doing it. Can my fellow StackOverflow'ers please suggest ways that they have taken existing code monoliths and cut them down to size?
Single Responsibility Principle - A class should have only one reason to change. If you have a monolithic class, then it probably has more than one reason to change. Simply define your one reason to change, and be as granular as reasonable. I would suggest to start "large". Refactor one third of the code out into another class. Once you have that, then start over with your new class. Going straight from one class to 20 is too daunting.
Open/Closed Principle - A class should be open for extension, but closed for change. Where reasonable, mark your members and methods as virtual or abstract. Each item should be relatively small in nature, and give you some base functionality or definition of behavior. However, if you need to change the functionality later, you will be able to add code, rather than change code to introduce new/different functionality.
Liskov Substitution Principle - A class should be substitutable for its base class. The key here, in my opinion, is do to inheritance correctly. If you have a huge case statement, or two pages of if statements that check the derived type of the object, then your violating this principle and need to rethink your approach.
Interface Segregation Principle - In my mind, this principle closely resembles the Single Responsibility principle. It just applies specifically to a high level (or mature) class/interface. One way to use this principle in a large class is to make your class implement an empty interface. Next, change all of the types that use your class to be the type of the interface. This will break your code. However, it will point out exactly how you are consuming your class. If you have three instances that each use their own subset of methods and properties, then you now know that you need three different interfaces. Each interface represents a collective set of functionality, and one reason to change.
Dependency Inversion Principle - The parent / child allegory made me understand this. Think of a parent class. It defines behavior, but isn't concerned with the dirty details. It's dependable. A child class, however, is all about the details, and can't be depended upon because it changes often. You always want to depend upon the parent, responsible classes, and never the other way around. If you have a parent class depending upon a child class, you'll get unexpected behavior when you change something. In my mind, this is the same mindset of SOA. A service contract defines inputs, outputs, and behavior, with no details.
Of course, my opinions and understandings may be incomplete or wrong. I would suggest learning from people who have mastered these principles, like Uncle Bob. A good starting point for me was his book, Agile Principles, Patterns, and Practices in C#. Another good resource was Uncle Bob on Hanselminutes.
Of course, as Joel and Jeff pointed out, these are principles, not rules. They are to be tools to help guide you, not the law of the land.
EDIT:
I just found these SOLID screencasts which look really interesting. Each one is approximately 10-15 minutes long.
There's a classic book by Martin Fowler - Refactoring: Improving the Design of Existing Code.
There he provides a set of design techniques and example of decisions to make your existing codebase more manageable and maintainable (and that what SOLID principals are all about). Even though there are some standard routines in refactoring it is a very custom process and one solution couldn't be applied to all project.
Unit testing is one of the corner pillars for this process to succeed. You do need to cover your existing codebase with enough code coverage so that you'd be sure you don't break stuff while changing it. Actually using modern unit testing framework with mocking support will lead encourage you to better design.
There are tools like ReSharper (my favorite) and CodeRush to assist with tedious code changes. But those are usually trivial mechanical stuff, making design decisions is much more complex process and there's no so much tool support. Using class diagrams and UML helps. That what I would start from, actually. Try to make sense of what is already there and bring some structure to it. Then from there you can make decisions about decomposition and relations between different components and change your code accordingly.
Hope this helps and happy refactoring!
It will be a time consuming process. You need to read the code and identify parts that do not meet the SOLID principles and refactor into new classes. Using a VS add-in like Resharper (http://www.jetbrains.com) will assist with the refactoring process.
Ideally you will have good coverage of automated unit tests so that you can ensure your changes do not introduce problems with the code.
More Information
In the main API class, you need to identify methods that relate to each other and create a class that more specifically represents what actions the method performs.
e.g.
Let's say I had an Address class with separate variables containing street number, name, etc. This class is responsible for inserting, updating, deleting, etc. If I also needed to format an address a specific way for a postal address, I could have a method called GetFormattedPostalAddress() that returned the formatted address.
Alternatively, I could refactor this method into a class called AddressFormatter that takes an Address in it constructor and has a Get property called PostalAddress that returns the formatted address.
The idea is to separate different responsibilities into separate classes.
What I've done when presented with this type of thing (and I'll readily admit that I haven't used SOLID principles before, but from what little I know of them, they sound good) is to look at the existing codebase from a connectivity point of view. Essentially, by looking at the system, you should be able to find some subset of functionality that is internally highly coupled (many frequent interactions) but externally loosely coupled (few infrequent interactions). Usually, there are a few of these pieces in any large codebase; they are candidates for excision. Essentially, once you've identified your candidates, you have to enumerate the points at which they are externally coupled to the system as a whole. This should give you a good idea of the level of interdependency involved. There usually is a fair bit of interdependency involved. Evaluate the subsets and their connection points for refactoring; frequently (but not always) there ends up being a couple of clear structural refactorings that can increase the decoupling. With an eye on those refactorings, use the existing couplings to define the minimal interface required to allow the subsystem to work with the rest of the system. Look for commonalities in those interfaces (frequently, you find more than you'd expect!). And finally, implement these changes that you've identified.
The process sounds terrible, but in practice, it's actually pretty straightforward. Mind you, this is not a roadmap towards getting to a completely perfectly designed system (for that, you'd need to start from scratch), but it very certainly will decrease the complexity of the system as a whole and increase the code comprehensibility.
OOD - Object Oriented Design
SOLID - class design
Single Responsibility Principle - SRP - introduced by Uncle Bob. Method, class, module are responsible only for doing single thing(one single task)
Open/Closed Principle - OCP - introduced by Bertrand Meyer. Method, class, module are open for extension and closed for modification. Use a power of inheritance, abstraction, polymorphism, extension, wrapper. [Java example], [Swift example]
[Liskov Substitution Principle] - LSP - introduced by Barbara Liskov and Jeannette Wing. A subtype can replace supertype without side effects
Interface Segregation Principle - ISP - introduced by Uncle Bob. Your interface should be as small as possible
[Dependency Inversion Principle(DIP)] - DIP - introduced by Uncle Bob. Internal class, layer should not be depended on external class, layer. For example when you have aggregation[About] dependency you should rather use some abstraction/interfaces. [DIP vs DI vs IoC]
6 principles about packages/modules(.jar, .aar, .framework):
what to put inside a package
The Release Reuse Equivalency
The Common Closure
The Common Reuse
couplings between packages
The Acyclic Dependencies
The Stable Dependencies
The Stable Abstractions
[Protocol Oriented Programming(POP)]