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 Reddit 5

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

4.6

Review Date:

Comments

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.