I have an architectural pattern that I use to accomplish the only two objectives that matter: 1) Speed of execution 2) Ease of maintenance
In my opinion absolutely everything else is, with one exception, irrelevant. You can evaluate whether or not software is crap with this simple formula: x = initial cost of development y = minimal required lifespan z = cost of maintenance during the length of y + costs of all associated penalties and harms during the length of y if x < z then your software is either a business failure or a costly hobby It is important to understand that this formula takes into account some minor level of risk management. It does not take into account definitions of what are acceptable initial costs, because that is presumed to be understood during planning before any code is written. Good programs are not written so that the programmer can give themselves a warm fuzzy to show off with unnecessary complexity or use frameworks to avoid addressing necessary concerns. Good programs work as intended and require as little maintenance as possible. The only other value worthy of consideration is detailed error reporting that describes what failed, what it was doing when it failed, and where it failed at. In my opinion, that is the opposite of error suppression, which is why I cannot stand most of the JS frameworks out there. Here is what I did for the Pretty Diff tool. If you want you can following along by passing the Pretty Diff code through the tool. tool: http://prettydiff.com/ code: http://prettydiff.com/prettydiff.js 1) I ALWAYS avoid use of object literals with only one exception. Object literals are the slowest containers in JavaScript, so therefore fast programs do not use them. The only one exception is that it is generally a good idea to use object literals to feed input into functions to avoid a massive list of arguments. For more information about this exception please read through the active thread here: Parameters vs. Objects as Parameters 2) I ALWAYS use a single var keyword per function and put it near the top of the function. The one var keyword is absolutely necessary for ease of maintenance and putting near the top is a good idea, because its going to be moved to the top of the function at execution time anyways. I say it is a requirement for ease of maintenance, because in complex applications there could be scope interference when a variable is re-scoped in an ancestor function and sometimes there may be no control to prevent such name collisions if different parties are writing different functions are different levels. It is nice to know where to look for variable as part of standard troubleshooting to quickly test for and/or identify the presence of such problems. The only code I put before the var keyword are return conditions. If, for example, a function is entered and the execution supplied by that function is either harmful or unnecessary it is convenient to supply an escape sequence before any other conditions are evaluated. 3) I ALWAYS use anonymous functions assigned to variables. There was some quote that went around from Brendan Eich that the "function" is too long and makes functional coding diffecult to read, but because I use assigned anonymous functions I do not encounter this problem. There are some rare cases where I use an unassigned anonymous function as an otherwise shallow container, but these rare cases are only used for condition encapsulation to ease readability and are not used to supply variable scope. 4) I ALWAYS separate DOM methods and all other code that must interface with the DOM from the application code. In the Pretty Diff example the DOM code is available for examination at http://prettydiff.com/pd.js This has three benefits: 4a) This helps to eliminate troubleshooting complexity associated with the DOM from the application. Those two pieces of code have completely separate objectives, and so their bugs should like wise be separated as necessary to reduce maintenance effort from enhancements. 4b) Code is much easier to read and understand when it is logically reduced into as many separated pieces as possible. 4c) This makes the application code platform neutral. The DOM code can be added for execution in a browser or eliminated for command line execution. Once the DOM code is isolated you only have to maintain a single piece of application code to enhance the application equally in all environments. 5) I ALWAYS seek to limit access to the DOM as much as possible, such as requesting nothing more than I absolutely need and never supplying such requests inside loops. Accessing the DOM in XML is great, but is a horrible bottleneck in HTML. This is because HTML standards and browsers have a legacy of supporting HTML code that is sloppy crap, and since the DOM is an abstract model of markup structure then therefore interpretation of the DOM is sloppy crap. I prefer to limit access only to the getElementById method and read element contents as string literals from the innerHTML property. If I have to write to the DOM I prefer to build content as an array and return it in an innerHTML property with a join method containing an empty string. In my opinion this is the fastest possible way to access the DOM, and so I structure my code accordingly. 6) I seek to avoid fanciness. I have nothing to prove to anybody else with my brilliant coding abilities in how elaborate my fantastic code is. If I want to be perceived as a decent programmer then I will use simple and predictable practices so that my application performs quickly and predictably. For loops I prefer a standard "for" loop, because in my opinion it is the most predictable. For conditions I prefer to use only "if/else if/else" conditions because while they are not as fast to execute as switch conditions they are more expressive and more predictable in their behavior. I never use empty conditions because condition fall through and condition trapping should always be predictable and intentional with known and testable alterations. I try to avoid multidimensional arrays, because they tend to be unnecessarily complicated, but this rule is not absolute. 7) Since I cannot stand error suppression I use the "use strict" statement to trigger strict mode. I want to know when I am screwing up so that I can fix the problem before it hits production. Sometimes errors slip out into production anyways, so is it more important to lie to suppress necessary all indications of the error to the users or expose your incompetence to your users. I would say the later is better. In my opinion it is better to have a minor showing of incompetence than a massive hidden failure, because a minor embarrassment costs less and is repaired more quickly than a massive unreported technology failure. If you follow those steps you will reveal a pattern of code that is easy to reproduce, easy to extend, and easy to maintain. The pattern that is revealed is the architecture I use in my own code. Austin Cheney, CISSP http://prettydiff.com/ -- To view archived discussions from the original JSMentors Mailman list: http://www.mail-archive.com/[email protected]/ To search via a non-Google archive, visit here: http://www.mail-archive.com/[email protected]/ To unsubscribe from this group, send email to [email protected]
