This paper demonstrates that TDD adds 15-35% development time in return for a 40-90% reduction in defect density on otherwise like-for-like projects.
The article refers full paper (pdf) - Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat, and Laurie Williams. “Realizing quality improvement through test driven development: results and experiences of four industrial teams“. ESE 2008.
Abstract Test-driven development (TDD) is a software development practice that has been
used sporadically for decades.With this practice, a software engineer cycles minute-by-minute
between writing failing unit tests and writing implementation code to pass those tests. Testdriven
development has recently re-emerged as a critical enabling practice of agile software
development methodologies. However, little empirical evidence supports or refutes the utility
of this practice in an industrial context. Case studies were conducted with three development
teams at Microsoft and one at IBM that have adopted TDD. The results of the case studies
indicate that the pre-release defect density of the four products decreased between 40% and
90% relative to similar projects that did not use the TDD practice. Subjectively, the teams
experienced a 15–35% increase in initial development time after adopting TDD.
Full paper also briefly summarizes the relevant empirical studies on TDD and their high level results (section 3 Related Works), including George and Williams 2003, Müller and Hagner (2002), Erdogmus et al. (2005) , Müller and Tichy (2001), Janzen and Seiedian (2006).
There is a development process question which should be understood and answered before worrying too much about the code.
IMHO, any organisation which employes more than one software developer, and especially one using interns to develop code, should have sane, rational, understood, shared development processes. There is a tremendous amount of evidence that reviewing code helps a lot. They help all developers to get onto the same page about coding techniques, style, libraries, tools, etc.
Recommendation 1: Ask your supervisor about doing a review of your code or design as soon as practical. It'll give you some feedback from people who's views are much more relevant than ours. Also it'll provide a way for your supervisor to understand your code well in advance of you leaving, with a clear invitation to direct you to fix things they don't like.
Let's try to look at it from some other persons position. They have to change the code, without breaking it, or fix a bug. They might be the next intern, with less knowledge than you. They want life to be straightforward. Ideally they will look at your code and say to their supervisor "this code is great, I can understand it really easily, and I am confident the set of test cases they built will catch most of the types of errors that I might make."
When I have to read other peoples code, I like it 'as simple as possible, but no simpler'.
The less code I have to read, the fewer ideas, and the less 'stacking' or 'cross-referencing' (I wonder how that works, I'll have to go and read that before I can progress), the better. So callbacks are unwelcome unless they reduce the total amount of effort a lot. Big libraries, with lots of extra features mainly obscure the code. Good unit tests and test cases help me to understand what the developer intended.
Your code seems like a model of how this might be done.
My only slight criticism is:
display(toTerminal, "Press 2 to go to sub-menu 2" ENDL);
then later
else if(choice == '2'){ goToSecondSubMenu(); }
requires someone to ensure the text of the terminal message, and the value in the if test matches. If the program really is that level of complexity. I wouldn't worry. Hoever if it is significantly larger, then I might be tempted to create some named constants, and write something like:
#define SUB_MENU_2 '2'
...
display(toTerminal, "Press " SUB_MENU_2 " to go to sub-menu 2" ENDL);
else if(choice == SUB_MENU_2){ goToSecondSubMenu(); }
You might be tempted to put the message and choice character into an array of structs, so that the choice value and message are kept together. That is making the reader of your code have to think a bit harder, but you might find it helps if there are some other requirements. For example, it might help to identify values explicitly, so that more ways of navigation can be made to work, e.g. driving up and down the menu with cursor keys, or pressing the digit. However, resist the temptation to write 'clever' code; it causes a new reader to have to move around the code, rather than simply read it in sequence.
MVC is useful when you need to separate concerns when one or more parts are complex, or there is a lot of value in reusing solutions to part of the overall problem.
For example, the code to manage a view, menus, mouse clicks, and keyboard input in a windowing system is complex to write and test. It is worth reusing that. Your 'view library' is display()
and getchar()
. That's it. The rest is your code to do more view stuff.
There seems to be very little control state. In the example you've shown, the view isn't changing what is offered to the user depending on the state of the model or rules managed by the controller. Further, the actions seem to be straightforward too. So the controller seems very simple, and the model encapsulated.
If that changes, and the view must dynamically respond to reflect the state of the model, or their are several ways to get at the model, or more 'input validation' of data, their may be a need for a more explicit implementation of MVC.
The stuff you have been taught is typically designed for very large systems (or is just another new fad). Unfortunately, when it is taught, the reasoning or rationale might be poorly explained.
IMHO, some of that complexity comes from people trying to implement things in a language which is not a good fit. For example, SmallTalk, the original home of MVC, makes some things easy because it is so dynamic and rich, however some of its mechanisms are ugly to implement in other languages. Hence we end up with a lot of complication, to address complex and very general situations.
Also, there is quite a lot of money, marketing and ego tied up in offering very clever solutions designed for extremely complex problems, then selling the skills capable of applying those clever solutions. It is unlikely you'll hear a large system integrator say "no, you don't need anything this clever and expensive, you just need that very simple, straightforward approach that any competent developer will use successfully". Just my $0.02.
Best Answer
First off, you should know that trying to understand code you didn't write is 5x harder than writing it yourself. You can learn C by reading production code, but it's going to take a lot longer than learning by doing.
It's a skill; you get better at it. Most C programmers don't understand how people use Ruby, but that doesn't mean they can't.
Well, there are books on the subject:
If a bumblebee can do it, you can too!
Keep in mind that applying practices from other languages usually doesn't work. TDD is pretty universal though.