Code Complete: A Practical Handbook of Software Construction, Second Edition

Author: Steve McConnell
4.6
All Stack Overflow 109
This Year Stack Overflow 6
This Month Stack Overflow 1

Comments

by maynman   2019-01-15
Speaking from a software engineering perspective, here are a few that I found really valuable. I've seen them recommended by people I respect on many occasions.

Code Complete by Steve McConnell https://www.amazon.com/Code-Complete-Practical-Handbook-Cons...

The Mythical Man Month by Frederick Brooks https://www.amazon.com/Mythical-Man-Month-Software-Engineeri...

by anonymous   2019-01-13

From the looks of it there might be multiple things you can do to make things better, depending on your context.

But first, you need to know that management is a process, not a task, and it cannot be done only on "projects in progress". It starts way prior to that, with how you initiate a project, how you plan it, then you execute it (including analysis, design, programming, testing) and close it properly. Also, you need to monitor and control the project throughout. Missing the planning step and just focusing on already started projects will not yield positive results as you're already missing some vital steps. On the other hand, it seems to me that you might not have the proper development process, and tools/infrastructure and the programming culture within the team might be lacking.

Keep in mind there are some assumptions in my writing, so you decide what's useful, as you surely know your context better. Here are my 2 cents:

  • Establish and follow a software development process. Sounds to me that you may not have a well-established process on your side. There is no short answer to this, but as a minimum I highly recommend reading Software Project Survival Guide by Steve McConnell for a pragmatic approach to managing software projects. If you want something more modern it's a good idea to look into Scrum and Kanban after that. If you really want to go deep and understand all the facets of proper project management - read the PMP Exam prepbook for how a project (any sort of project) is generally managed. It is an exam preparation book but offers a nice condensed summary on the most crucial topics. It's the hardest path, but offers the greatest benefit. Be sure to read it last, as you might find it too complex if you start with it.

  • Establish good programming culture - it's important all people on the team to have proper working habits regarding programming. Another book by Steve McConnell is the undisputed classic here Code Complete: A Practical Handbook of Software Construction, 2nd Edition. Although a bit outdated, it contains huge amount of wisdom and will help you have the basis to then start researching on how to establish a modern continuous integration/continuous delivery environment. I also liked "The Pragmatic Programmer", but I am not sure how well it aged.

  • Use software tools that will help you with organizing your work and make it much easier to track what happens. Some examples of such software:

    • Trac is a minimalist software to track progress on issues, tasks and such, and it is also free.
    • Microsoft VSTS and also the Atlassian's suite offer much deeper solutions that help in establishing a full DevOps environment. They are paid through.

Hope that helps!

I know you probably expected a simpler answer, but the hard truth is that it would probably prove to be a long and tough journey. Good results always require persistence and hard work and there are rarely shortcuts.

by anonymous   2019-01-13

As an alternative to @Sweeper's answer, consider using the Arrays.copyOf() method, as suggested in this answer. Note that the copyOf() method is type-safe whereas the clone() method isn't.

double[] a, b, c;
c = Arrays.copyOf((b = Arrays.copyOf((a = new double[10]), a.length)), b.length);

But again, I'll reiterate as @Sweeper does, that this code really smells and you should consider doing it in multiple lines. As Steve McConnell says in Code Complete 2nd Ed., the Primary Technical Imperative of software is to manage complexity (i.e. make your code simple). This doesn't necessarily mean reducing the lines of code, but more to do with enabling people who read your code to understand what it does at a glance.

by anonymous   2019-01-13

Facts:

1. GIT and other version controls systems treat white-space differently

Based on my experience, we faced on our projects: GIT and other version controls systems treat invisible spaces + TABS differently, and it leads to changes in lines, which actually haven't been affected. It's easy not to notice, when there will accidentally added one space + TAB = indent looks the same in IDE, but GIT will make the difference when merging. It damages your ability to effectively compare revisions in source control, which is really scary. It never going to happen when you are having spaces only.

2. Neutralize difference in collaborator's environment (Editor, OS, preferences, etc.)

The tab width (in spaces) depends on your environment (text editor, OS, preferences, etc.), but the space width is the same everywhere. IDEs are smart enough to treat white spaces up to you personal taste, but the output generated for collaboration should be up to standards.

3. Developers who use spaces make more money than those who use tabs

Using spaces instead of tabs is associated with an 8.6% higher salary. Using spaces instead of tabs is associated with as high a salary difference as an extra 2.4 years of experience. (source: Stack Overflow 2017 Developer Survey).

4. Numerous studies on coding style importance

If every collaborator on your project would keep the same standards on coding - it will be good in long run, collaboration is more efficient and professional, the same indent when you refactor or develop. Studies regarding that:

  1. For example, Ben Shneiderman confirmed this in Exploratory experiments in programmer behavior:

    when program statements were arranged in a sensible order, experts were able to remember them better than novices. When statements were shuffled, the experts' superiority was reduced.

  2. An old 1984 study by Soloway and Ehrlich cited in Code Complete, and supported studies from The Elements of Programming Style:

    Our empirical results put teeth into these rules: It is not merely a matter of aesthetics that programs should be written in a particular style. Rather there is a psychological basis for writing programs in a conventional manner: programmers have strong expectations that other programmers will follow these discourse rules. If the rules are violated, then the utility afforded by the expectations that programmers have built up over time is effectively nullified.

by anonymous   2019-01-13

I think that in cases involving performance optimization, you really want to create an A/B test to determine which one you should do. There really is no cookie cutter answer for image preloading that applies to everybody as a best practice.

One of the biggest tenets of a favorite book of mine, Lean Enterprise, is use to A/B tests to prove or disprove a HIPPO (highly paid person's opinion). Certain opinions carry a lot of weight, both in your organization and on the internet. Because of their importance and reputation, their opinions veer towards the realm of fact, even though it may not be.

The practice of measuring performance empirically is also touted by another book I love which deals with performance tuning - Code Complete 2nd Ed. In that book, McConnell gives several code examples where you would expect one piece of code to be optimal, but in fact, it performed poorly (see chapters 25 and 26). One of his key points is that you should always test a performance optimization. If it isn't worth testing, it isn't worth writing the "highly performant" code in the first place. McConnell's premise doesn't just apply to his low level coding examples, but to high level decisions such as preloading images above the fold as well.

I can also attest to the importance of A/B testing at a professional level. I used to work on Amazon's SEO team and we A/B tested everything. The fact of the matter is that you never really know how customers will respond to something. Nobody can predict customer behavior - not even Jeff Bezos - and you really need to back up your hypothesis with real data to prove or disprove the validity of what you're doing.

Even though you can find multiple blog articles and online sources discussing whether preloading is better or not, you don't really know whether that will work for you until you've done it. Different people have different servers with different performance characteristics and different network topologies, etc. You just don't know which way is better for you until you have the data. If you launch your A/B test and find that find that your repel rate goes up when preloading, then you know that you have to dial back your treatment and return to your control. If however, you find that customers don't get bored waiting and click through at a higher rate than before, then you have a winner and you dial up the treatment - deleting the control code entirely after a period.

I hope that helps.

by ToFab123   2018-12-26
You could refresh your memories from the time before you started to complicate stuff by reading (or rereading) the marvelous book "code complete"

https://www.amazon.com/Code-Complete-Practical-Handbook-Cons...

by PiggySpeed   2018-11-10

If you want to improve your writing skills, you have to read good books and regularly practice good writing.

Read *good * coding techniques.

If you're just writing the same code you wrote the week before, you're not improving.

by samort7   2018-11-10

For anyone looking for general book suggestions, I always recommend they go with the classics:

EDIT: Updated with some more books I forgot initially, and links to the latest versions

General Computing

Computer Science

Software Development

Case Studies

Employment

Language-Specific

C

Python

C#

C++

Java

Linux Shell Scripts

Web Development

Ruby and Rails

Assembly

by sarevok9   2018-11-10

Well, since it's in js...sure.

  1. In index.php it's weird to me that you load each component separately. Why wouldn't you just load game.php which then includes the other assets? Making multiple calls makes them more likely to fail (for any, or no reason at all), this is another verbosity complaint -- (after writing the rest this seems like the least of our worries)

  2. There are no comments in your code ANYWHERE at all. Either you removed all the comments after the fact or you spent a TON of time struggling to remember what each piece of the program does.

  3. The amount of code here is staggering... truly. board.js is 3000 lines long. The word "this" is used 1797 times in that one file.

  4. There's a lot of things in here that are a little bit concerning. Tetris is a fairly easy game. You start on an empty board, and pieces (randomly generated / chosen) are loaded onto the top-center of the board and then an increasing amount of gravity carries them downwards. When the player presses a button the piece rotates. When a line (or multiple lines) are made, they are cleared and score is added to the player's total. When the player clears level 99 or blocks exceed the top, the game ends.
    In general this means that you really don't need a lot of code to do this -- you need: collision detection, row detection, simple "gravity" (which allows for changes to acceleration), score keeping, checking if either win or lose conditions are met, rotation and piece loading. With that kept in mind there's a lot of overthinking around the way to handle some of these concepts in your code. The code for "border" seems like it's both unnecessarily verbose and unnecessarily complex, also, your naming in this function is pretty terrible.

  5. There's a lot of stuff being done to generate specific screens (pause, curtain (game over?), etc. You should have a function which generates a screen that is simply blank -- or maybe a simple overlay of opacity to the game screen. The fact that each of these are generated in a verbose manner seems like overkill.

  6. Pieces.js feels over-engineered as well. In the solution that I described above in step 4 -- a piece just needs to be a simple shape mapping which can rotate on it's x axis by 90 degrees, queue / release piece feel like they should be an attribute of either game or piece, as those are what I feel like should be calling those methods.

  7. ui.js (Where I stopped reviewing after looking at about ~4500 lines of code) -- I think that UI.js runs into the same issue as the other files. Extreme overuse of "this". Like virtually every other function / file, it seems like you pass in basically every global variable at every time.

Upon running the game, it looked / played pretty well overall, but this definitely had the feel of "student project" to me. Based on this code I think I can assert 3 things about you:

  1. You're the type of person who gets themselves into a bind, and rather than thinking about the "how" of a solution, and the best / simplest ways to implement a solution, you charge forward and add more functions / handlers / pass in more variables so that "Oh, this isn't in scope? Well fuck that, now it is!" without any second thoughts... which is perfectly fine, but it does make someone who's been coding for a while look and go "Are all these things really necessary?" In my head I don't think so.

  2. You are the only author of the project -- if you were working with anyone else on this it would have become too verbose / hard to read for anyone else to contribute.

  3. Overall I feel like you show promise and that you could get into a career in CS -- but you'd probably come in as a junior and need to be kept close to someone with more experience than you.

There's a few sins in here that seem really avoidable to me, and others where it seems like you backed yourself into a corner. I'd strongly recommend a copy of code complete for quiet downtime / train rides / whatever (https://toptalkedbooks.com/amzn/0735619670 ) as there's a fair number of practices in here which may help you (variable naming, what to pass / how to structure).

Hopefully you take this in the spirit which I wrote it -- the code does absolutely what it's intended to do, so, good on you. My concern as someone who manages a team of engineers is, if something in there ever broke, we'd have a hell of a time fixing it.

Good luck :)

by YuleTideCamel   2018-11-10

Books would be good. Most technical books work better if you can immediately try the examples, but having a bookmark or something to remind you to try later would be good.

Another would be read some books that are programming related but not an introduction to a programming language or such. For example:

Another thing to consider is videos, a lot of online courses allow you to download videos to your phone. Though imo, they are hard to follow on a small screen as they will show code and you'll end up squinting a lot :)

by fdsvnsmvas   2018-09-13
Thanks everyone, the comments are much appreciated. Here's a list of books and other media resources recommended so far in the thread:

Robert C. Martin, Clean code: https://www.amazon.com/Clean-Code-Handbook-Software-Craftsma...

Vaughn Vernon, various: https://www.amazon.com/Code-Complete-Practical-Handbook-Cons... 2

Clean coder: https://www.amazon.com/Pragmatic-Programmer-Journeyman-Maste...

Hitchhiker's Guide to Python: https://www.amazon.com/Art-Readable-Code-Practical-Technique...

John Ousterhout, A Philosophy of Software Design: https://www.amazon.com/Philosophy-Software-Design-John-Ouste... This one looks particularly interesting, thanks AlexCoventry!

Kent Beck, Test Driven Development: https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/...

Dan Bader, Python Tricks: The Book: https://www.amazon.com/Software-Engineering-10th-Ian-Sommerv...

Svilen Dobrev, various: http://www.svilendobrev.com/rabota/

by anonymous   2018-03-19

You cannot set the default values for your enum members, only for whole enum. Default value for it is 0, which goes to first element of enum. Other enum members should differ from that value, otherwise they simply override it. In this case:

enum Foo { Bar=0, Baz=0, bread=0, jam=0 };

You're saying to compiler: OK, now they 0 will be named as Bar. Ok, now 0 will be named as Baz, and so on. It doesn't make any sence for compiler.

In a book Code Complete one can find an advice to introduce a default enum member named like None and explicitly assign it to 0 and place it at first place of your enum. So, your code could looks like this:

enum Foo
{
    None = 0,
    Bar, // 1
    Baz, // 2
    bread, // 3
    jam // 4
};
by anonymous   2018-03-19

You should use the file option to initialize the photo image object.
This means you need to change photo = PhotoImage("eh.gif") to photo = PhotoImage(file="eh.gif")

Now your code will work. But a working code is not necessarily a good code. There are other issues with your code. Let me go through them quickly:

  • It is better to code import Tkinter as Tk than from Tkinter import *
  • Why that hyphen in your class name? Follow PEP8 so that, in the futur, people will find it easy to review and understand your code.
  • Good that you have written self.master = master (read complete code to know why) but then you have never used it. This means you made a good decision and you render it useless.
  • You set the title of the window within the initializer. It is better if you do that in a separate function so that whenever you want to add additional settings to your GUI (such as the size, font or whatever) you will only add code to that function instead of vomiting lot of trash inside the initializer which rather needs to be clean.
  • None of the widgets you created is 'selfed' (you may read Why explicit self has to stay)
  • It is better you create the widgets in a separate function otherwise your __init__() will be dirty.
  • Why do you use return in prank() and close_window()? By default, Python functions that do not return something return None anyway so it is useless to code that.
  • Why did you pack one button to left and the other one to right and then no pack siding for the label? Read about the pack() geometry manager.
  • Why you did not attach the label to a parent widget as you did for the 2 other buttons? All Tkinter widgets need to be clung into a parent widget. The grand parent of those widgets is an instance of Tkinter.Tk()
  • Why did you create that frame and then you never used it? You are not doing anything with it, so ..?

Given these remarks, I want to provide you an improved -but not perfect- version of your program. You can then follow this 'philosophy' to add or modifying existing widgets:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Tkinter as Tk
from PIL import ImageTk

class FakeVirus:
   def __init__(self, master):
       self.master = master
       self.configure_gui()
       self.create_widgets()

   def configure_gui(self):
       self.master.title('Totally not a virus!')

   def create_widgets(self):
       self.create_buttons()
       self.create_label_for_image()

   def create_buttons(self):
       self.help = Tk.Button(self.master, text='Help', command=self.prank)
       self.help.pack(side=Tk.LEFT)
       self.quit = Tk.Button(self.master, text='Close', command=self.close_window)
       self.quit.pack(side=Tk.LEFT)

   def create_label_for_image(self):
       self.image_label = Tk.Label(self.master)
       self.image_label.pack(side=Tk.LEFT)
       self.load_image_to_label()

   def load_image_to_label(self):
       self.photo = ImageTk.PhotoImage(file='eh.gif')
       self.image_label.image = self.photo
       self.image_label.config(image=self.photo)

   def prank(self):
       print "work"

   def close_window(self):
        root.destroy()

if __name__ == '__main__':
   root = Tk.Tk()
   my_gui = FakeVirus(root)
   root.mainloop()

The output of the above program is:

enter image description here

by anonymous   2018-03-19

The build is deterministic, is the result of running VS builder or MSBuild on the solution file and the project files. They define strictly what assemblies are produced, there is no flexibility there. The general rule is "one .csproj file produces one assembly". And one .cs file belongs to one .csproj.

As for you modifying the access of a method or type to internal and then discovering at runtime that something is broken, you can rest assured: the discovery occurs at compile time. Your code won't even compile anymore.

Also, your binary 'may or may not work' seems like you're missing basic unit tests. Add unit tests, make them part of your build, and then you'll know if the code works or not (at least the part that is tested). Integration tests also help. Get started with developer testing tools.

Also, read Code Complete. So many of your questions were answered years ago and is sad to see them come back again and again.

by anonymous   2018-01-01

You don't need var before variables here

function doGetWord(){
            var word = F.gword.value;
            var wLength = word.length;

As the idea is to save this values in scope of parent function. And you might replace the letters like this

const letters = document.getElementById("dword").textContent.split('');
letters[i] = dummy;
document.getElementById("dword").textContent = letters.join('');

You are using bad variable names and a lot of global variables, it might be a good practice to work of this. I recommend reading a book on general programming, something like https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670 and something more specific to javascript (to get the concept of scopes) https://www.manning.com/books/secrets-of-the-javascript-ninja

    <!DOCTYPE html>
    <html>

      <head>
        <title>Story</title>
        <script data-require="jquery@*" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        <style>
            /*body {
                font-family: Calibri;
                font-size: 13.5pt;
                margin-left: 5px;
                color: black;
            }*/

            #aa{
                border: 1px solid black;
            }

            /*.in2{
                width: 300px;
                height: 630px;
                border: 0px solid white;
                background-color: white;
                color: white;
                font-family: Arial;
                font-size: 25pt;
            }*/
        </style>
        <script src="jquery-3.2.1.js"></script>
        <script type="text/javascript">
            var word = "" //word variable
            var wLength = 0 //word length variable
            var dummy = "" //letter guessed
            var dm = new Array(26)


            $(document).ready(function(){
                $("input.in2").hide()
            })

            $(document).ready(function(){
                $("input.bi2").hide()
            })

            function doGetWord(){
                word = F.gword.value;
                wLength = word.length;
                for(var i = 0; i < wLength; i++){
                    document.getElementById("dword").innerHTML += "_ "
                }
                $("input.wordi").hide()
                $("input.bi").hide()
                $("input.in2").show()
                $("input.bi2").show()
            }

            function doGuess(){
                dummy = F.t.value
                if(dummy.length > 1){
                    dummy = ""
                    F.t.value = ""
                }
                else{
                    F.t.value = ""
                    alp = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
                    dd = dummy.toString()
                    window["cl" + dd]
                    if(window["cl" + dd] == false){
                        alert("Letter already used, please try again with another letter")
                        dummy = ""
                        F.t.value = ""
                    }
                    else{
                        window["cl" + dd] = false
                        F.t.value = ""
                        doGuessWord();
                    }
                }
            }

            function doGuessWord(){
                const letters = document.getElementById("dword").textContent.split(' ');
                for(i = 0; i < wLength; i++){
                    if(dummy === word.charAt(i)) {
                        letters[i] = dummy;
                    }
                }
                document.getElementById("dword").textContent = letters.join(' ');
            }
        </script>
      </head>

      <body>
        <form name="F">
          <input type="text" name="gword" class="wordi" />
          <input type="text" name="t" class="in2" />
          <input type="button" name="b" value="do" onclick="doGetWord()" class="bi" />
          <input type="button" name="b2" value="do" onclick="doGuess()" class="bi2" />
          <div id="dword"></div>
        </form>
      </body>

    </html>

by anonymous   2017-08-20

For decades programmers have often spent time making software worse by applying practices they don't understand, rather than learning why that practice is good. The use of certain tools/keywords/frameworkes can make a programmer feel sophisticated, when they're just screwing things up. Some common examples:

  • Throwing in lots of try/catch/finally blocks can make a programmer feel like they have an error handling scheme, when in fact they don't.
  • Replacing sql with stored procedures can make programmers feel like they have a data access layer that magically gives them efficiency, reuseability, encapsulation, when in fact they don't.
  • Using classes makes many programmers believe they're engaging in object oriented programming, when in fact they aren't (or are only scratching the surface of OO).

This list could go on forever. This tendency has always been around and always will be, because we humans always look for shortcuts. We see this a lot with patterns now because patterns are currently popular. The root problem is the same: developers not having a respect for how complicated software development is, and thinking a blindly implemented pattern or practice is a substitute for learning and humility.

The solution? Difficult to say. You can't go to wrong though handing a junior developer Code Complete or some such, to help them understand this is all about applying principles to particular situations, and that great developers keep it simple.