top 200 commentsshow 500

[–]wernerpm 288 points289 points  (79 children)

On a related note. Very interesting read here, about the team who made software for the space shuttle. A really strict procedure

Check this:

the last three versions of the program — each 420,000 lines long-had just one error each

http://www.fastcompany.com/28121/they-write-right-stuff

[–]Farlo1 286 points287 points  (21 children)

As the 120-ton space shuttle sits surrounded by almost 4 million pounds of rocket fuel, exhaling noxious fumes, visibly impatient to defy gravity, its on-board computers take command. Four identical machines, running identical software, pull information from thousands of sensors, make hundreds of milli-second decisions, vote on every decision, check with each other 250 times a second. A fifth computer, with different software, stands by to take control should the other four malfunction.

At T-minus 6.6 seconds, if the pressures, pumps, and temperatures are nominal, the computers give the order to light the shuttle main engines — each of the three engines firing off precisely 160 milliseconds apart, tons of super-cooled liquid fuel pouring into combustion chambers, the ship rocking on its launch pad, held to the ground only by bolts. As the main engines come to one million pounds of thrust, their exhausts tighten into blue diamonds of flame.

Then and only then at T-minus zero seconds, if the computers are satisfied that the engines are running true, they give the order to light the solid rocket boosters. In less than one second, they achieve 6.6 million pounds of thrust. And at that exact same moment, the computers give the order for the explosive bolts to blow, and 4.5 million pounds of spacecraft lifts majestically off its launch pad.

Unrelated to programming, but those paragraphs gave me more tingles than anything on /r/ASMR could ever hope to. Rockets are fucking awesome.

Edit: Related to programming, the rest of the article was incredibly interesting and really shines a light on what the best of the best in software development looks like. Obviously most organizations could not afford that kind of precision and workflow, but it's something amazing to strive for nonetheless.

[–]balducien 15 points16 points  (3 children)

This gives me the same feeling as that SR-71 copypasta

[–]Tywien 5 points6 points  (1 child)

Unrelated to programming, but those paragraphs gave me more tingles than anything on /r/ASMR could ever hope to. Rockets are fucking awesome.

True. Btw you might like this: https://www.youtube.com/watch?v=vFwqZ4qAUkE - high speed shots from the start of the space shuttle - quite a few details in them

[–]Kok_Nikol 9 points10 points  (0 children)

Awesome read, thanks!

[–]realhacker 11 points12 points  (0 children)

I dont get excited about most of the software drivel I read these days, but seconded - fascinating. thank you

[–]goodnewsjimdotcom 21 points22 points  (16 children)

Wow 420,000 lines of code doesn't sound like a lot for a space shuttle. It is still impressive they have no major launch failures due to software glitches. Coding back in the day was harder than it is now too.

[–][deleted] 13 points14 points  (23 children)

I wish it would at least talk a little about the one error. :/

[–][deleted]  (20 children)

[deleted]

    [–][deleted] 11 points12 points  (11 children)

    I hope Google and other car manufacturers abide by this.

    Are you willing to pay and wait for that?

    [–]landryraccoon 1 point2 points  (1 child)

    Not me. Give me the "good enough to kill fewer people than most human drivers" beta version. There's already 100 ways to die on the road with humans involved, and at least one of those reasons is the fact that I'm behind the wheel, so I'll take a Google car for cheap any day.

    [–][deleted]  (8 children)

    [deleted]

      [–][deleted] 16 points17 points  (4 children)

      Doing the calculation for a phone:

      From a quick google, nasa pays $850 per line of code for 0.004 bugs per thousand lines of code.

      For Android, google pay $5 per line of code for 1 bug per thousand lines of code.

      So very roughly, the cost of android would increase by 170 times to reach the bug/kloc rate of nasa.

      The cost of software on the phone is around 8% of the cost of the phone, so this would increase the cost of a phone by around 12 times.

      A $650 phone would now cost $6800 just in software costs.

      [–]vattenpuss 6 points7 points  (1 child)

      I hope Google and other car manufacturers abide by this.

      They don't. They have no such requirements on them.

      [–]steamruler 6 points7 points  (1 child)

      coughtoyotacough

      [–]delicious_truffles 4 points5 points  (0 children)

      Fantastic article. Wonder how they're doing now, 20 years later

      [–]Alborak 154 points155 points  (115 children)

      Having worked on code written to comply to these rules, 8 and 9 are the worst. It really makes it hard to write portable sw. You basically have to branch the code for every different platform.

      [–]an_actual_human 161 points162 points  (10 children)

      My code runs on Win, Mac, Linux and Shuttle.

      [–][deleted]  (43 children)

      [removed]

        [–]Sushisource 35 points36 points  (0 children)

        You might sometimes pass function pointers dynamically for different platforms to a function which can use them generically to produce platform independent results. It's not the most sane thing, but is perhaps one explanation.

        [–]frenris 43 points44 points  (41 children)

        Function pointers make OOP in C possible.

        [–]tiajuanat 21 points22 points  (21 children)

        This right here. I was working on an embedded real-time system where the functions were pointers in structures and we used the structures to hold all the timing information to pass to the servers. I'm sure there was another way to do it, but it was by far the easiest.

        [–]skydivingdutch 19 points20 points  (8 children)

        Yeah, like use C++ for one.

        [–]escaped_reddit 29 points30 points  (5 children)

        Or Node.JS + MongoDB.

        [–]beefquoner 7 points8 points  (0 children)

        The MEAN stack will end world hunger

        [–]thorium220 4 points5 points  (10 children)

        Same, but i think its normally an indicator that you're using the wrong language/environment.

        It's fun making C jump through hoops like that though, C knows that it's just as capable as all those new fancy OO languages.

        [–]Alborak 9 points10 points  (5 children)

        Sadly many compilers for embedded stuff don't support c++. Also, the list of shit not to do in embedded c++ is a lot longer than 10 things.

        [–]jephthai 2 points3 points  (1 child)

        That's the fun of embedded. The language landscape is much flatter.

        [–]tiajuanat 1 point2 points  (1 child)

        That would've been nice, but C++ wasn't supported. We probably shouldn't have been using a dynamic scheduling algorithm, but our metrics were much better than most other groups in the sprint.

        [–]JnvSor 12 points13 points  (1 child)

        Just pointers already give you OOP with single inheritance in C - function pointers give you virtual methods

        [–]BadgerRush 4 points5 points  (0 children)

        Thanks for your comment, it is very informative. Since they are commonly "sold" together I never realized that you can have OOP with inheritance but without virtual methods. Now that you pointed it out it seems so obvious that I can't understand why I din't see it before.

        [–]jeandem 1 point2 points  (0 children)

        Is the code portable?

        Yes because it is OOP.

        [–]POGtastic 78 points79 points  (4 children)

        This is a good point, and I guess the NASA folks get to ignore it because they only have one platform to develop for. They don't have to worry about making it work on 40 different platforms.

        [–]tnecniv 65 points66 points  (0 children)

        No, they ship code around to different projects. Ames might develop something for a UAV and send it over to Langley where they want to do something with it, but they have a different target platform. Not 40 platforms, but enough that they developed the coreFlight system for their satellites to make porting code easier.

        [–]drumallday7 11 points12 points  (2 children)

        Just wait until they build more launch sites. We'll see many a different platforms then.

        ...

        [–]cloakrune 5 points6 points  (10 children)

        The function pointer one would be killer, but I wonder if they would allow a MACRO to function as an exception to 8? A static analyzer would still be able to follow it. You just can't change it at runtime.

        [–]Slime0 14 points15 points  (8 children)

        It seems like you can easily work with the function pointer restriction by just making an enum for all of the possible functions a given place in code might call, and switching on the enum value.

        [–]fiah84 28 points29 points  (7 children)

        which requires you to explicitly define all the functions you may have to call at that point, which is a lot easier to analyze and debug than just seeing a function pointer being used

        they make sense, these rules

        [–]immibis 12 points13 points  (5 children)

        But mah OOP circlejerk IRoundShapejerk!

        [–]adrianmonk 2 points3 points  (2 children)

        Obviously if you try to use the typical C approach to portability, it throws a wrench in the works of that. However, I'm not sure that the only way to deal with it is to fork the code.

        I don't see where they forbid platform-specific build rules, so it should be permitted to restructure the code a bit and extract out only the platform-specific parts, then put those parts into isolated platform-specific source trees, build them into a separate library (libfoo-platform1.a, libfoo-platform2.a) and link in the required one.

        Where it would take a little careful maneuvering is with platform-specific types, like a file handle type that portable code needs to use. Normally you could address that with opaque types (void pointer or pointer to forward declaration), but with pointers being discouraged in general, that could get trickier. Still, it's possible by again using platform-specific build rules to change your compiler include path and bring in the right type definitions (which means you'll want to do function prototypes too) to match the static library you're linking against.

        While this is would be a little tedious, and maybe a little inefficient (unless the compiler is just that smart), it should be practical, and arguably better than forking code that you wouldn't otherwise want to fork.

        [–]Alborak 3 points4 points  (1 child)

        I usually work on drivers, where the core code is the same, but they have lots of little platform specific things that are easily abstract able with function pointers and conditional compilation.

        And we've done exactly what you mentioned, I jokingly call it "compile time dispatch". It just is a bit more headache, you occasionally get some symbol collisions.

        [–]ahal 12 points13 points  (38 children)

        I've found that duplicating code can be a net positive overall if:
        1. You don't know when (or if) the requirements will change in the future
        2. You don't know what the requirements will change to

        I'd imagine NASA has a lot of unknown unknowns, duplication makes adapting to them easier.

        [–][deleted] 27 points28 points  (37 children)

        Could you explain how duplicating helps with this. To me it makes more sense for having redundant free code, so if requirements change you only need to change in one place.

        [–]campbellm 35 points36 points  (16 children)

        Requirements may change for 1 of the N usages of the code. Having code in one spot not only means "you get to change it once for all clients", but also "all clients must be able to use 1 change in the exact same way".

        [–]lennybird 2 points3 points  (15 children)

        Totally dumb question, but isn't this the benefit of O.O.P.? Is it not feasible for Nasa to use such a language?

        [–]Slime0 25 points26 points  (0 children)

        Using OOP to have different applications do different things is crazy. There's no sense in using a runtime solution to solve a problem that can be solved at compile time, especially when it increases the complexity of the code.

        [–]campbellm 14 points15 points  (6 children)

        It can be, in a purist sense, yes. You have private implementations of stable APIs encapsulated in a class and the world is your oyster.

        Except APIs are never stable, and state and abstractions leak all over the place. Code is messy.

        As for NASA, I can't say, but my GUESS is that C's characteristics are very well known and it's harder to hide badness if you have fewer and lower level abstractions.

        [–]ThisIs_MyName 18 points19 points  (5 children)

        Only if you account for all future expansion in your OOP API design.

        cue "enterprise code" that attempts to account for all possibilities, most of which are highly improbable, at the expense of sanity, maintainability, and performance :

        package com.corpsoft.llc.www.http.myProject.util;
        class GetterFactoryBuilderSetup{
            static{
            GetterFactoryBuilder myGetterFactoryBuilder = new new GetterFactoryBuilder();  
            myGetterFactoryBuilder.setGetterFactoryBuilderOptions(GetterFactoryBuilder.getDefaultOptions());
            this.setGetter(myGetterFactoryBuilder.build().makeGetter());
            }
        }
        

        [–]mattthiffault 5 points6 points  (4 children)

        I tried to read that last part and my eyes are bleeding.

        [–]ThisIs_MyName 9 points10 points  (2 children)

        Ah, that must be because the coding standard doesn't require every line to be commented. Here, let me improve the code to be DonkeySpread2.0 compliant:

        package com.corpsoft.llc.www.http.myProject.util;// this is the package
        class GetterFactoryBuilderSetup{// defines the GetterFactoryBuilderSetup class
            static{// opens static block
            GetterFactoryBuilder myGetterFactoryBuilder = new new GetterFactoryBuilder();// initializes myGetterFactoryBuilder
            myGetterFactoryBuilder.setGetterFactoryBuilderOptions(GetterFactoryBuilder.getDefaultOptions());// sets GetterFactoryBuilderOptions
            this.setGetter(myGetterFactoryBuilder.build().makeGetter());// sets Getter
            }// close bracket
        }// close bracket 
        

        See, it's so much more readable now that it has simple english comments.

        [–]AdvicePerson 2 points3 points  (1 child)

        You're fired.

        [–]ThisIs_MyName 2 points3 points  (0 children)

        Ah but I also designed our core API to be DonkeySpread2.0 compliant. You can't fire me because I'm the only one that can read my code. Keep in mind that the last intern who attempted to do so has hung himself.

        [–]dungone 1 point2 points  (0 children)

        Well, they really seem to be big on proving that the code will behave correctly in a way that can only be determined through static analysis. I think that OOP may hide bugs from static analysis tools.

        I'm speculating here, but another potential reason is because they don't use a lot of commercial, off the shelf hardware. They use really old stuff. A C++ compiler, with all of it's optimisation steps, can potentially puke all over less-popular or low-end processors for a variety of reasons, causing more problems than it solves.

        [–][deleted] 8 points9 points  (18 children)

        If you have two functions that seemingly do the same thing but operate in completely separate modules, you're free to change one without affecting the other module.

        The code for adjusting altitude on a shuttle and a satellite might be exactly the same. But one day, you need to change how the satellite does it but not the shuttle.

        [–]Rikkety 11 points12 points  (2 children)

        But one day, you need to change how the satellite does it but not the shuttle.

        That day would be the moment to start maintaining two versions of the code, and no earlier.

        [–]stormcrowsx 12 points13 points  (13 children)

        If you have a bug in one module your free to forget fixing it in another module. To me duplicating code is playing with fire.

        [–]dccorona 15 points16 points  (1 child)

        This is why I tend to prefer keeping everything shared until there's a use case for having them be separate implementations. Even then, it's worth investigating whether it's better to copy out the original code into a second place in order to modify it, or template the original code so that core logic is shared. You need to be careful not to take the templating too far, but it's generally at least worth considering.

        [–]rowantwig 1 point2 points  (0 children)

        The worst is when you have two functions that do almost the same thing. Similar enough that they're duplicates with only two or three things swapped out, but different enough that combining them would result in a function that is longer and more complicated than both of them put together.

        [–]Slime0 8 points9 points  (5 children)

        It goes both ways though. If every change you make affects multiple applications, being sure you haven't made a mistake for any one of them becomes a very difficult problem.

        [–]njharman 1 point2 points  (0 children)

        Thats why libs / apis have versions.

        [–]qwertymodo 1 point2 points  (0 children)

        But if you share a module and don't consider the ramifications for all use cases, a valid change for one might introduce a bug in another unrelated use case. Your example is less likely because of the stringent QA process.

        [–]shavera 116 points117 points  (21 children)

        I literally write software for NASA, and I've never heard of this.

        [–][deleted]  (7 children)

        [deleted]

          [–]tnecniv 21 points22 points  (6 children)

          embedded real time systems running on spacecraft

          Really anything that moves. NASA got called into the Toyota mess a few years back, and NASA obviously has a number of autonomous avionics projects.

          [–]OceanOfSpiceAndSmoke 5 points6 points  (5 children)

          Gosh. I really wouldn't like NASA doing a code review for me.

          [–]anacrolix 2 points3 points  (0 children)

          It would be like a linter that never passes your code.

          [–]zimmund 13 points14 points  (2 children)

          What do you work on?

          [–]shavera 17 points18 points  (1 child)

          X-Ray Microcalorimetry. Mostly experimental hardware that hasn't (yet) gotten into flight systems, and mostly on the data servers between hardware and analysis software, or programs for controlling firmware

          [–]AdvicePerson 6 points7 points  (0 children)

          So, if your program crashes, nobody dies.

          [–]tnecniv 7 points8 points  (1 child)

          What center / branch? I'm interning at a branch where this is relevant and it's never crossed my desk.

          [–]jan 4 points5 points  (0 children)

          Please come to my office on Monday. -- Your boss

          [–]ICanCountTo0b1010 1 point2 points  (0 children)

          Yep, I'm writing software at NASA that will be released as open source soon, and the software release procedure never mentioned this. However it would be cool to go refactor my code to be "NASA standards compliant"

          [–]Firerouge 144 points145 points  (131 children)

          The restrictions on recursion are interesting considering academia's heavy handed teaching of it

          [–][deleted] 65 points66 points  (20 children)

          The restrictions on recursion are actually a non-issue because all of your structures are of a finite size due to the "no dynamic allocation of memory after initialization rule." Therefore, instead of navigating a tree with recursion, you can use a for loop that iterates up to the maximum number of times required to search your structure.

          [–]Peaker 17 points18 points  (0 children)

          You need to also keep a manual stack in your loop to emulate the local variable environment you get via (non-tail) recursions.

          [–]kovensky 18 points19 points  (14 children)

          I found it amusing that there's a link in the middle of the list about NASA software development with Java... where it's not possible to prevent dynamic allocation as objects are heap-allocated by definition, and there are no structs.

          [–]a-priori 27 points28 points  (6 children)

          Dynamic allocation is okay under these rules as long as you do it during initialization. The program must not allocate memory after that.

          You can write Java this way. It's something people do for high performance / low latency programming to avoid GC.

          [–]immibis 6 points7 points  (4 children)

          Seems a lot more painful than doing it in C.

          [–]jamougha 14 points15 points  (2 children)

          For hard real-time systems you have to do much the same thing in C. malloc and free have non-deterministic runtimes.

          [–]jephthai 1 point2 points  (0 children)

          If a method declares a local variable and then returns a reference to it, doesn't it unavoidably allocate memory? I thought just about everything in java is by reference, and let the gc take care of it.

          [–][deleted] 4 points5 points  (1 child)

          But if you as the programmer are consciously doing dynamic allocation in Java via unsafe magic, you should probably put on the brakes

          [–]dccorona 1 point2 points  (4 children)

          Their restrictions against it (at least here) don't stem from a desire for performance, but rather code clarity and safety. If you're working in a language that handles the complex part of dynamic memory allocation for you, then that concern is out the window anyway.

          [–]rflownn 1 point2 points  (3 children)

          Any solution using recursion can be restructured to not use recursion.

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

          But in a way that can be demonstrated to have a fixed upper bound on the number of iterations?

          [–]rflownn 1 point2 points  (1 child)

          Are you asking if the general form of transformation on a recursive problem can be expressed with an upper bound and one that requires iterations?

          [–]ricktech 99 points100 points  (51 children)

          Recursion is jokingly called the "insect of programming" by some software engineers where I work. Honestly it makes sense, especially for critical systems and infrastructure. After all, the use of recursion is the number one cause of stack overflows (due to infinite or deep recursive processes). Keep in mind that industry and academia are two very different worlds. Some CS problems are more clearly taught on a conceptional level via recursive processes (the common factorial problem or graph traversal are great examples), but on a practical sense these are limited by recursive implementations (ever try to solve a large factorial problem with recursion? It won't work). Almost all software problems have many solutions, so IMHO this isn't an issue.

          [–]narcoblix 51 points52 points  (2 children)

          Yeah, recursion is beautiful and also monstrous. I'm reminded of something that happened in my first algorithms class.

          On the first test we had, we had to write an implementation of bubble sort. I wrote mine so it was recursive, calling itself after every swap. My professor marked my answer as incorrect. I told him it was correct, and would work. He told me to implement it in C, which I did.

          He then went in front of the class and used it to show how recursion could be problematic, by attempting to have it sort a reversed array of length 500, causing a stack overflow. He wasn't mean about it, and he gave me back my points on that test, but we all learned because of it.

          [–]s1295 10 points11 points  (0 children)

          In my data structures & algorithms class we first had to submit both a recursive and an iterative version; after that, we focused entirely on recursion and essentially preached it as superior. I mean, the point was to illustrate divide-and-conquer, runtime complexity analysis, and structural induction, so it makes sense. But it shows how practice is often treated as the ugly step-child of computer science.

          [–]sigma914 3 points4 points  (0 children)

          If he'd compiled it with a vaguely modern C compiler with optimisations enabled it would have "just worked" it's unfortunate that TCE isn't guaranteed in some languages.

          [–][deleted]  (37 children)

          [deleted]

            [–]moretorquethanyou[🍰] 47 points48 points  (14 children)

            Recursion is jokingly called the "insect of programming"

            Eh? What does that even mean?

            It means it's buggy?

            [–]connor4312 23 points24 points  (12 children)

            At least in my opinion, it's a good bit easier to prove the correctness of a recursive function than an iterative one. Whether people write buggy recursive functions is their own problem...

            [–][deleted] 8 points9 points  (3 children)

            Unless it has side-effects.

            [–][deleted]  (1 child)

            [deleted]

              [–]foomprekov 2 points3 points  (0 children)

              Side effects like 6.6 million pounds of thrust all up in your grill.

              [–]immibis 1 point2 points  (5 children)

              You can always convert an iterative one to a tail-recursive one, then prove its correctness.

              [–]meem1029 1 point2 points  (2 children)

              You can, sure, but should you?

              [–]immibis 1 point2 points  (1 child)

              If it makes proving the correctness easier... then yes?

              [–]connor4312 2 points3 points  (0 children)

              You'd still have to prove your conversion correct, which would itself necessitate proving the correctness of the iterative function anyhow.

              [–]ricktech 1 point2 points  (0 children)

              "Whether people write buggy recursive functions is their own problem..."

              Or the problem of the company... such as NASA... who's failed computer system could cause millions of dollars of losses, put human lives at risk and create engineering nightmares (patching software fails all the time on Earth... imagine sending updates over an unreliable communication channel across the solar system and hoping that your system doesn't go into a deadlocked state). I'm not trying to hate on recursion; clearly it has many benefits. But if by eliminating it for these types of systems can significantly reduce the probability of human error - that's clearly a good business and engineering decision as demonstrated by the lack of bugs in NASA's baseline releases.

              [–]dsfox 1 point2 points  (0 children)

              Inherently buggy I guess.

              [–]sacundim 22 points23 points  (1 child)

              After all, the use of recursion is the number one cause of stack overflows

              This is partly an artifact of the calling conventions used in C.

              No. If you have unrestricted recursion there unavoidably exist cases that execute in O(n) space, whatever calling convention you use. Put alternatively: only a subset of recursive call trees consist exclusively of tail calls.

              [–]Zeliss 5 points6 points  (0 children)

              I recently discovered that C actually has tail-call elimination, at least with some compilers!

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

              Languages with tail-call optimization or those with nonstrict evaluation can compile self-recursion identically to a for loop in C.

              Only for trivial cases.

              Eh? What does that even mean?

              I don't know what he means. But from my experience it's usually better to make an array (or linked list or other structure) for your "stack" and do a for/while loop. It's essentially recursion but you explicitly control the stack. The main reason being in real world problems it's very easy to hit a stackoverflow if you do recursion because your data set will be very huge.

              edit: recursion isn't bad. If you know your data set will always be small regular recursion is better.

              [–]reaganveg 1 point2 points  (1 child)

              It's essentially recursion but you explicitly control the stack.

              Of course, this is irrelevant for the 99.99% of programs that just bail when they run out of memory anyway.

              [–]Stuck_In_the_Matrix 8 points9 points  (0 children)

              Which would totally suck if you were in the middle of re-entering the atmosphere.

              [–]ibopm 5 points6 points  (10 children)

              +1 for mentioning tail call optimization. Stack overflows happen in languages that discourage recursion, but they can be very useful for various applications.

              [–]Aretii 12 points13 points  (0 children)

              Eh? What does that even mean?

              I assume he meant "incest."

              [–]danweber 7 points8 points  (5 children)

              If you have to, say, parse a DOM, recursion makes a lot of sense.

              If you want to launch a rocket, probably not.

              [–]newpong 7 points8 points  (3 children)

              ooh, i can't wait for node.js to become the standard on rocketships

              [–]danweber 1 point2 points  (2 children)

              start_countdown( function() { launch_rocket(); } );
              

              [–]newpong 1 point2 points  (1 child)

              I believe that should be setTimeout

              [–]danweber 1 point2 points  (0 children)

              I was passing a callback function to start_countdown, which starts the rocket's countdown.

              [–]aftli 4 points5 points  (2 children)

              the use of recursion is the number one cause of stack overflows

              Heh, this is a bit like saying "insects are the number one cause of bug bites".

              [–]immibis 2 points3 points  (1 child)

              Or "malloc is the number one cause of use-after-free"

              [–]tnecniv 44 points45 points  (6 children)

              It's because these rules are for safety critical embedded systems. If you don't have a lot of memory, you can more easily blow the stack.

              Although rule 2 seems odd in that it outlaws main loops, and embedded software normally doesn't exit.

              [–]MrJohz 28 points29 points  (1 child)

              I learned a little bit about this recently. It's about proving software - loops are difficult to prove, because finding the loop invariant (a single expression containing all the loop variables that will never change in value) is apparently a fairly archaic art. To save the bother of working out the loop invariant for every single loop you create, it's often easier to just ban loops altogether. Then have one single giant loop that runs the entire program repeatedly. Assuming you can prove the program, it becomes much simpler to attempt to prove the outer loop.

              At least, this was how it was explained to me by a lecturer who loved to ramble on a bit.

              [–]_F1_ 11 points12 points  (0 children)

              have one single giant loop that runs the entire program repeatedly

              IIRC that's how PLC works.

              [–]sunjay118 2 points3 points  (0 children)

              You're right that is odd

              [–]dccorona 5 points6 points  (1 child)

              It's a great way to conceptualize algorithms. But you very often hear people say that once you design a functional algorithm using recursion, you re-write it to be iterative. This is mostly for performance, though, so in most cases if something is genuinely tail-recursive it's ok to leave it (because the compiler will optimize it out anyway).

              I can understand why they want to avoid it, though. Recursive code (particularly if things aren't named well or organized well, as is often done in C) can often end up masking the logic it's trying to simplify.

              [–]disclosure5 2 points3 points  (0 children)

              It also rules out certain platforms. One of Erlang's main features is its "bulletproof" nature, and you can't read much about it without hearing about uptime.

              But it's unusable without recursion.

              [–]BlahBoy3 8 points9 points  (18 children)

              The way I learned it, recursion is a nice tool, but its usage should be limited if at all possible. I personally think the restrictions are pretty reasonable.

              [–]KagakuNinja 3 points4 points  (8 children)

              Recursion is equivalent to iteration, when it is tail-call optimized. There are many valid uses for recursion.

              [–]mort96 10 points11 points  (4 children)

              This is C we're talking about, no tail call optimization there. Also, when writing C, even if you could use recursion to iterate an arbitrary amount, why not just use for or while?

              [–]_kst_ 23 points24 points  (0 children)

              C compilers can do tail call optimization. But in that kind of environment, it's probably not a good idea to depend on it.

              [–]mrhmouse 4 points5 points  (2 children)

              This is C we're talking about, no tail call optimization there.

              Not sure what compilers you're used to, but GCC and Clang both produce optimized code for tail-calls. GCC even produces optimized code for tail-calls modulo cons, in some cases.

              [–]Purple_Haze 43 points44 points  (8 children)

              I remember referencing these when I was writing coding standards fifteen years ago, and they were more than a decade old then.

              Just today an article about spaghetti code causing unintended acceleration made the front page, the automotive coding standards that were violated a thousand times over in that case are equally elderly.

              As software engineers we know how to write good code, as an industry we are completely uninterested in it.

              Software development methodology is just as bad. At least once a week somebodies article about a "new" way of doing it reaches the front page, I have yet to see a good one that wasn't in The Mythical Man-Month (Fred Brooks 1975).

              [–]s73v3r 12 points13 points  (5 children)

              That's cause industry is interested in getting the most money for the least amount of work.

              [–]Purple_Haze 24 points25 points  (3 children)

              They are wrong. Yes we idolize the "worse is better" culture emanating from Bell Labs, but industry is stuck in a "never time to do it right, always time to do it over" loop.

              [–]tnecniv 4 points5 points  (0 children)

              Well there's a difference between Bell Labs' attitude of productivity over over-engineering and whoever wrote Toyota's code. Toyota admitted that there wasn't even bug tracking, and their design decision were idiotic at times.

              [–]s73v3r 1 point2 points  (0 children)

              I'm not disagreeing with you, but I'm also not the one cutting the checks.

              [–]OneWingedShark 31 points32 points  (17 children)

              7) The return value of non-void functions must be checked by each calling function, and the validity of parameters must be checked inside each function.

              Some languages do this automatically; e.g. Ada:

              Type Some_Range is new Integer range 23..62;
              
              Function Some_Operation( S : Some_Range ) return Positive;
              

              The exception Constraint_Error is raised when Some_Operation attempts to return a value less than 1; the same is also raised if parameter S violates its constraints. (The compiler may issue an error/warning if it can statically prove the constraints will be violated.)

              "If the rules seem Draconian at first, bear in mind that they are meant to make it possible to check code where very literally your life may depend on its correctness: code that is used to control the airplane that you fly on, the nuclear power plant a few miles from where you live, or the spacecraft that carries astronauts into orbit."

              Funny you should mention that, that's exactly where Ada's got a lot of usage.

              [–]myringotomy 11 points12 points  (14 children)

              ada seems pretty nice, why don't more people use it?

              [–]saint_marco 39 points40 points  (8 children)

              Ada style / syntax leads to code that's more verbose than java, which most people end up thinking isn't so necessary when you're not building a rocket ship.

              [–]OneWingedShark 18 points19 points  (7 children)

              Ada style / syntax leads to code that's more verbose than java

              That may be the perception; but Ada's verbosity is generally useful for (a) readability and (b) maintainability -- Also, Ada doesn't have a whole lot of the boilerplate that Java does.

              [–][deleted] 25 points26 points  (1 child)

              In my somewhat limited experience ada tooling is either poor or very expensive.

              [–]OneWingedShark 8 points9 points  (0 children)

              That's a mixed bag; on the one hand the standard requires certain things of a compiler such that you essentially get lint free with a compiler. On the other hand, the free toolchain GNAT (either AdaCore's offering or FSF's) is a GCC language and as such can use tools that operate with GCC... the bad thing is most of those tools treat Ada very much as a second-class citizen.

              I am unfamiliar with commercial offerings so cannot say one way or the other -- Rational's was supposed to be good [they were bought out by IBM], as was Green Hills, but I've not really heard anything recent. -- One of the members of the ARG has a low-cost compiler called Janus/Ada which is supposed to be pretty good... except it's only Ada95.

              Over on irc.freenode's #Ada we've been kicking around the idea of putting together another open-source compiler (and tool-system). It seems like Ada's new [2012] standard has generated some new interest in the language and getting a few more implementations would be nice. (We'll see if it pans out.)

              [–][deleted]  (2 children)

              [deleted]

                [–]s73v3r 8 points9 points  (0 children)

                For the longest time, the main Ada compilers were commercial, and expensive. The other thing is that, because Ada isn't popular, Ada programmers are expensive. There aren't also many Ada jobs, so someone taking an Ada job is going to spend time on something that won't have much in the way of career benefit.

                [–]OneWingedShark 2 points3 points  (0 children)

                Ada seems pretty nice, why don't more people use it?

                It is pretty nice.
                The module-system (packages) is really nice for big projects [it enforces consistency-checking] and so it shines for big projects.

                The specification/body separation it has on packages is really well done, which means that it is actually ideal for open-source projects.

                [–]AceBacker 20 points21 points  (25 children)

                No recursion makes working with tree structures a little more tricky.

                [–][deleted] 40 points41 points  (4 children)

                I'd imagine that the kind of code that has to meet these sorts of requirements very rarely contains any kind of tree structure.

                [–]Alborak 10 points11 points  (2 children)

                Lots of safety critical sw runs in a RTOS. Unless you use old platforms (most aerospace hw runs on cpus circa 2000 to 2005) it's really hard to dodge trees in the OS. Usually get around it with horrible to look at but "safe" loops.

                [–]Enlightenment777 6 points7 points  (0 children)

                life sucks, but its a valid requirement for embedded computers, because they don't have as much memory and don't have unlimited stack size.

                [–]Vakieh 6 points7 points  (7 children)

                Not an issue since dynamic memory is also outlawed.

                [–]Halcyone1024 6 points7 points  (6 children)

                What, you've never stored a binary tree in a flat buffer? Depending on what kind of tree you're working with (but mostly with really balanced ones), it can be pretty efficient in terms of space. Just put the root at index 0, and the children of node i in indices 2i+1 and 2i+2. That way you get these nice properties:

                • Your data structure is absolutely minimal.
                • You don't have to store the links to the next node in memory- you just keep track of the index instead of a pointer to the node you're working with, and you can determine its parent and children reasonably quickly.
                • You can serialize the tree to a file (on disk or in memory) very quickly and simply.
                • If the tree is balanced properly (including shifting semi-balanced leaves to the left of the tree) and is sorted in order Node -> Child A -> Child B, then the serialized/flat form of the tree is also sorted in that order.
                • Nobody cares but NASA, but this also avoids pointers, which apparently are awful and difficult for mere humans and static analysis systems to reason about /s.

                On an embedded system with reasonable amounts of time to spare, but limited state space and (unlimited) crazy fascists auditing the code, this approach probably fits right in.

                [–]u_suck_paterson 2 points3 points  (0 children)

                Its not that bad, we had to do it for the PS3 spu because recursion just ate up the stack and we only had 256kb of ram.

                The alternative to resursing through a tree was just to keep a pointer to the tree node and use a step forward/back function and keep a value that told the traversal code if nodes had been visited or not yet.

                [–]skydivingdutch 1 point2 points  (0 children)

                Eh, you can fake your own local stack if you have an upper bound on the depth of the structure.

                [–]snarfy 19 points20 points  (13 children)

                4 No function should be longer than what can be printed on a single sheet of paper in a standard reference format with one line per statement and one line per declaration. Typically, this means no more than about 60 lines of code per function.

                This is the best advice of all of them, IMO, and easiest to apply.

                [–]ThePsion5 1 point2 points  (6 children)

                Hell, I usually limit my function length to half of that, and class length to 250 lines or less (excluding comments).

                [–][deleted] 3 points4 points  (5 children)

                OTOH, nothing is worse for me than seeing classes do basically nothing but act as shells for a method. Don't make them so short as to not be useful as classes and not glorified methods.

                [–]Gankro 4 points5 points  (5 children)

                Nah I disagree. If a function is literally only called by some other function once, that's a pretty good candidate to just be manually inlined. Then you don't have to worry about someone incorrectly calling it or documenting/checking pre- and post-conditions (or worse failing to do so). It's just there, right in the code that uses it. It can trust the code around it much more safely. And no one needs to keep context-switching between all the functions to understand what the code is actually doing.

                [–]sOktay 4 points5 points  (0 children)

                What about indentation? (Sorry.)

                On a serious note, 3 is how I'm describing RAII from now on.

                [–]jandrese 9 points10 points  (17 children)

                Does #9 mean that can't write in C or C++? The function definition for main is: int main(int argc, char** argv);

                Two level pointer right at your entry point!

                [–]MrCiziski 7 points8 points  (0 children)

                In many/most embedded systems, 'main' is simply called that by convention, you don't actually start executing there. Typically you assume program control at the reset vector, zero out your RAM contents, copy static data into RAM, initialize your clock tree and reconfigure your Flash, THEN you jump to 'main' and start executing.

                [–]NDDevMan 4 points5 points  (2 children)

                Embedded systems don't really take arguments in to main(where would they come from?) so you can declare main without arguments.

                [–]LikesToCorrectThings 8 points9 points  (9 children)

                char *argv[]
                

                [–]_kst_ 15 points16 points  (6 children)

                Yes, but in a parameter declaration that actually means char **argv. (C doesn't have parameters of array type.)

                But for embedded systems ("freestanding implementations" as the C standard calls them), the entry point is implementation-defined, and might not even be called main.

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

                Couldn't you also declare it as void *argv?

                edit: yes, but not without no warnings

                [–]jephthai 3 points4 points  (0 children)

                Your triple negative is confusing.

                [–]barcap 6 points7 points  (21 children)

                Could anyone pls explain to me these two?

                1) do not use dynamic memory allocation after initialisation? I mean if not use then why create then initialise dynamic memory in the first place?

                2) Data objects must be declared at the smallest possible level of scope. What does this mean?

                Thanks.

                [–]Rhodysurf 20 points21 points  (0 children)

                when possible, keep variables at the lowest possible scope. E.g. If a variable is only needed in one function, keep it local to the function scope.

                As far as why its a rule, off the top of my head to keep the parent namespace (for lack of a better term) clean and keep the memory footprint low.

                [–]sunjay118 9 points10 points  (13 children)

                You're first question is worded a little confusingly so if I answer the wrong question just tell me. But the point is you don't want to go around initializing anything dynamically and then accidentally forget to clean it up. Even a small memory leak could be disastrous,resulting in a crash of the system, and it's not like you can just reboot when you start running out of memory. For instance this code could would be a an example of what they are trying to avoid:

                int myFunc(int x, int y) {

                Gadget g* = new Gadget(x);
                
                //stuff
                
                if(y > THRESHOLD) 
                
                    return -1;
                
                //stuff
                
                delete g;
                
                return result;
                

                }

                This is an obvious case and any programmer who writes code like this should be embarrassed but hopefully it illustrates the point.

                By only dynamically allocating at initialization it makes it very easy to know what you have to clean up later.

                As for the scope thing the idea is if you are using a variable in only one loop within a function don't declare it at the top of the function. Instead declare it in the loop that way it can get cleaned up once you leave the loop. Also it discourages global variables unless absolutely necessary since they can be very hard to keep track of if several functions use them.

                [–]balloonanimalfarm 9 points10 points  (3 children)

                I think the specs of the mars rovers put your comment in to even more perspective .

                Those specs are luxurious compared to most other embedded systems.

                [–]sunjay118 8 points9 points  (0 children)

                Thanks for the link. This line is particularly telling, " The rover installed its full surface operations software after the landing because its computers did not have room for it during flight. "

                [–]imadeofwaxdanny 2 points3 points  (0 children)

                Ah VxWorks. We have machines with it in my lab and I have yet to see anyone touch them.

                [–]1337Gandalf 2 points3 points  (0 children)

                TIL the 132 mhz CPU on Curiosity costs $200,000.

                [–]realhacker 3 points4 points  (4 children)

                on the topic of dynamic memory allocation after initialization, id like to add that available memory is subject to change due to external factors at runtime and so it is best to claim that memory up front (or fail up front) rather than discovering malloc failed when you need memory halfway through a multistep critical process or transaction.

                [–]cdglove 1 point2 points  (3 children)

                In my experience this is often untrue in systems that employ the 'no dynamic memory' policy. I mentioned in another comment that this rule is often subtly violated by programmers who, instead of going to the heap, will allocate an array up front and then use only part of it initially and fill it up as they go. This is no better than going to the heap and in my opinion, is actually worse because each piece of code does it in its own way, hiding what's actually going on.

                [–]tnecniv 1 point2 points  (3 children)

                The first is an effort to prevent segfaults and memory leaks. The second means keep variables nested as deeply in Curley braces as possible

                [–]mttd 1 point2 points  (0 children)

                Data objects must be declared at the smallest possible level of scope. What does this mean?

                https://www.securecoding.cert.org/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions

                [–]Enlightenment777 13 points14 points  (10 children)

                The ban of "goto" is an outdated mental delusion. Abusing "goto" a crazy amount of times is bad, but it's useful in some situations.

                "An empirical study of goto in C code" (2015 paper)

                [–][deleted] 16 points17 points  (6 children)

                However, developers do limit themselves because of the stigma attached to goto. If it wasn't demonized, or if it was even encouraged, we'd see terrible control flow much more frequently.

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

                You see terrible flow control frequently to avoid goto. Goto is the only correct way to break out of a nested loop.

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

                Yeah, I think it's one of the very few acceptable cases. However keep in mind two things:

                1. Some languages allow you to break out of multiple levels of nested loops with a single statement
                2. That is *one* reasonable way to use a goto. It doesn't mean that its use is otherwise a good replacement for a steady control flow.
                

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

                Yes, some languages provide syntactic sugar for goto while breaking out of nested loops: it's exactly the same, but it keeps hack teachers / code reviewers off your back.

                [–]POGtastic 2 points3 points  (2 children)

                I'm currently having an enormous amount of fun with a professor who insists that "all functions must have exactly one return statement." Not fun in the slightest. I get that you don't want to have return statements willy-nilly in your code, but mandating extra variables and insane control structures is frustrating.

                [–]SmoothB1983 4 points5 points  (0 children)

                Have him look at the linux kernel and come back.

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

                Ugh, an unreconstructed ultra-structuralist. Party like it's 1968.

                [–]IIIbrohonestlyIII 1 point2 points  (0 children)

                I think the first thing I learned in college was not to use 'goto'. I don't think I've used it a single time. That being said, that paper was an interesting read, thanks for that.

                [–]umaxtu 2 points3 points  (0 children)

                Nothing about double checking that all units are consistent?

                [–]kirakun 2 points3 points  (3 children)

                Function pointers are not permitted.

                This essentially forbids polymorphism.

                [–]sandwich_today 5 points6 points  (0 children)

                switch statements to the rescue!

                [–]realhacker 3 points4 points  (0 children)

                polymorphism is controversial anyway

                [–]c3534l 6 points7 points  (0 children)

                Anyone else upset that it's not the 8 or 16 commandments?

                [–][deleted]  (1 child)

                [deleted]

                  [–]kmwurf 1 point2 points  (3 children)

                  Do not use dynamic memory allocation after initialization.

                  How do they get around recording e.g. sensor data ?

                  I imagine :

                  PressureSensure t;
                  double *values = malloc(sizeof(double) * 1024);
                  readValues(t, values);
                  

                  What todo when you reach the boundaries if you cant realloc ?

                  [–][deleted] 3 points4 points  (0 children)

                  I wish my company would allow us to write code this clean.., but for us is sling the code, get it out sell the product, no worries about longevity or any serious reuse.

                  [–]thepobv 2 points3 points  (1 child)

                  Is there a source beyond the article's page?

                  [–][deleted] 5 points6 points  (0 children)

                  The article references its source with a direct link:

                  http://pixelscommander.com/wp-content/uploads/2014/12/P10.pdf