39

When I start a new project, I often times immediately start thinking about the details of implementation. "Where am I gonna put the DataBaseHandler? How should I use it? Should classes that want to use it extend from some Abstract superclass..? Should I use an interface? What level of abstraction am I going to use in my class that contains methods for sending requests and parsing data?"

I end up stalling for a long time because I want to code for extensibility and reusability. But I feel it almost impossible to get past thinking about how to implement perfectly.

And then, if I try to just say "screw it, just get it done!", I hit a brick wall pretty quickly because my code isn't organized, I mixed levels of abstractions, etc.

What are some techniques/methods you have for launching into a new project while also setting up a logical/modular structure that will scale well?

-- EDIT --

Well, this is already the type of question that is difficult to accept an answer to, but wanted to get some more feedback, see if there's some consensus. TDD sounds really cool and, frankly, I've been meaning to get more up to speed on using JUnit, etc. At the same time, what do the fans of TDD think about the fact that one legitimate point with relation to TDD solving my particular issues, is that TDD doesn't really seem to address the question of design. Sure, I agree TDD will help me define what I want to do and then I can gradually work through the how, but there are many different overall design patterns/structures that could all pass through unit testing. That's just it: it tests single UNITS. I guess I'm a bit confused... I dunno. Maybe I'm just trying to procrastinate even more by trying to figure out some magical formula, but I would like to hear how some of the veterans approach this area...

Thanks!

3
  • 2
    Step back, grab a pen and paper, sketch out the bigger picture. this will help you then design the implementation in a more structured way rather than losing your self in the details...
    – Darknight
    Commented Jun 23, 2011 at 8:32
  • This is a great question. This is a trap I have been guilty of falling into as well.
    – Corv1nus
    Commented Jun 23, 2011 at 14:56
  • 1
    Possible duplicate of How do I deal with analysis paralysis?
    – gnat
    Commented Apr 22, 2016 at 13:39

9 Answers 9

18

I recomment using Test-Driven-Development, it takes some getting used to especially when working with a good IDE such as eclipse, but the advantages are great.

Basically what you do is write the tests to your code before you write the code itself. So you are forced to look at your code from the point of view of how it will be used, which means your interfaces evolve the more scenarios you implement.

Another characteristic is that you implement in very small chunks (they grow larger the more experienced you are at the technique and at programming) so it forces you to focus on a very small and well defined problem each time.

And also since you first write a test and only then implement, you have a failing test in front of you. So if you are like most programmers you won't get carried away with crazy analysis because you'll think: "I need to make this test work".

A short java example:
Say I want to develop a program that reads and writes a message from a db.

So I start off with the first well defined action, I need a DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
}

ok, so here I see that I need to implement the DbConnector.getDB class so that it returns the DB, until then this test fails. I go and do that...

Not I add the next thing I wanna do, load the message from the DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
}

Now I've added another small feature to the DB which is to fetch a message, I go and implement that, once finished I keep going one feature at a time until I reach something like this:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
  message = "foo bar";
  db.storeMessage(message);
  message = db.fetchMessage();
  assertEquals("foo bar", message);
}

It might seem like a very simple example, but this works for more complex tasks as well. I know it is very time consuming at first but as you get used to it you see that in fact it is much more efficient. For one you avoid the paralysis by analysis and for another you get much more robust code which usually has less bugs and goes through less iterations.

8
  • 4
    And TDD forces you to refactor a lot, so you're getting into a work mode of continuous refactoring which will help to break through the brick wall of messed code, like programmers.stackexchange.com/questions/86364/… mentioned.
    – cringe
    Commented Jun 23, 2011 at 4:00
  • I actually find the test-first aspect of TDD to be a hindrance in these kinds of circumstances. If I'm having enough trouble designing the interface itself, how is designing the tests going to be any easier or more obvious? That and the refactor burden in the very beginning of trying to design something is far too high. I wonder how others deal with that. Commented Jun 23, 2011 at 4:05
  • 1
    @SnOrfus, right. TDD works well when you've got your modules and want to concentrate on what versus how. But those modules might be organized in any number of ways. How they're grouped together, what kind of structure you're gonna use isn't really being clarified through TDD.
    – LuxuryMode
    Commented Jun 23, 2011 at 4:11
  • 5
    Hmmmm this sounds like a TDD fanboy..... What ever happened to using pen and paper to sketch out an architecture? or am I old fashion and not "hip" enough....
    – Darknight
    Commented Jun 23, 2011 at 8:27
  • 1
    Pen and paper (or whiteboard) is good. Sketch the overall plan, the big picture. If it doesn't fit on a piece of paper, it's too complicated. Once you've got the big picture plan, you can get busy with BDD, mocking, etc. Commented Jun 23, 2011 at 8:37
13

This happens to me, so I have gotten into the habit of accepting (and embracing) a mindset of continual refactoring. I make the simplest thing that could possibly work, then I clean it up, organize it, decouple it, test it and move on.

That's not to say that there isn't much planning going on, but it happens very quickly and more-often as doodles on scrap or in my head. All in all, I sometimes call this little process micro-iterations because they take 5-20 minutes each and from experience it takes 2-3 to finish what I'm working on (depending on what I'm making, obviously).

As a side note: I've tutored a number of people in different forms of writing (reports, essays and technical writing in general) and this is the same way that I get them to write things to overcome writer's block. "Just blurt out anything about your topic that comes to mind onto the page. Then we'll make sense out of it and separate it all into paragraphs and check the flow. If need be, we'll even re-write it."

1
  • 1
    +1 for mentioning writing. I just recently adopted the frequent refactoring approach from coding and applied it to writing; works very well for me. Commented Jun 23, 2011 at 8:46
2

A few things that might work:

  • Identify the core problem you're trying to solve - what is the very heart of the thing you want to do? Implement just that, and the bare minimum of support code to make it run. Once it works to your satisfaction, build up iteratively, refactoring without mercy at each step.
  • See if other programming paradigms work for you. Despite all of its merits, object-oriented programming is not the answer to all problems, and not all programmers' brains work that way. Pick up a (pure) functional language; write some procedural code; dive down to the hardware level and do some C or maybe even assembler; etc. A few languages that might shake up your mind (assuming you're currently using something like C++ / Java / C# / VB / ...): Haskell, ML, Lisp (various dialects to choose from), Erlang, Prolog, Smalltalk, Javascript (if you let go of trying to make it behave like Java and embrace its closure nature instead), C, Pascal, awk, and probably a dozen more. Key feature is that they need to be very different from what you use now. This is not something you want to do on a big project with a lot at stake, but doing it for side projects (personal or work-related) will give you new insights.
  • Use a radically different design method. See if you can pick up the design from a different angle. I assume you usually start designing by laying out your classes; how about you start with data structures for a change? Or how about you design the UI first, literally drawing input forms before designing any functionality?
0
1

For many design decisions it can help to do a "spike" which is a short, time-limited research effort where you can explore some architecture or design options by coding to a throw-away prototype. For example you could explore the use of some open source library or how you will organize your classes and interfaces. They key is to keep it short so that you can try another approach if the first is unsatisfactory and hopefully you will gain enough knowledge in the exercise to better make the architectural decisions or to prove the concept. The exercise itself involves immediate coding which helps to get out of the "writers block" without necessarily committing to the "git 'er done" too early.

After that it is then beneficial to use the TDD or BDD approach that Asaf mentioned to go forward with the implementation of the project.

1
  • +1 I agree. Plan to throw away the first attempt. Treat it as a learning experience. I've thrown away as many as six, before I think I want to stick with the seventh one. Commented Jun 24, 2011 at 2:02
1

You ain't gonna need it, so don't think too much at the beginning.

Invest more time to define, to understand the goal and the problem.

"Extensibility and reusability" is natural outcome of the life cycle of well written software programs.

0

I'll assume that we're looking at a medium size project.
I would start by going on the drawing board. You should have your functional and non functional requirements ready before you do this. You would first come up with the software archtiecture i.e look at any architectural patterns that will suit your requirements
Once you decide on how your archtiecture looks, you should go in to the low level design i,e look at all the entities, classes and functionality. Here, you'll again try and identify design patterns that fits in. In the process, you'll know what your base classes are and the interfaces that you would need
You can then build the framework and run some quick tests to see if this satisfies all your non functional requirements
I would then go with Test Driven Development as @Asaf has suggested.

Remember, In spite of spending good time on design and architecture, always be willing to revisit the architecture if the need arises.

0

I think this is a great question, and nothing will work for everyone. I do think that such paralysis is a natural byproduct of becoming more and more competent in your field. That said, here's a few things I do that help, but doesn't solve the issue:

  • Put your pristine project aside and work on the fugly version. This is the version where you tell yourself: a. The code is not supposed to be pretty. In fact, tell yourself, major refactoring and reformatting isn't allowed. Let it be absolutely unorganized and free yourself of the bonds of good coding. b. It just has to work. c. It's always surprising to me what I learn about the problem space when I throw out all other concerns. I also end up with little tidbits that often help me come to the right design in a more enlightened way.

  • Set aside a decent sized block of time where you're on the project, just without a computer. Try to conceptualize what you're really trying to accomplish and look for that magic zen that transcends OO/Design Pattern madness.

0

Give a concrete expression to your thoughts: write/type them down, draw them out or whatever. This will help you in revisiting your thoughts when needed; it will stop you from going in circles; helps you think more clearly.

Whenever i see myself going nowhere and everywhere thinking about something, I type them out and it helps me think clearly.

0

I usually start from the ground up, create the simplest prototype possible and get something running. Use the prototype to reverse engineer the happy path test cases, the test cases to drive the interfaces and then think about pre/post contracts to help build out test coverage.

Don't worry about abstraction, optimization, or verification until the problem is fully understood.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.