12

First a disclaimer: I don't really know if this question fits this website, but I still find it a relevant question not just to me but for other people which are beginners. If the question can be improved to fit here, please point out int comments. If it doesn't fit, let me know also and if possible let me know where this can be discussed because I didn't find any good forums for this.

I've learned to program in 2009 when I studied PHP. Later in 2012, I moved to C# and .NET. Anyway, coding isn't the problem, writing down algorithms isn't my problem. My actual problem is to know what has to be coded to achieve a requirement and where it has to be coded.

Most courses out there available on the web tackle the how - how to write code in a certain language, how to use some sets of APIs, etc. That's not my point here.

In these years I've read a lot about a bunch of things: object-oriented analysis and design, design patterns, domain-driven design and so on. I understand for example the SOLID principles, some of the main ideas of DDD like the necessity for engagement of domain experts, the development of a ubiquitous language and so on. I would dare say I a theoretical background at least reasonable.

But when it comes to practice I feel like I'm a disaster. Some time ago I needed to continue the development of a financial system that was already being developed by someone else. It's that kind of "old system" developed with C# and WinForms. It was the first time I picked a project with real domain complexity, with lots of business rules and so on.

I confess that when I receive the requirements most of the time I think "how on earth can this be done?" - I have no idea on how to even get started working on the requirements to figure out what has to be done. My main confusions I believe are what I must code, what classes, interfaces and where each piece of logic goes, on which class each thing must be. The problem is that I don't know where to start.

Most of the times, with quite a lot of thought I end up with some ideas, but I never know how to judge if my idea is correct or not.

I mean I don't think this is a lack of theory, as I said I've read about a bunch of thing on software architecture and object orientation I was recommended but it didn't help much in identifying what must be done in practice.

So how can I learn to really do object oriented design? What I want to learn is: given requirements know how to get started working on them in a process that leads to finding out what has to be done and where each piece of code belongs. How can I also learn to judge if my idea is correct or not?

I believe fully explaining this as an answer here would not be possible. What I am looking for, however, that may be according to the site style are answers just giving an overview and pointing some references (books, online courses, etc) that can be used to expand the ideas and really learn these things.

  • 1. Do you already understand all of the fundamental concepts of C#, including things like the difference between operator overloading vs operator overriding, what an abstract class is and how it's different from an interface, encapsulation, polymorphism, etc.? Knowing these things first is essential to fully understanding OO in C#. See c-sharpcorner.com/technologies/oop-ood. – Robert Harvey May 6 '17 at 23:11
  • 2
    2. Older applications written in Winforms tend to turn into big balls of mud unless they are architected properly. Separation of concerns becomes paramount. See winformsmvp.codeplex.com – Robert Harvey May 6 '17 at 23:17
  • 1
    There isn't really a process. Design is mostly about knowing how to organize, which comes with experience. The SOLID principles are a good start, but they're not enough, and people tend to get lost in SOLID and forget why the principles exist. – Robert Harvey May 7 '17 at 0:02
  • 1
    Start little. Requirements are problems. One problem can be as huge as "We want to develop the next Stackexchange site" or as little as "we want our next Stackexchange to have a login". Turn a big problem into many but smallers. Overall, give yourself the chance to do the things "wrong" first and improve over time. – Laiv May 7 '17 at 1:25
  • 1
    I simultaneously want to upvote and vtc this... – svidgen May 7 '17 at 21:57
21

So how can I learn to really do object oriented design? What I want to learn is: given requirements know how to get started working on them in a process that leads to find out what has to be done and where each piece of code belongs. How can I also learn to judge if my idea is correct or not?

Well first of all, stop thinking of object oriented design as correct. That's like thinking of English as being correct.

The object oriented paradigm isn't correct. It has certain advantages and disadvantages. It is an ideal. It's not our only one. It is better than nothing but it's certainly not everything.

I've been coding for decades now. I've studied this stuff for almost as long as it's ideas have existed. I'm still learning what it means. The experts are still learning what it means. Our entire field is less than 100 years old.

So when you take a pile of requirements and turn out code that satisfies them yet feel like the code you wrote is a tragic mess you're not alone. Working code is simply the first step to great code. Code that not only works but that others can read and understand easily. Code that can be adapted quickly when requirements change. Code that makes you want to sit back and say "Wow, that's so simple".

The problem is we aren't getting paid to do all that. We do all that because we're professionals. We have to do all that when the boss isn't looking because there's always a deadline. But we want to come back in 5 years and say to the newbies: "Oh yeah, I wrote that. Still works huh? Cool."

How do you get there? Practice. Don't accept ANY design idea on faith. Someone wont shut up about how event driven design will simplify this design? Not sure if they're right? Build your own toy project at home that uses the observer pattern. Mess with it. Try to find things it DOESN'T help with.

Read. Question. Test. Repeat.

When you get to the point that you've been doing that for 80% of your life you'll be just as confused as I am.

I confess that when I receive the requirements most of the time I think "how on earth can this be done?" - I have no idea on how to even get started working on the requirements to figure out what has to be done. My main confusions I believe are what I must code, what classes, interfaces and where each piece of logic goes, on which class each thing must be. The problem is that I don't know where to start.

I used to feel the same way. Then I discovered the joy of refactoring. Be willing to adapt designs as you code. Trying to work everything out on paper ahead of time is the hard way to do it. Write code that can be proven wrong, prove it wrong, and fix it.

  • 2
    This is a great answer. I've been programming for 15 years, and I'll add that the entire field of Software Engineering (my profession) is "fuzzy" - it's a mix of art and function, and depending on the developer is more one than the other. I can come up with an idea for an architecture on paper, but I can't ever work out the details of the OO design until I get into the dirt, mess around, and find what works and what doesn't. – jropella May 7 '17 at 6:59
  • Thanks for the answer! So your point is: once we have at least one solution to implement a requirement, and it works, we implement it, and then as we see how it relates to the other code and other requirements, we refactor it to make it better? But there are still situations where I get some requirements and I have no idea on how to start. In that cases, do you have any advice on how to even start? Sometimes I believe the best would be to discuss the requirements and the possible implementations, but I work alone. Is there some forum where this kind of discussion is welcome? – user1620696 May 8 '17 at 0:43
  • 2
    Well first, stop working alone. Even having a clueless newbie who slows you down to explain things to is better than that. Second learn to break a requirement down into parts. Keep doing that until you have something manageable that you can get traction on. Write proof of concept code in a completely different environment if you have to. Just do something that expresses your understanding of what is needed. Then test that expression. You my find you made bad assumptions. That's good. Be willing to change them. – candied_orange May 8 '17 at 3:04
1

Software development boils down to the delivery of working software, on time, on budget while meeting all of your acceptance criteria. Assuming you've managed to do that, the perceived quality of the code or its structure is a secondary concern.

The problem of course is that writing fresh new greenfield code tends to be a lot cheaper and easier than maintaining legacy code, so rather than being too hung up on code quality or architecture, remember that your real problem is maintainability.

Typically code is considered maintainable when the costs, time and risks associated with changing that code are proportionately low enough that fixing bugs or implementing changes to requirements is still cost-effective, and that by implementing those changes you're not perpetuating a "death spiral" of code-entropy.

Conversely, code is considered un-maintainable when you cannot confidently change or refactor without a serious risk of either breaking something or spending excessive time/money to ensure nothing is broken - i.e. when the time, cost and risk involved in working with that code is disproportionately high compared with the benefits of making changes (i.e. your employer or customer is not losing money adding new features, fixing bugs, etc.)

Remember that even the most diabolical spaghetti mess can be potentially maintainable if you have enough provisions around the mess to protect yourself against breaking changes (though such cases are rare). The problem with a spaghetti mess is that protecting it against breaking changes tends to be quite expensive and inefficient - especially if you're doing it retrospectively.

Perhaps the most reliable way to ensure you've written maintainable code is to write (where reasonably possible) an adequate suite of automated tests at the same time (while also taking full advantage of any other static analysis tools which might be available).

You don't particularly need to follow a strict development methodology such as TDD/BDD in order to end up with enough automated tests to allow you to refactor; you just need enough to protect the code against accidental breaking changes in the future.

If your code is covered by automated tests, then you can relax about its design and structure knowing that you're covered by those tests; you can aggressively refactor at a later date, or even throw it away and start again.

This begs the question of how to write easily-testable code; this is typically the main argument for following SOLID principles; in fact, the hallmark of code which adheres to SOLID principles is that its easy and time/cost effective to write unit tests.

Of course, sometimes you don't have time for writing unit tests either; however if you've written all your code while keeping in mind the question "How do i write automated tests for this?" (even if you didn't actually implement those tests), you've probably also managed to find a design which is reasonably maintainable.

  • 1
    we never have time to write automated tests but we always have time run manual tests over and over again... – Nick Keighley May 17 '17 at 10:37
  • Likewise, we never have time to write the code "correctly" and "cleanly" the first time but seem to have endless time to keep going back and fixing it, over and over and over again because of the misguided but so prevalent mindset presented in this post. – Dunk May 17 '17 at 18:05
  • @Dunk I don't think its realistic to expect code should never change or be revisited. Unit testing practices and SOLID guidelines are about encouraging practices which result in code that is easy and cheap to change when the inevitable happens - e.g. somebody finds a really weird obscure bug which the developer didn't consider at the time, or the customer sees the solution and changes the requirements, or even the original code contained mistakes because developers are only human; or maybe the developer misunderstood the requirements, or discovered previously unknown technical limitations... – Ben Cottrell May 17 '17 at 20:04
  • 1
    @BenCottrell - I totally agree. Code will always need to be revisited. However, because of that, it leads people to point to taking the time to do "upfront design" and writing somewhat "clean code" as some sort of failure. They use the "on-time" and "on-budget" mantra to justify poor code/design. You can use all the "practices" you want but it isn't going to buy you "code that is easy and cheap to change" without having a good design and relatively "clean code" to begin with. A good design and "clean code" will have the by-product of actually achieving the on-time and on-budget goal. – Dunk May 18 '17 at 19:20
  • @Dunk That sounds like you're saying many developers just don't care about code quality, which I don't believe is usually the case. In reality I think there are two bigger problems - firstly, while developers may be the ones who provide an estimate for the budget and deadline, estimates can easily turn out to be wrong. Secondly, project stakeholders get the final say on time/cost, which means risks, budgets and deadlines override technical concerns. Given a choice between "definitely late/over-budget" or "potentially bad code", I find that stakeholders frequently choose the latter. – Ben Cottrell May 19 '17 at 1:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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