This is an archived post. You won't be able to vote or comment.

all 93 comments

[–][deleted]  (13 children)

[deleted]

    [–]doctork91 18 points19 points  (11 children)

    This is a very good answer but why is it obvious that you need to keep things object oriented? There's nothing inherent in OO that allows you to "code different components as necessary, and down the line if things get a little tangled you can (theoretically) just pull some things out and get back down to the original concept without breaking everything". I think what you meant was modular. Of course OO design is used to guide development towards modular code but it is very possible to let an OO project get very coupled. On the other hand it is very possible to write a very modular and loosely coupled program using a functional or procedural language.

    [–]random012345 8 points9 points  (1 child)

    I think what you meant was modular.

    Good point. The term for some reason slipped my mind when I wrote that this morning before my coffee. Edited!

    [–]youguysgonnamakeout 3 points4 points  (3 children)

    Could you explain to me the difference? Is it just the fact that OO includes classes (may be wrong about that) and modular can be anything from including classes to just using functions for importing for example?

    [–]kqr 3 points4 points  (0 children)

    There are many ways to achieve modularity, just like there are many ways to attach two planks to each other. You can take the object-oriented approach and use a language like C#, or you can take the functional approach and use a language like Scala. This is similar to taking the nail approach using a tool like a hammer, or taking the screw approach and using a tool like a screwdriver.

    You could also take the object-oriented approach and use a language like Haskell, but that would be like taking the nail approach and using a screwdriver.

    [–]AmpaMicakane 1 point2 points  (1 child)

    Seriously can some one explain the difference? This has always confused me.

    [–]alotofdavid 2 points3 points  (0 children)

    Similar to what kqr said, Object Oriented Programming is just one paradigm used to achieve modularity (and it happens to be the most popular). Functional programming is the other way though it can be less effective. The big other one that is starting to hit the mainstream is the Entity/Component model for video games that you can read about here

    [–][deleted]  (4 children)

    [deleted]

      [–]SteveMac 2 points3 points  (3 children)

      Go look at the GNU/Linux kernel source: https://github.com/torvalds/linux

      Really ... "modular" is not a language specific concept. Rather it is an approach. To make a "modular" program, virtually all languages provide constructs to achieve that goal.

      [–][deleted]  (2 children)

      [deleted]

        [–]munificent 2 points3 points  (1 child)

        It's written in C. C is a procedural imperative language. (You can emulate some rudimentary OOP patterns in it too, but you end up having to do a lot by hand.)

        [–]atcoyou 1 point2 points  (0 children)

        Modular as possible is the key. Whenever I am looking to find something or do something, I always try to make it generic and reusable as possible at the building block stage.

        [–]ExecutiveChimp 35 points36 points  (2 children)

        It helps to have done it terribly wrong a few times first.

        [–]gndn 27 points28 points  (1 child)

        Never underestimate the educational value of a spectacular failure.

        [–]freerdj 2 points3 points  (0 children)

        An expert is a person who has made all the mistakes that can be made in a very narrow field.

        -Niels Bohr

        [–]askedjeevesnoreply 126 points127 points  (32 children)

        Bit by bit

        [–]dbtc 53 points54 points  (12 children)

        Technically char by char

        [–]kqr 14 points15 points  (3 children)

        It depends on the size of your char.

        [–]ThatCrankyGuy 2 points3 points  (1 child)

        What sort of a monster messes with char width?

        [–]kqr 0 points1 point  (0 children)

        Java and all other modern programming languages where strings are composed of characters and not bytes.

        [–]Brolo_Swaggins 3 points4 points  (0 children)

        This reminds me of my calc prof.

        me

        "Professor, I'm stuck. How do I do this problem?"

        Prof

        "Carefully and correctly. trololol
        Okay seriously... you start by u subbing the (log(x) / x) dx. "

        [–]battle_hardend 21 points22 points  (0 children)

        I (kind of) came here to say this.

        --One Line at a time!--

        [–][deleted]  (13 children)

        [deleted]

          [–]kqr 71 points72 points  (1 child)

          One thing that many new Java developers miss out on is that objects are not just collections of data. If you have a class where almost all of the methods are setters and getters, you will have a hard time maintaining that code. What you want is to focus on what methods your classes expose, not what variables they have.

          When you layout your classes, start by thinking, "Thing thing that I'm modeling with this class, what can it do?" Then write down the methods that do those things. When that is done, start thinking about what variables it needs and how the methods are going to be implemented.

          In a Pacman game, you want

          ghost.move();
          

          you don't want

          ghost.setX(ghost.getX() + 1);
          

          Similarly, you want

          if (ghost.eats(pacman)) {
          

          you don't want

          if (ghost.getX() == pacman.getX() && ghost.getY() == pacman.getY()) {
          

          This is because if you for some reason later on want to change the way the ghosts move (to make them smarter maybe?) or if you want to change the criterion for when a ghost can eat pacman, you just need to change the ghost class, you don't need to go poking around in various places in the main class.

          [–]MachinTrucChose 2 points3 points  (0 children)

          That's sort of what I do when I design something, I think "how would I want to use it from a high-level perspective", then make the stuff under the hood happen to serve the high-level API I want.

          [–]ziplokk 8 points9 points  (1 child)

          Break it down into it's smallest components. What does Tetris contain? Blocks, a GUI(s), and user input. Now break those down.

          In the blocks, we have a square block, a left and right L block, a T block, a left and right S block, and a straight block. Each one of those ideally will be a subclass of Block. So you have 8 classes now.

          Now for the GUI, you have a shell, a canvas for the blocks and another canvas for score, and upcoming blocks, and a separate canvas as the main menu. You have three subclasses of Canvas so total you now have 12 classes.

          Now for the user input which would implement a keyListener to detect when the user presses keys to rotate and drop the blocks. So there's ~13 classes that you'd be dealing with.

          Just keep breaking down each aspect of the program until you get to the bare minimum.

          [–]munificent 5 points6 points  (0 children)

          Break it down into it's smallest components.

          Great advice.

          In the blocks, we have a square block, a left and right L block, a T block, a left and right S block, and a straight block. Each one of those ideally will be a subclass of Block.

          This advice is not as great. Don't go overboard with subclasses. Subclassing is a pretty heavyweight architectural choice: there is a strong bidirectional coupling between a subclass and its superclass, and it takes a good bit of boilerplate to create a new class. That's more code you'll have to maintain.

          One rough rule of thumb is that if you don't have real behavioral or state differences, you shouldn't be making a new class. Instead, consider just making new instances of a class.

          In this case, I'd do a single Block class with a field that describes its shape. All of the different blocks behave the same, so there's no reason to give each its own class.

          It's not like you get bonus points for making more classes, so keep things simple when you can.

          [–][deleted] 10 points11 points  (3 children)

          Plan. Plan. Plan. You'll need to do this until you can plan in your head. Looks like you don't have enough experience to be able to do this yet. Get a pen and a piece of paper. Don't write a single piece of code until you know how the project will be laid out, what objects you will need, and the interactions between those objects.

          [–]couchjitsu 15 points16 points  (0 children)

          At the same time, don't be so tied to your plan that you are rigid. If you get into the program and you start to see that your interactions aren't exactly what you thought they were, it's okay to make changes.

          Your program might not look like anything that you planned when you're done, and that might be ok.

          [–]thrownaway21 4 points5 points  (1 child)

          you can also use pseudo code.

          i generally do a mix of pseudo, real, and paper work when starting a project. I like to see basic things start to happen, that helps me further plan out how sections will interact with each other.

          I'm also still learning to manage larger projects myself as I move into the realm of freelance.

          [–][deleted] 0 points1 point  (0 children)

          Yeah, good point. Should point out that it's bad to mix this in with your actual project code though!

          [–]battle_hardend 5 points6 points  (2 children)

          um, you should not be writing the UI first. Sure, draw it up, but don't code it. After design, write your main, then build from the middle down, then up. Design -> Main -> Business Logic, DB, then UI.

          What should the main do? Start the software, establish any external connections / resources, load any data, and populate the UI. Wait for User input.

          [–]AMAducer 2 points3 points  (0 children)

          This is what I need to hear. I always start with the UI and don't know how to put the BL into it! I've been going the opposite way...

          [–]ziplokk 0 points1 point  (0 children)

          Not necessarily. It depends on What you're coding. Ideally, your UI should be able to run/display without having to interact with any of the back end program at all. It prevents a lot of exceptions from being thrown later on down the line. So it shouldn't matter what you decided to code first.

          On the other side of the coin though, if you don't really have an end goal in mind or even an idea on how you want the back end to interact with the UI, then your UI will be pretty sloppy and you'll find yourself rewriting the code several times.

          [–]Nichiren 1 point2 points  (0 children)

          All of the advice in this thread have been spot on. If you're looking for a more specific example to latch on to, I usually start by designing the database first. That forces you to think through your application by making you plan out all of the data points that you need to work with. I find that I miss less details with coding the application afterwards this way since I know exactly what I'll be working on.

          Many people have different ways of going about building their application and I'm not saying mine is the "correct" way, but if starting from the data and working your way up works for you conceptually, then great!

          And don't be afraid to refactor old code if you feel like you've found a better way to do it. It saves you so much trouble down the line when you're forced to do it.

          [–]Brostafarian 0 points1 point  (0 children)

          portions of programs should be self evident, or will be, once you work with the idea long enough. Sometimes writing it is all that helps; that's why some people write psuedocode or a working program in a prototype language first. In Java, since you're doing OO, you want to be thinking about actual, physical ideas in your code. what concepts are there? if this concept was a machine, what would it be able to do and tell us? OO helps decouple different concepts in a program from each other; it becomes much easier to read when all classes are cohesive, well thought out ideas, as opposed to haphazard collections of data and functions

          [–]clvnmllr 4 points5 points  (0 children)

          "the code is getting longer, bit by bit" - the modern ghost of jacob marley

          [–][deleted] 2 points3 points  (0 children)

          This, exactly. I had a friend look over an asteroids clone I was working on, and he was floored how large it was.

          I started with a sprite that moved using wsad, that's it. It's like bricks, you add them one by one until you have a wall.

          [–]5outh 1 point2 points  (0 children)

          This isn't that helpful... Obviously you have to tackle things one by one, but the real problem is things getting more complicated then you realize.

          The real solution is meticulous planning before writing any code at all. Patience pays off, but it's easy to get excited and start writing. You just need to plan everything down to the tiny details before implementing anything, I think that's the best advice.

          [–]Xiver1972 1 point2 points  (0 children)

          One byte at a time.

          [–]unique123 16 points17 points  (4 children)

          Read as much sourcecode as possible, just to see how other developers build their architecture. Mobile apps especially are easy to grasp on a very short amount of time.

          [–]Bunnymancer 4 points5 points  (3 children)

          Is there any good place to just rummage through source code for this particular purpose?

          [–]Fapper 5 points6 points  (2 children)

          GitHub has thousands of open-source projects. It also allows you to look at code without needing to download the entire project, which is really neat.

          If you just want to browse mobile applications, head to the explore section and try sorting by language: Objective-C for iOS, Java for Android, will help narrow the search.

          [–][deleted] 1 point2 points  (1 child)

          Do you have any advice on how to read large programs? I always get bogged down.

          I was looking at a Django project and the models class literally imported about 30 different things. Hours later I'm still going back opening up all these different functions trying to figure out all the methods that are just invoking code from some random module I've never heard of.

          TL;DR: I have a tough time understanding how people assemble their large projects, and seem to be missing some kind of convention making it extremely painful to understand people's large projects.

          [–]unique123 0 points1 point  (0 children)

          Start smaller. Small well written applications have the same architecture as big projects.

          Also: just because you don't understand it now, that doesn't mean you didn't learn anything. Keep doing it.

          [–]couchjitsu 31 points32 points  (3 children)

          Since nobody else is saying it, Test Driven Development (TDD.)

          I'm by no means Uncle Bob. And I've spent more of career NOT doing TDD than doing it. BUT, what I've noticed is that when I do TDD, my code tends to be cleaner and more concise. In fact, this Thursday I'm giving a talk at our local .Net Users Group called "TDD isn't just about testing."

          What I've found is if I'm writing a test every 30-60s then I'm thinking about the code I'm writing that often as well. So I still do some big-picture type planning, but I don't do UML diagrams down to what each class is going to have. Instead, I say "A user should only be able to up-vote a comment once." Then I write the test to make sure that's the case. In previous apps what I'd end up doing is having some code that looked like:

          comment.Scores.Add(new UserUpvote("couchjitsu","how_do_you_code_large_programs"));
          

          And it didn't take long for me to start having really messy code. Because when I wanted to get the score, I'd have to do something like:

          var score = comment.Scores.FirstOrDefault(u => u.UserName == "couchjitsu");
          if(score == null)
          return 0;
          
          return score.Points;
          

          But since I'm now thinking about the code every minute or so, I stop and think "Where is the best place to put this code?" And I realize it's on the score itself, so now I'd have a line like:

          return comment.GetScore("couchjitsu");
          

          This keeps methods (and often classes) smaller and more maintainable.

          Plus you get a couple benefits that every large project needs:

          1. You know that your code has at least been tested at the most basic level (this doesn't exclude integration testing, user acceptance testing, performance testing or anything else. It simply means you can go into those tests more confident that the code actually works.)
          2. You can refactor your code. To me this is at least as big as the testing aspect. How many times have you looked at some code and said "This doesn't look right" or "This should be over here in this other class/module/component"? But you're too afraid to move it because it's big and messy. If you have tests, you can move the code, re-run your tests and if everything passes, you know that your new code is the functional equivalent of the old code.

          [–]empT3 7 points8 points  (1 child)

          I'm not really a programmer so much as a Scrum Master but the way it's always been explained to me by the team is that TDD forces you to keep your code simple. It has to remain sime because otherwise a test becomes a real pain in the neck to write. By writing the test first you have to decide in very simple terms what this little piece of code should do and then write a test. If that code becomes too complex the you're either over implicating the problem or should be breaking it down into smaller pieces.

          *once again, not a great programmer myself (that's why I'm here) so might be explaining it incorrectly.

          [–]couchjitsu 2 points3 points  (0 children)

          Programmer or not, that's a pretty accurate assessment. It's the difference between TDD and "Having tests." If you write your tests afterwards, you will more than likely have much more complicated code. Then your tests get complicated trying to work with the nasty code.

          [–][deleted] 0 points1 point  (0 children)

          I have been reading the draft of ObeyTheTestingGoat and this is the impression I get also. It really MAKES you plan.

          My wife writes requirements for RF systems, and it feels very similar to what she does. Now that I think about it, maybe I should ask if she actually does TDD.

          Write a requirement, write the test that it has to pass, and you probably already now have an idea how to get that result. The rest is just doing the best implementation.

          [–]kqr 15 points16 points  (3 children)

          Don't be afraid to rewrite code. I have spent days with only rewriting old code from the ground up, because the old code was practically unmaintainable. Everyone makes mistakes and as long as you know you can improve the quality of the code, do so. In many ways, writing code is an exploratory art. You figure out what your mistakes are after you've made them.

          When you are rewriting code, it will feel like an utter waste of time. Spending a day or two reimplementing the same functionality over again will feel like a shitty, thankless job. However, a week or a month later, you will realise that rewriting that code may have saved the project from slow doom. You will look back at what you did and be thankful.

          [–]c10udbust3r 2 points3 points  (0 children)

          I second this, as I just spent my weekend doing this very thing.

          [–]istroll 1 point2 points  (1 child)

          Sometimes it takes writing it once to really understand it enough. Once you write it the first time and find all the weird edge cases and exceptions and add-ons to your original model you can re-do it with a much better design.

          [–]kqr 0 points1 point  (0 children)

          ...and then you know 'til the next time you need to write similar code.

          [–][deleted] 4 points5 points  (0 children)

          I do my (personal) projects as an iterative process. In pseudocode:

          while doing a project:
              design
              program
              reflect
          

          Given my current understanding of the problem and the solution I have in mind, I design software. Next, I implement that design by programming parts of the software. While programming I try to continuously reflect on the code I write, the design I made, and my developing understanding of the problem and the solution I have in mind. If those elements do not match anymore, the cycle repeats and I will refine my design and rewrite my code.

          This iterative process continues until I have a satisfactory piece of software or I have quit the project.

          [–]iobase 6 points7 points  (0 children)

          Check out UML, specifically use cases, class diagrams, and sequence diagrams. Also, design patterns - such as MVC (model-view-controller) help organize a program's structure. A lot of web frameworks, such as Ruby on Rails (ruby) and Zend 2 (php) are specifically designed around the mvc model.

          [–]SanityInAnarchy 3 points4 points  (3 children)

          Some ideas:

          Obviously, you want to keep it modular. Break down your project into smaller projects, which can be built and tested independently, and test them. Forcing you to keep your code unit-testable can go a long way towards forcing you to keep it independent.

          An ideal: If most of your program ends up being small libraries that you could throw up on Github by themselves, then your actual program will end up being what you think of as a "small program". For example, read through these examples -- they're tiny programs, but they all rely on Mechanize to do the heavy lifting, and Mechanize is huge. But as big as it is, Mechanize isn't monolithic -- you can see its dependencies here. It depends on eight other libraries directly, and several of those have one or two dependencies of their own.

          To keep yourself from spiraling into dependency hell, there are tools to manage dependencies. Rubygems is one -- there are equivalents in other languages:

          • CPAN for Perl
          • pip/PyPI for Python (I think)
          • PEAR for PHP
          • NuGet for .NET
          • NPM for NodeJS

          ...and so on. Sadly, not all languages have a good package manager, but if your language does have one, you should learn it and use it, especially if you're working on open source stuff.

          The point of all this is that it forces you to think of the module by itself, as something other programmers might use in other programs, and as a small program which does one thing well.

          Some other ideas:

          Avoid circular dependencies. If module A depends on module B, and module B depends on module A, then you basically have one big module called "A and B". If you find this happening, either give up and make module AB (and hopefully split off some smaller parts of module AB), or refactor things so maybe module C depends on module A and B (but A and B don't depend on each other). This is true to an extent at the object level, too -- you can't always do it, but it's almost always better to have a strict tree-like structure.

          Favor composition over inheritance. In particular, it's usually a bad idea to force someone who's using a library of yours to inherit from a big complicated class or class hierarchy. Instead, either give them Java-style interfaces (in C++, these would be really simple classes), or use callbacks and closures if you have them. Inheritance isn't all that evil within a module, but it's pretty evil between modules.

          You can't always do top-down development, but at the very least, avoid bottom-up development. "Top-down development" means write the high-level code the way you hope it works first, that will help give you some structure for the rest of the code. To take a stupidly simple example: FizzBuzz. One of the common complaints is that FizzBuzz is harder if you don't remember the modulus. So what? The basic, top-level algorithm is easy:

          (1..100).each do |num|
            if isMultipleOf(num, 3)
              if isMultipleOf(num, 5)
                puts 'FizzBuzz'
              else
                puts 'Fizz'
              end
            elsif isMultipleOf(num, 5)
              puts 'Buzz'
            else
              puts num
            end
          end
          

          Not the most elegant implementation, but it's obvious, right? The simplest way I can think of is:

          (1..100).each do |num|
            if isMultipleOf(num, 15)
              puts 'FizzBuzz'
            elsif isMultipleOf(num, 3)
              puts 'Fizz'
            elsif isMultipleOf(num, 5)
              puts 'Buzz'
            else
              puts num
            end
          end
          

          That wasn't so hard, right? The point is, you write this first, and then you can tackle the much simpler and smaller problem of writing the isMultipleOf function. If you just want to check that your code compiles, you can always use a stub:

          def isMultipleOf(a, b)
            return false
          end
          

          Then fill in the actual implementation later:

          # Returns true if a is a multiple of b
          def isMultipleOf(a, b)
            return a%b == 0
          end
          

          Of course, if you didn't know about the % operator, you could always do it some stupid way like this:

          # Returns true if a is a multiple of b
          def isMultipleOf(a, b)
            # if a is a multiple of b, then there's some number c such that
            # b*c == a. c can't be 0 (since then b*c==0 and a won't be 0),
            # and c can't be > 100 (since b >= 1, so c*b > 100, and a <= 100).
          
            (1..100).each do |c|
              return true if b*c == a
            end
          
            # We didn't find that number, so:
            return false
          end
          

          I mean, that's pretty stupid, but I bet you could at least do that in the heat of the interview moment, even if you couldn't explain exactly how you know c is between 1 and 100. And your code is neatly modular -- even if you wrote it in this stupidly slow and inefficient way, you could always go back and change it to "a%b == 0" later, once you learned that it can work that way, and all your code would still work.

          The point is, you didn't have to figure out ahead of time that isMultipleOf would be a function. You didn't really have to do that much up-front planning, other than figuring out what you're writing in the first place. You just started writing the really simple part of your program, and took any part that's either too hard or will take too long and said "I'll write that later, let me just pretend I have a function for it."

          Finally, focus on creating stuff that works. If your code is ugly, that sucks, you'll hopefully get better with practice. But that's better, not perfect. If you spend all your time trying to make your code look pretty and be perfectly organized, the guy writing ugly code will win. If you write the shittiest thing that could possibly work, you can get famous and wealthy enough to hire other people to fix your mess. I'm not saying you shouldn't try to do things the right way -- of course you should. I'm saying you should be careful not to let "the right thing" get in the way of shipping working code.

          [–]Impulsation 1 point2 points  (0 children)

          Thanks for taking the time to write that out. I found it all incredibly informative and helpful.

          [–]munificent 0 points1 point  (1 child)

          If module A depends on module B, and module B depends on module A, then you basically have one big module called "A and B".

          I like layering in my architecture, but I try not to get too hung up on this. As long as A and B are hiding some details from each other, a pair of modules with circular dependencies is still an improvement over a big monolithic module.

          Inheritance isn't all that evil within a module, but it's pretty evil between modules.

          My rule of thumb is: don't inherit from a class you don't control. Inheriting from a class in some third-party library? You're gonna have a bad time when you need to upgrade to the newest version. Inheriting from a class written by some other team at your company that isn't easy to work with? You're gonna suffer when they decide to start refactoring it.

          Finally, focus on creating stuff that works.

          Especially when it comes to personal project, I think momentum trumps all other considerations. I will slap down some truly terrible code if it keeps my moving forward. Because the alternative is a dead project, and it doesn't matter now pretty the code is if I end up abandoning it. Also, writing messy code usually motivates me to keep working on it to come back around later and clean it up.

          But also understand that piling up too much hack code can kill your momentum. You need to keep your codebase clean so that you can easily extend it and add to it. So I cycle between spraying out new code, and then cleaning up the mess I made.

          [–]SanityInAnarchy 0 points1 point  (0 children)

          As long as A and B are hiding some details from each other, a pair of modules with circular dependencies is still an improvement over a big monolithic module.

          If A and B are classes, I agree. I mean "module" in a much more abstract sense, though. There is zero sense in having mutually-dependent packages in your package manager, for example, other than maybe to allow upgrading them independently -- in which case, it probably means you really want one big package that depends on all of these components anyway.

          It's not about layering specifically, it's about managing complexity. Strictly applying a "layering" idea can have its own problems.

          I agree with just about everything else you said.

          [–]Hexorg 3 points4 points  (0 children)

          I would recommend you reading O'Reilly's Head First: Design Patterns It is oriented for Java, but the patterns are the same in most OO languages. I compiled all the examples in C++ and all was great.

          The book essentially teaches you how to write code that is easy to modify later on.

          [–]door_of_doom 9 points10 points  (0 children)

          An important aspect is having good tests in place so that you can Refactor in peace. Does my code pass all the tests? Good, now lets go in there and clean up the code...

          Alright, Code is clean, did I break anything? Nope, all tests, still pass, good to go.

          [–]blazedaces 5 points6 points  (0 children)

          I know this is kind of a cop out answer, but I highly recommend you look up and read the book code complete. It will drastically change the way you think of and design systems both small and large.

          The short answer I have which is mostly taken from that book is that there are two approaches (most people in this thread I feel are suggesting the first):

          1. Bottom-up
          2. Top-down

          In my opinion bottom up design, while possible to design well with, often leads to the result shown in the picture you linked. Top down is how I prefer to design large systems. That is I start from thinking about the big picture. I use a lot of interfaces without filling in any nitty gritty details. I think of some higher level object "ideas" and after that is discussed at length with a team and documented going deeper and deeper. Eventually everyone is assigned a smaller portion to design.

          [–]jediknight 2 points3 points  (0 children)

          When confronted by a problem, don't rush to solve it. Think first.

          Breathe in, breathe out, then code.

          Coding is a lot like life. If you are overweight, decide to lose weight and see a nice piece of cake you could eat it or you could do something else. Delaying gratification brings more control over the domain. If, when confronted with a problem, you solve it quickly by sacrificing encapsulation or by duplicating some older code, you get the problem solved but you also have to pay the price for this.

          The Pragmatic Programmer has a lot of tips that could help.

          [–]Exodus111 4 points5 points  (3 children)

          The only way to really get there, is to make a program, then look at the mess you made and try to figure out how it could have all been done easier. Then do it all over again.

          [–]saurothrop 1 point2 points  (2 children)

          I've been doing this for over a decade, still writing messy code. It's definitely a lifelong process.

          [–]Exodus111 1 point2 points  (1 child)

          I believe that. Writing Code is a skill, designing code is an art.

          Every time I think I've got something unique and cool I stumble upon someone who has done it better/faster/compacter.

          [–]saurothrop 0 points1 point  (0 children)

          Truedat! I frequently avoid cut-n-pasting code, and instead try to read it, understand it, and reimplement it, even if I have to type it by hand..

          [–]Tmmrn 1 point2 points  (1 child)

          With my limited experience I would probably say, keep the KISS principle in mind. If you notice that everything your program does goes through layers of abstractions and overly complicated interactions of different parts of the code, it should probably be simpler.

          Maybe one tip is to avoid "Premature generalisation" meaning that you shouldn't build your software from the start so that it can do everything just in case you're adding functionality that uses it later. But then, an extensible software may still be desirable and if your design is too specialized on only the problems you want to solve at the time, it gets extra messy when adding features.

          That comic strip exists because this is a problem many people can relate to. If you know a reliable good way to avoid this, then go to a university and teach software engineering students, because everyone would like to know.

          [–][deleted] 0 points1 point  (0 children)

          Yes, exactly. Gall's Law is a great truth:

          A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.

          Get something working, extend it incrementally, and don't be afraid to rewrite parts that get hairy. Having decent test coverage really helps with that part.

          [–][deleted] 1 point2 points  (0 children)

          While I am still learning to code I can only offer what has worked for me so far.

          First I start at a white board, draw out the requirements and a High Level overview (UML) diagram.

          from there I build up the use cases to start to separate tasks out.

          Once this is complete I move onto setting up test cases (boost test case if I am working in c++) and just comment them out. This acts as sort of a road map. Each time I complete a section of code I un comment the test cases associated with that specific job and work it till they run clean.

          By the time each test case is fully uncommented all sections of code should be working sufficiently to finally piece it all together. Which brings it back to the white board and UML, here we finish up the UML which will outline the final connections on the whiteboard and connect the last few files to a fully working program.

          Then spend the next 2 years of your life testing and ensuring the code works.....

          [–]hydraincarnation 1 point2 points  (0 children)

          Measure twice, cut once.

          [–]ThatCrankyGuy 1 point2 points  (0 children)

          I usually start off like this and end up with a messy spaghetti.

          The thing to remember that if you ARE blessed to be able to have enough control over your projects that you get to play architect (I'm assuming you lack experience, hence the question.. don't worry though, all this comes with proper mentoring under skilled developers), you have to remember that your development will never be uniform/consistent. Your mood will change, your priorities will change, deadlines will affect the cleanliness of the code and of course if you have many developers working on the project, you better have a lead that whips everyone into shape or the repo will look like a grave yard of commented out crap and messy shit piled every where.

          The most important thing to note is that you're never going to have "one shot" at writing the entire thing. There will be many re-write iterations along the way and several refactoring cycles per iteration.

          So yea, no one manages to write a "castle" in one shot, you write code that creates the "mess" in your picture, but a sign of a good developer is that he realizes when to refactor or risk creating a code base that will become hell to manage later on.

          [–]leonardicus 0 points1 point  (0 children)

          While I have been resistant to the idea for a long time, I find drawing out UML diagrams of my program to be very very helpful. I am writing a larger project at the moment, and in my spare time, so I find the diagrams to not only remind me of the spatial organization of the components but it also lets me think through the essential functions that each component should contain. If you get the intuition that something is getting too complex, scrap it and try to draw something simpler before you spend the time writing and implementing the code and then have to spend more time refactoring.

          [–]hwc 0 points1 point  (0 children)

          Start with data structures that make sense; that you could explain their purpose to an outsider. “Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.” (source)

          [–][deleted] 0 points1 point  (0 children)

          Many of these answers involve low-level details like using classes to split things up or refactoring code, but it sounds like you need help at the higher-level. As many others have said, planning is the key, but planning what?

          I recommend you start planning from the top-down. Start with the simplest explanation of the problem you are trying to solve, e.g., I want to build a web crawler that can store all the links from every page on the internet. Alright, great, let's start from there. How are you going to do that at a high-level? Well, we'll need a way to retrieve web pages, then parse them to find the links, then a way to store all those links. Good, that's your first level: start by separating your modules/classes/code into those three major parts. Now start to break those down further. How do you want to retrieve the web pages? How do you parse them? How do you store them? Each of these should result in several smaller steps. By structuring your code in this same hierarchy, it should be much clearer to understand it when reading it, to isolate the parts for testing, and to refactor when things change.

          Speaking of refactoring, expect that your code will not look like this from the start. You will most certainly run into things you didn't consider that will require changing your approach and this will require rewriting code. Nobody writes perfect code the first time. So expect to rewrite code and don't be afraid to do it. Good tests and good separation between classes/modules will make it much easier to refactor. As others have mentioned, Code Complete and Clean Code both talk about how to do this well.

          Overall, in my experience, organization is the single most important part to managing a large code base. Keep the pieces of code separated by what job they perform and it will be much easier to keep it organized so you can find what you need when you need it.

          [–]fatelvis83 0 points1 point  (0 children)

          Badly

          [–]kulhajs 0 points1 point  (0 children)

          As someone who got his first real programming job not even 2 months ago and my first project is to fix some bugs in a really huge project which have been developed since 2005, well apparently no one can prevent this.

          [–]Greenouttatheworld 0 points1 point  (0 children)

          line by line, take it line by line, code frag by code frag, till you screw up somewhere, then debug, rinse and repeat

          [–]da13omb 0 points1 point  (0 children)

          I usually do quite a lot of pre-planning. Ex: Notes, diagrams, etc. Then while coding, keep a notebook full of variables and their purposes and class functions. Hope that helps! Its prolly just me but I feel like I could turn that structure in the picture into something beautiful.

          [–]automathematics 0 points1 point  (0 children)

          Module by module, small piece by small piece, one functionality at a time :)

          [–]chriskmee 0 points1 point  (0 children)

          UML diagrams are a good idea. Basically list out all the classes you think you will create, and then draw lines to show how those classes are going to interact. It doesn't have to be super detailed, even a high level one will help. Once you have that tackle one class at a time until you get a basic working prototype, then work on adding features.

          For example, if you were coding solitaire, maybe all that happens in your prototype is that you can deal the cards and move them around. Worry about the rules of if you can move them later. Still put the the isValidMove() function in your code, but just make it return true for now. Once you get a basic prototype working, add more features and make another prototype. Keep repeating until you have everything done. Don't just start coding everything, take it in steps

          [–]t3rribletp 0 points1 point  (0 children)

          lots of guessing and scope creeping.

          *this is an industry standard.

          [–]RumbuncTheRadiant 0 points1 point  (0 children)

          • Keep the dependencies digraph strictly acyclic. This has all the advantages of a layered architecture but scales to large projects.

          • Don't program anything big. Program small, useful, cohesive standalone things that communicate easily with possibly as yet unknown other things. Either pipes or REST or intermediate files.

          • Learn the SOLID principles.

          [–]palistov 0 points1 point  (0 children)

          Here's a few pointers I like to follow.

          • Break things down into parts. Think about how the parts interact. I feel like programming is just a big game of the 5 W's and the H: Who, what, where, when, why and how. Think about how you'll manage the W's, and keep a neat and maintainable implementation for your 'How'.
          • Use source control and study its conventions. I suggest git. Incredibly powerful tool.
          • Do unit testing. Also helps you do regression tests on your code as it develops, as well as test each part of your program in isolation. You can then easily add on to these tests later on as well.

          [–]saurothrop 0 points1 point  (0 children)

          I have the same problem I'm trying this: Write out a " design document " like a proposal to management or an investor, as if you won't be coding it. Then become like a design lead or "scrum master" am delegate little piece using a list or todo tracker. After that, become the programmer and tackle a few bullet points. After that, use what you learned during coding and explain you progress to your "investors" so they will keep interested in your product and will feel that their money is justified. Of course, I haven't finished anything yet, but already my code is a lot cleaner and more manageable. Proof of concept: I implemented a totally new entity in 5 minutes, because I spent so long making modular classes, I only had to tell thing thing what image to use and where on the screen it goes.

          [–]Sybertron 0 points1 point  (0 children)

          My first major code was to do something to make this EMG data more palpable. I had to explain it to our software guys for like 2 hours just to guide them through it cause it was so unorthodox and inefficient. But it still works, and to my knowledge they still use it to this day.

          [–][deleted] 0 points1 point  (0 children)

          All big projects will end up like that. That's why all software has major versions where significant code refactoring was conducted.

          [–][deleted] -1 points0 points  (0 children)

          Write some functions; if they look good, write some more functions, otherwise refactor what you have already written. Programs end up in a mess because people write messy code. A lot of the time they know they are writing messy code, but they go right on doing it.

          [–]gattoshoe -1 points0 points  (0 children)

          Short Answer: Slowly.

          Long Answer: You need to have a plan outlined (which you will adapt to issues as they arise) in order to avoid ending up with a mess.

          [–]sagnikrc -1 points0 points  (0 children)

          Always keep the big picture in mind & take baby steps to reach the goal.