• Post Reply Bookmark Topic Watch Topic
  • New Topic

Question about software structure  RSS feed

 
Aline Galea
Greenhorn
Posts: 22
2
IntelliJ IDE Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello everyone,

I just finished my beginner java course and I decided to try coding a small application to use what I've learned. I figured I could do this in maybe a day, but I'm already scratching my head and I haven't written a line of code yet.

What I'm trying to do: A work breakdown structure editor.
It's a tool to structure project items in the early stages of project planning. It has a hierarchy of different components representing parts of project work. Lowest level components are "work packages", higher level components are "elements". The number of levels can vary and is up to the user.

I'm trying to define the code structure and here is what I thought of so far:

Option 1:

Option 1 means I just have components with different states, and work package isn't a different kind of object, just a particular state of a component object. Very easy to make an element into a work package and vice versa. The user adds components and lowest level is always considered a work package. However, there are things that elements and work packages will need to do differently if I later implement additional features like cost estimates. All those features would have to check if the component is a work package or not. Might get messy at some point.

Option 2:

Option 2 means I can neatly handle elements and work packages separate and give each their own features. But what if a user decides to change the structure in the middle and to break it down to a lower level? I can't make a work package into an element, I need to delete objects and create new ones instead, so a bit more complicated.

Option 2 still feels a bit better regarding the concern of adding more features later, but it definitely complicates the process of creating and changing the structure without leaving it in an illegal state (lowest level component not a work package). On the other hand, maybe I let this up to the user and just signal "hello, you are missing a work package here"?

I'm trying to get a grasp of proper software design and I would really like your opinion on this.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are three essays by Jack Reeves about how Code is Design. You might want to read that first before reading the rest of this reply. In summary, Reeves proposes that the act of writing code is not "implementation" as many commonly regard it but rather, it is a design activity. I happen to buy into this philosophy.

Therefore, you can't come up with a design by just drawing nice pictures. Pictures are only useful to the extent that they can give you a starting context from which you can extend your design thinking into the details. The best way to hash out a design is to write code and see it evolve in front of your eyes. The best way to evolve code is to test it as you experiment with options and tweak your understanding of what your code needs to do. For me, it's very much like the mindset of a sculptor who looks at a block of marble and sees the figure already inside it, waiting to be revealed. The sculptor's job is not to make the figure, it is to remove the marble that is not part of the figure. When all is said and done, it is what remains that matters.

Ok, so enough with the philosophy and down to the nitty-gritty. A WBS is a tree structure. So, I would start there. Elements of a Tree have to be the same general type. That is, if you have a Tree<Component>, then everything in the tree must be a Component. This would imply Option 2. Option 1 does not seem right in this context.

Next, I would start experimenting with a small implementation. I would write unit tests that exemplify how I would use a WBS and its elements. I would identify different uses cases I want to handle and look for a few that seem like they would have architecturally significant implications. When I have something that looks decent, I would try to expand the implementation incrementally and do more experiments. I would be especially watchful of any kind of pain or ugliness that extending the base design would cause. Whenever I see any ugliness, I will refactor the design to eliminate the ugliness. This process continues, with small increments being added as testing and refactoring drives my progress forward.
 
Stephan van Hulst
Saloon Keeper
Posts: 7993
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Warning: The following might be a bit advanced if you've just completed a beginner course. Maybe it's useful to you.

I would use a combination of the visitor and the strategy patterns for this one.

What this means is that your Component should have a Role, which represents the specific type of component, and it should have a method that accepts a Visitor. A Visitor represents a custom operation that you can perform on specific types of Roles.

Here's roughly what it looks like:

As an example, ElementRole can hold the sub-components of the component it represents. You can implement its accept() method by passing 'this' to the visitor's visit(ElementRole) method.

You can change a work package component to an element component by letting a visitor that represents the subdivide operation call a divide() method on a WorkPackageRole, which in turn can call the reassignRole() method of its associated Component.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan's suggestion is reasonable and it might even turn out to be one of the best choices to follow. The approach of starting right off with general patterns like Visitor and Strategy can save you a lot of time but you need a good grasp of the subtleties and details involved. On the other hand, if you're not familiar with the subtleties and details of these patterns, even just the outline given can start to confuse and mislead you. 

Take this part, for example:
Stephan wrote:
As an example, ElementRole can hold the sub-components of the component it represents. You can implement its accept() method by passing 'this' to the visitor's visit(ElementRole) method.

You can change a work package component to an element component by letting a visitor that represents the subdivide operation call a divide() method on a WorkPackageRole, which in turn can call the reassignRole() method of its associated Component.

Do you understand any of that? Even after reading it a few times, I still go, "Hmmm... I wonder what that code would look like and what its implications are." So, for me it still goes back to needing to write tests and experiment with the API in the context of specific scenarios of usage. I would strongly advise against trying to come up with a full design without writing any code and tests to validate your ideas as you form an understanding of what your program needs/wants to do.
 
Junilu Lacar
Sheriff
Posts: 11494
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Somewhat related to using patterns, you might want to look at other implementations of Tree structures for some insights and inspiration. An XML Document, for example, has similar concepts and relationships and the DOM provides ways to treat Nodes as either children or parents, individual elements or subtrees, etc. You might even consider using a DOM as the underlying structure and just provide a domain-specific layer on top of it so that the names and semantics more closely align with that of a WBS.
 
Aline Galea
Greenhorn
Posts: 22
2
IntelliJ IDE Java Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, that makes sense.
You've given me a lot to think about, both regarding the design possibilities and my general approach. I'll start with a simple implementation and tests, and work my way from there.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!