So when you try to educate yourself for Single Responsibility Principle, you will most likely encounter definitions like "One method should do just one thing." and "One class should be just one reason to change". And then there are always bunch of toy examples like
class Dog {
String bark() {
return "Woof";
}
}
But I find it very hard to apply this principle in Enterprise Application Development.
We have an application where we have "Project Elements", "Activities" and "Employees". An Employee will have many Activities, and an Activity can have one Project Element.
Some Employees are assigned to all Project Elements, some are only assigned to a bunch only. A Project Element can be removed from an Employee and new ones can be assigned. Employee can only add new Activities with Project Elements assigned to her. If no Project Elements are assigned, this means all are available.
A client of us had a requirement, they wanted to see a List of favorite Project Elements when adding new Activities. It does not matter how an Employee favorites a Project Element, it is a different View..
The Favorite Project elements must be ordered by some interesting rules. It depends on the total calculated work of Activities where a Favorite Project Element exists, only last 60 days being considered. At least it is a concrete requirement..
So it was my duty to implement this, and here is the implementation I have:
public List<ProjectElement> getFavoriteProjectElementsSortedDescendingByTotalWorkHoursInLast60Days(Employee owner) {
// All Favorite Project Elements of Owner
final List<ProjectElement> favoriteProjectElementsOfOwner
= (List<ProjectElement>) (List<?>) favoriteBusinessObjectHelper.getAllFavoriteObjectsForBusinessObjectType(BusinessObjectType.PROJECT_ELEMENT.toInt());
// Activities by Favorite Project Elements
final List<Activity> favoriteProjectElementActivitiesForLast60Days
= activityFinder.findByInProjectElementsForLastGivenDates(owner, favoriteProjectElementsOfOwner, 60);
// Create a Map with Favorite Project Element - Calculated Work
final Map<ProjectElement, Long> projectElementTotalWorkMap = new HashMap<ProjectElement, Long>();
for (Activity activity : favoriteProjectElementActivitiesForLast60Days) {
final ProjectElement activityProjectElement = activity.getProjectElement();
if (!projectElementTotalWorkMap.containsKey(activityProjectElement)) {
projectElementTotalWorkMap.put(activityProjectElement, 0L);
}
final long calculatedWork = activity.getCalculatedWork();
final long totalCalculatedWork = projectElementTotalWorkMap.get(activityProjectElement) + calculatedWork;
projectElementTotalWorkMap.put(activityProjectElement, totalCalculatedWork);
}
// Sort the Map by value descending
final Map<ProjectElement, Long> sortedProjectElementTotalWorkMap
= InnboundSortTool.sortByValueDescending(projectElementTotalWorkMap);
// We do not want to show owners Favorite Project Element in the sidebar, if the Project Element is not available
// for Employee anymore.. See the comments at the end of the file.
final Set<ProjectElement> allowedProjectElementsForOwner = owner.getExplicitlyAssignedOnlyActiveProjectElements();
final ArrayList<ProjectElement> projectElementsSorted = new ArrayList<ProjectElement>();
for (ProjectElement projectElement : sortedProjectElementTotalWorkMap.keySet()) {
if (allowedProjectElementsForOwner.size() == 0) { // This means Employee does not have any restrictions, all Project Elements are available to him.
projectElementsSorted.add(projectElement);
} else { // If Employee has assigned Project Elements, we must check if the Favorite Project Element is assigned to him..
if (allowedProjectElementsForOwner.contains(projectElement)) {
projectElementsSorted.add(projectElement); // If yes, add it to list, if no simply continue the loop without adding.
}
}
if (projectElementsSorted.size() == 20) {
break; // 20 is an arbitrary value, we do not want to show too many Favorite Project Elements in the UI.. Limit by 20.
}
}
return projectElementsSorted;
}
Whoa, that is one big method, but it gets the job done. But it does not do one thing, does it? But if every method only does one thing, who is going to do the whole thing?
Do I introduce a Helper class and delegate everything to the that class and start calling:
final Map<ProjectElement, Long> projectElementTotalWorkMap = helper.CreateprojectElementTotalWorkMap();
helper.removeUnassignedFavoriteProjectElementsFromEmployee();
etc? But then do I introduce a Helper to Helper itself? Where does it even end? When I start refactoring like this, I end up having extremely useless methods, which just call other methods, and this class will look like:
List<ProjectElement> favoritesList;
favoritesList = helper.doThis();
favoritesList = helper.doThat();
favoritesList = helper.sort();
return favoritesList;
Do I not understand this principle at all? I guess I do not, so here is the question, how should I fix this method so that it adheres to "SRP"?
Aucun commentaire:
Enregistrer un commentaire