Every time I start a project, I decide at crucial moments to completely change the core classes and get caught up in obscure errors. I try planning in advanced and usually start off on a good foot but then I go to it another day and decide I would like to do it 'another way'.

Is there a standard, of sorts, when starting a project such as mapping out classes and starting with unit tests? What is a good convention when planning and starting a medium project.

The last project and started was a projectile motion simulator - I know, predictable.

11 Answers
11

When you plan, don't plan every possible thing about the application in advance. Plan in baby steps. What is the absolute minimum functionality you need to start using the application? Start there.

When you start your project, only code out the absolute minimum functionality. When you do code it out, make sure you are writing good, clean code with smart encapsulation. This will minimize errors that come from making changes later.

Iterate on that minimum functionality until you are happy with it. Then start adding in new functionality and enhancements, one at a time. Again focus on writing good, clean code with smart encapsulation.

If you plan in baby steps and write clean code it will minimize the number of changes you actually need to make. By the time you've finished writing that first feature, you should have adopted the patterns your application's foundation will sit on. If there are problems with that foundation, your next features should quickly reveal the problem. It will be easier to see how piece integrate together. The changes you do make should, at this point, cause minimal disruptions.

It seems that your planning isn't helping. That's no surprise because you don't have enough experience to make a feasible plan. The solution is simple. Stop planning so much. Just accept that you are going to write and rewrite the code as you go. That's ok, because code is free, except for your time. If you are writing a UI application, just start with a blank window and add a bit at a time until you are done. When you have more experience, your projects will go faster. Worrying because you are changing code is like a music student worrying about all the notes wasted in practice.

+1 if the question is only about small personal projects. Frequently changing and rewriting code on those projects is also a good sign: it means that the developer is thinking about better approaches or ways to solve the same problem. What would be problematic is to write crappy code and never think about it again.
–
MainMaFeb 8 '12 at 19:05

No one really knows what the best design will be until they've coded a certain amount of it. Therefore, the secret to good design is to recognize that your first draft is inevitably suboptimal, and plan to rewrite smaller portions earlier and more frequently. Instead of scrapping an almost complete program, rewrite lines or functions or classes as soon as you recognize their deficiencies.

Good experienced programmers don't usually get it right on the first draft either. What comes with experience is the ability to recognize a bad design sooner, and the ability to rewrite more quickly.

In my experience, this problem goes away when you have some more experience- you get a feel for what works and what doesn't. In addition, good encapsulation can lower the costs of changing design. The more tightly encapsulated your modules are, the cheaper it is to change later. Consider it an excellent motivation for keeping your classes separate.

There are two aspects to designing an application. The first is deciding just what your application can do. The second is designing how to do it. Changes to what it does are pretty significant and depending on the maturity of the application (and the shift in direction of the application) are best approached as a rewrite rather than re-work.

The second aspect is the how. Using unit testing and agile development practices, you can minimize the impact of changing how a specific function is accomplished through refactoring. Part of learning how to leverage those techniques is practice practice practice.

I'll give the advice I've given time and time again. Pick a pet project. Write it to the best of your abilities. Learn something new, and apply what you've learned to improve how you approach developing that project.

For example, start with a Todo list. Make it simple...don't even worry about database storage at first. Just get it working. Now start building on that foundation. Maybe you want to learn MVVM and WPF...you already know how to implement the in memory todo list, so you have one less problem to solve. Now you want to make it where multiple users can load their todo lists from a database. You've solved in memory and separated presentation, so you can focus on learning data access. From there you can expand the application to have a more complex domain model (for instance changing from a Todo list to a project management solution), a web interface, or even make it run on a mobile device. The key to making this work is to pick something that is accomplishable by you that you can mark progress against and that you can grow over time.

In my experience, the system design often takes as long or longer than the actual coding. When you say "planning in advance" what do you actually plan? Maybe go old school and use one of the tried and tested design methodologies. Or go old school and write the pseudo code before writing actual code.

I think you have to ask yourself why are you changing things at crucial moments rather than sticking with the original plan. Was the original plan flawed? Or did you have an insightful moment that showed a better way to do things. Was it actually better or just different?

As you gain exp you will need to rewrite/scratch and start over, less often. Write down the problem you trying to solve. Write down vague class descriptions that you think you will need, write up how the will need to interact. Get an idea of how everything is going to work then code. Do not spend tons of times writing out every property, method of your classes. At this stage you're trying to get the 50K foot view of what your supposed to do. Once you start coding if you need to write down more detail go for it. If not just start coding.

The reason you are finding this so difficult is that you have an idea, but you don't really have a complete idea what you want it to do. If you are doing your own project and you don't have a customer to tell you what they want, then it is up to you to be your own customer. Put yourself into the customer's shoes and start building an impossible wish list.

In other words, when you start Don't design ANYTHING!!!.

Once you have a big list of things you want the system to do, prioritize everything and decide what the minimum functionality will be to have a basic system running. This could be a single basic function, or an entire screen, but it needs to be something you feel - as the customer -will be useful enough to test.

So, Wish list of features + basic priorities = Requirements.

Once you have all of that, do a very high level design. Just sit and think about what your system will need to get the first few priorities up and running. Change you mind if you wish, but here is where you may wish to spike some code or a system configuration to learn more about what is possible. Go only far enough to validate your basic idea of a design.

I.e.: NOWyou get to indulge your designers urges.

Once done, you start implementing your features. Create for each feature a basic functional spec. This could be as simple as a collection of feature statements. Story cards if you like. This allows you to develop your idea in your mind a little, and to create a set of statements that will become the specification that you will be testing and building your implementation against.

Cry Havoc, let slip the dogs of...Code!!

From there, implement your tests to match your specifications, then for each test, write your code. Build, "release", then repeat with the next feature until you decide the project is complete enough.

It really comes down to experienced, but this approach I've found is a simple formula to help you focus your mind on what needs to be done, rather than getting locked into an endless cycle of procrastination due to trying to do too much all at once.

After you have done the basics such as establish the projects goals, got your list of requirements, and locked down any interfaces to external systems.

Then you need to do a use case or "story" for every user interaction. Volumes have been written on what makes a "good" use case or story and there are many variations. Use cases are the single most effective design tool I have come across. They help pick up missing functionality at the same time as eliminating unnecessary requirements and strip your design down to its essentials. As I said methodologies vary but most practioners agree on:-

concise plain English text.

"Goal Driven" works best i.e. "Monkey gets a grape" is better than "Monkey Pushes red button".

ban technical terminology. No "pulldowns", "text boxes". A good use case should be independent of any interface technology. You should be able to take a use case for a HTML based system and use it for a voice activated system without any changes to the use case itself. (this is very hard to do but worth it!).

Aim to reduce the word count of your first draft by 50%, get rid of any unnecessary steps and verbiage.

Than you are ready to specify your major classes:

UML- Universal Modeling Language. Is the standard tool for designing classes.
You specify the public members and methods of each class and link them together in a clear an concise graphical model.

In conjunction with sequence diagrams, data models, you can verify and improve your design before any coding takes place.

Shift your focus on the result you want to obtain and weigh the potential gains of learning/trying new implementations with the risk of going down a road that winds you up back at square one.

In the case that you do end up back at square one, all is not lost because you gained experience.

If you have a deadline (it sounded like maybe you are programming for fun) then this is really tricky. If you continually go one way, you risk using outdated methods as time goes on. If you continually go the other way, you risk the consequences of producing output at a slower rate (a variably slower rate depending on the outcomes of your learning adventures).

I used to blaze through work, getting things done fast year after year, and then one day I realized I was becoming non-current in my skillset.