Nikola Brežnjak blog - Tackling software development with a dose of humor
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Home
Daily Thoughts
Ionic
Stack Overflow
Books
About me
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Nikola Brežnjak blog - Tackling software development with a dose of humor
Programming

Code Complete 2 – Steve McConnell – The Software-Quality Landscape

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types
  • Chapter 15: Using Conditionals
  • Chapter 16: Controlling Loops
  • Chapter 17: Unusual Control Structures
  • Chapter 18: Table-Driven Methods
  • Chapter 19: General Control Issues

⚠️ Users care about whether the software is easy to use, not about whether it’s easy for you to modify. They care about whether the software works correctly, not about whether the code is readable or well structured.

⚠️ The General Principle of Software Quality is that improving quality reduces development costs. Understanding this principle depends on understanding a key observation: the best way to improve productivity and quality is to reduce the time spent reworking code.

Characteristics of Software Quality

The software has both external and internal quality characteristics. External characteristics are characteristics that a user of the software product is aware of, including the following:

  • Correctness
    • The degree to which a system is free from faults in its specification, design, and implementation
  • Usability
    • The ease with which users can learn and use a system
  • Efficiency
    • Minimal use of system resources, including memory and execution time
  • Reliability
    • The ability of a system to perform its required functions under stated conditions whenever required – having a long mean time between failures
  • Integrity
    • The degree to which a system prevents unauthorized or improper access to its programs and its data. The idea of integrity includes restricting unauthorized user accesses as well as ensuring that data is accessed properly
  • Adaptability
    • The extent to which a system can be used, without modification, in applications or environments other than those for which it was specifically designed
  • Accuracy
    • The degree to which a system, as built, is free from error, especially with respect to quantitative outputs. Accuracy differs from correctness; it is a determination of how well a system does the job it’s built for rather than whether it was built correctly
  • Robustness
    • The degree to which a system continues to function in the presence of invalid inputs or stressful environmental conditions

Programmers care about the internal characteristics of the software as well as the external ones. So here is a list of internal quality characteristics:

  • Maintainability
    • The ease with which you can modify a software system to change or add capabilities, improve performance, or correct defects
  • Flexibility
    • The extent to which you can modify a system for uses or environments other than those for which it was specifically designed
  • Portability
    • The ease with which you can modify a system to operate in an environment different from that for which it was specifically designed
  • Reusability
    • The extent to which and the ease with which you can use parts of a system in other systems
  • Readability
    • The ease with which you can read and understand the source code of a system, especially at the detailed-statement level
  • Testability
    • The degree to which you can unit-test and system-test a system; the degree to which you can verify that the system meets its requirements
  • Understandability
    • The ease with which you can comprehend a system at both the system-organizational and detailed-statement levels. Understandability has to do with the coherence of the system at a more general level than readability does

The attempt to maximize certain characteristics inevitably conflicts with the attempt to maximize others. Finding an optimal solution from a set of competing objectives is one activity that makes software development a true engineering discipline. But then again, that doesn’t mean that there has to be a tradeoff with another characteristic. Sometimes one hurts another, sometimes one helps another, and sometimes one neither hurts nor helps another. For example, focusing on adaptability helps robustness and vice versa.

Techniques for Improving Software Quality

Although it might seem that the best way to develop a high-quality product would be to focus on the product itself, in software quality assurance you also need to focus on the software development process. Here are a few tips for improving software-quality:

  • Setting explicit quality goals
  • Making the quality assurance activity explicit makes the priority clear, and the programmers will respond by focusing more on quality rather than how quickly they “complete” their programs
  • Developing a testing strategy
  • Informal technical reviews
  • Formal technical reviews

Relative Effectiveness of Quality Techniques

The various quality-assurance practices don’t all have the same effectiveness. Here are some quality-assurance practices:

  • Informal design reviews
  • Formal design inspections
  • Informal code reviews
  • Formal code inspections
  • Modeling or prototyping
  • Unit tests
  • Personal des-checking of code

Percentage of Defects Detected

Used on their own, the techniques detect on the average only about 40% of the errors. The strong implication is that if project developers are striving for a higher defect-detection rate, they need to use a combination of techniques. A study by Glenford Myers shows that using any combination of techniques increased the total number of defects found by a factor of almost 2.

Cost of Finding and Fixing Defects

Most studies have found that inspections are cheaper than testing. A study at the Software Engineering Laboratory found that code reading detected about 80% more faults per hour than testing. Another organization found that it cost six times as much to detect design defects by using testing as by using inspections.

As it was mentioned in previous chapters about design, the longer a defect remains in the system, the more expensive it becomes to remove. So a technique that catches the error earlier reduces the cost of fixing it. Even more important is whether the technique detects the symptoms and causes of defects in one step, e.g. inspections, or like testing, finds symptoms but require additional work to diagnose and fix the root cause.

The bottom line is that for a quality program you must use a combination of techniques, here’s my recommendation:

  • Formal inspections of all requirements, all architecture, and designs for critical parts of the system
  • Modeling or prototyping
  • Code reading or inspections
  • Execution testing

The general Principle of Software Quality

The General Principle of Software Quality is that improving quality reduces development costs. Understanding this principle depends on understanding a key observation: the best way to improve productivity and quality is to reduce the time spent reworking code.

The industry average productivity for a software product is about 10 to 50 of lines of delivered code per person per day (including all noncoding overhead). Part of the reason for these seemingly low productivity figures is that industry average numbers like these factor nonprogrammer time into the lines-of-code-per-day figure. But the single biggest activity on most projects is debugging and correcting code that doesn’t work properly.

The study at IBM produced similar findings:

Software projects with the lowest levels of defects had the shortest development schedules and the highest development productivity. Software defect removal is actually the most expensive and time-consuming form of work for software.

Keynote that you should take from this chapter is that quality is free, in the end, but it requires a reallocation of resources so that defects are prevented cheaply instead of fixed expensively ?

Programming

Code Complete 2 – Steve McConnell – General Control Issues

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types
  • Chapter 15: Using Conditionals
  • Chapter 16: Controlling Loops
  • Chapter 17: Unusual Control Structures
  • Chapter 18: Table-Driven Methods

Boolean Expressions

Except for the simplest control structure, the one that calls for the execution of statements in sequence, all control structures depend on the evaluation of boolean expressions.

Using true and false for Boolean Tests

Use the identifiers true and false in boolean expressions rather than using values like 0 and 1.

You can write clearer tests by treating the expressions as boolean expressions. For example, write

while ( !done ) ...
while ( a > b ) ...

rather than

while ( done == false ) ...
while ( (a > b) == true ) ...

Using implicit comparisons reduces the numbers of terms that someone reading your code has to keep in mind, and the resulting expressions read more like conversational English.

Making Complicated Expressions Simple

Break complicated tests into partial tests with new boolean variables rather than creating a monstrous test with half a dozen terms, assign intermediate values to terms that allow you to perform a simpler test.

Move complicated expressions into boolean functions if a test is repeated often or distracts from the main flow of the program. For example:

If ( ( document.AtEndOfStream ) And ( Not inputError ) ) And 
    ( ( MIN_LLINES <= lineCount ) And ( lineCount <= MAX_LINES ) ) And 
    ( Not ErrorProcessing() ) Then
    ...
End If

This is an ugly test to have to read through if you’re not interested in the test itself. By putting it into a function, you can isolate the test and allow the reader to forget about it unless it’s important.

If ( DocumentIsValid( document , lineCount, inputError) ) Then
    ' do something other
    ...
End If

If you use the test only once, you might not think it’s worthwhile to put it into a routine. But putting the test into a well-named function improves readability and makes it easier for you to see what your code is doing, and that’s sufficient reason to do it.

Forming Boolean Expressions Positively

I ain’t not no undummy.

~ Homer Simpson

Not a few people don’t have not any trouble understanding a nonshort string of nonpositives-that is, most people have trouble understanding a lot of negatives.

You can do several things to avoid complicated negative boolean expressions in your program:

  • In if statements, convert negatives to positives and flip-flop the code in the if and else clauses
    • You shouldn’t write if ( !statusOK ). Alternatively, you could choose a different variable name, one that would reverse the truth value of the test. In the example, you could replace statusOK with ErrorDetected, which would be true when statusOK was false.
  • Apply DeMorgean’s Theorems to simplify boolean test with negatives
    • DeMorgan’s Theorem lets you exploit the logical relationship between an expression and version of the expression that means the same thing because it’s doubly negated. For example:

if ( !displayOK || !printerOK ) ...

This is logically equvalent ot the following:

if ( !( displayOK && printerOK ) ) ...

Using Parentheses to Clarify Boolean Expressions

Using parentheses isn’t like sending a telegram: you’re not charged for each character – the extra characters are free.

Knowing How Boolean Expressions Are Evaluated

The pseudocodeThe pseudocode example of when “short-circuit” or “lazy” evaluation is necessary:

while( i < MAX_ELEMENTS and item[ i ] <> 0 ) ...

If the whole expression is evaluated, you’ll get an error on the last pass through the loop. The variable i equals MAX_ELEMENTS, so the expression item[ i ] is an array-index error.

In the pseudocode, you could restructure the test so that the error doesn’t occur:

while ( i < MAX_ELEMENTS )
    if (item[ i ] <> 0 ) then 
        ...

C++ uses short-circuit evaluation: if the first operand of the and is false, the second isn’t evaluated because the whole expression would be false anyway.

Write Numeric Expressions in Number-Line Order

MIN_ELEMENTS <= i and i <= MAX_ELEMENTS

The idea is to order the elements left to right, from smallest to largest. In the first line, MIN_ELEMENTS and MAX_ELEMENTS are the two endpoints, so they go at the ends. The variable i is supposed to be between them, so it goes in the middle.

Compound Statements (Blocks)

A “compound statement” or “block” is a collection of statements that are treated as a single statement for purposes of controlling the flow of a program. Compound statements are created by writing { and } around a group of statements in C++, C#, C, and Java.

⚠️ Use the block to clarify your intentions regardless of whether the code inside the block is 1 line or 20.

Taming Dangerously Deep Nesting

Excessive indentation, or “nesting,” has been pilloried in computing literature for 25 years and is still one of the chief culprits in confusing code.

Many researchers recommend avoiding nesting to more than three or four levels (Myers 1976, Marca 1981, and Ledgard and Tauer 1987a). Deep nesting works against what Chapter 5 describes as Software’s Major Technical Imperative: Managing Complexity. That is reason enough to avoid deep nesting.

It’s not hard to avoid deep nesting. If you have deep nesting, you can redesign the tests performed in the if and else clauses or you can break the code into simpler routines. Here are the tips to reduce the nesting depth:

Simplify the nested if by testing part of the condition

if ( inputStatus == InputStatus_Success ) {
   // lots of code
   ...
   if ( printerRoutine != NULL ) {
    // lots of code
        ...
        if ( SetupPage() ) {
            // lots of code
            ...
            if ( AllocMem( &printData ) ) {
                // lots of code
                ... 
        }
    } 
}

Here’s the code revised to use retesting rather than nesting:

if ( inputStatus == InputStatus_Success ) {
   // lots of code
   ...
   if ( printerRoutine != NULL ) {
      // lots of code
... }
}
if ( ( inputStatus == InputStatus_Success ) &&
   ( printerRoutine != NULL ) && SetupPage() ) {
   // lots of code
   ...
   if ( AllocMem( &printData ) ) {
      // lots of code
      ...
    } 
}

This is a particularly realistic example because it shows that you can’t reduce the nesting level for free; you have to put up with a more complicated test in return for the reduced level of nesting.

Simplify a nested if by using break

If some condition in the middle of the block fails, execution continues at the end of the block.

do {
   // begin break block
   if ( inputStatus != InputStatus_Success ) {
      break; // break out of block
   }
   // lots of code
   ...
   if ( printerRoutine == NULL ) {
      break; // break out of block
   }
   // lots of code
   ...
   if ( !SetupPage() ) {
      break; // break out of block
   }
   // lots of code
   ...
   if ( !AllocMem( &printData ) ) {
      break; // break out of block
   }
   // lots of code
   ...
} while (FALSE); // end break block

This technique is uncommon enough that it should be used only when your entire team is familiar with it.

Convert a nested if to a set of if-then-elses

If you think about a nested if test critically, you might discover that you can reorganize it so that it uses if-then-elses rather than nested ifs. Suppose you have a busy decision tree like this:

if ( 10 < quantity ) {
   if ( 100 < quantity ) {
      if ( 1000 < quantity ) {
        discount = 0.10;
      } 
      else {
        discount = 0.05;
      }
    }
    else {
      discount = 0.025;
    } 
}
else {
   discount = 0.0;
}

You can reorganize the code for better readability and reduced complexity:

if ( 1000 < quantity ) {
   discount = 0.10;
}
else if ( 100 < quantity ) {
   discount = 0.05;
}
else if ( 10 < quantity ) {
   discount = 0.025;
}
else {
   discount = 0;
}

Convert a nested if to a case statement

You can recode some kinds of tests, particularly those with integers, to use a case statement rather than chains of ifs and elses. You can’t use this technique in some languages, but it’s a powerful technique for those in which you can.

Factor deeply nested code into its own routine

If deep nesting occurs inside a loop, you can often improve the situation by putting the inside of the loop into its own routine. This is especially effective if the nesting is a result of both conditionals and iterations. Leave the if-then-else branches in the main loop to show the decision branching, and then move the statements within the branches to their own routines.

The new code has several advantages. First, the structure is simpler and easier to understand. Second, you can read, modify, and debug the shorter while loop on one screen; it doesn’t need to be broken across the screen or printed- page boundaries.

⚠️ Complicated code is a sign that you don’t understand your program well enough to make it simple.

A Programming Foundation: Structured Programming

The core of structured programming is a simple idea that a program should use only one-in, one-out control constructs (also called single-entry, single-exit control constructs).

A structured program progresses in an orderly, disciplined way, rather than jumping around unpredictably. You can read it from top to bottom, and it executes in much the same way.

The Three Components of Structured Programming

  • Sequence
    • A sequence is a set of statements executed in order. Typical sequential statements include assignments and calls to routines.
  • Selection
    • A selection is a control structure that causes statements to be executed selectively. The if-then-else statement is a common example.
  • Iteration
    • An iteration is a control structure that causes a group of statements to be executed multiple times. An iteration is commonly referred to as a “loop”.
  • The core thesis of structured programming is that any control flow whatsoever can be created from these three constructs of sequence, selection, and iteration (Böhm Jacopini 1966).

How important is complexity?

The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility

~ Edsger Dijkstra

Control-flow complexity is important because it has been correlated with low reliability and frequent errors.

Programming

Code Complete 2 – Steve McConnell – Table-Driven Methods

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types
  • Chapter 15: Using Conditionals
  • Chapter 16: Controlling Loops
  • Chapter 17: Unusual Control Structures

Table-driven code can be simpler than complicated logic using ifs. Suppose you wanted to classify characters into letters, punctuation marks, and digits; you might use a logic like this one (Java):

if ( ( ( 'a' <= inputChar ) && (inputChar <= 'z' ) )  || ( ( 'A' <= inputChar ) && (inputChar <= 'Z' ) ) ) {
    charType = CharacterType.Letter;
}
else if ( ( inputChar == ' ' ) || ( inputChar == ',' ) ||( inputChar == '.' ) || ( inputChar == '!' ) || 
    ( inputChar == '(' ) || ( inputChar == ')' ) || 
    ( inputChar == ':' ) || ( inputChar == ';' ) ||
    ( inputChar == '?' ) || ( inputChar == '-' ) ) {

    charType = CharacterType.Punctuation;
} else if ( ( '0' <= inputChar ) && ( inputChar <= '9' ) ) {
    charType = CharacterType.Digit;
}

Two Issues in Using Table-Driven Methods:

  • how to look up entries in the table
  • what to store in the table
    • the result of table lookup can be data, but also an action. In such case, you can store a code that describes the action, or in some languages, you can store a reference to the routine that implements the action. In either of these cases, tables become more complicated.

How to look up entries in the table

You can use some data to access a table directly. If you need to classify the data by month, for example, you can use an array with indexes 1 through 12.

Other data is too awkward to be used to look up a table entry directly. If you need to classify data by Social Security Number, for example, you can’t use the Social Security Number to key into the table directly unless you can afford to store 999-99-9999 entries in your table. You’re forced to use a more complicated approach. Here’s a list of ways to look up an entry in a table:

  • Direct access
  • Indexed access
  • Stair-step access

Direct Access Tables

Suppose you need to determine the number of days per month (forgetting about leap year, for the sake of argument). A clumsy way to do it, of course, is to write a large if statement:

if ( month == 1 ) {
    days = 31;
} else if ( month == 2 ) {
    days = 28;
}
// ...for all 12 months, you get the point
else if ( month == 12 ) {
    days = 31;
}

An easier and more modifiable way to perform the same function is to put the data in a table:

int daysPerMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Now, instead of using the long if statement, you can just use simple array access to find out the number of days in a month:

days = daysPerMonth[ month - 1 ];

Indexed access Tables

Sometimes a simple mathematical transformation isn’t powerful enough to make the jump from data like Age to a table key.

Suppose you run a warehouse and have an inventory of about 100 items. Suppose further that each item has a four-digit part number that ranges from 0000 through 9999.

First, if each of the entries in the main lookup table is large, it takes a lot less space to create an index array with a lot of wasted space than it does to create a main lookup table with a lot of wasted space.

For example, suppose that the main table takes 100 bytes per entry and that the index array takes 2 bytes per entry. Suppose that the main table has 100 entries and that the data used to access it has 10,000 possible values.

In such a case, the choice is between having an index with 10,000 entries or the main data member with 10,000 entries. If you use an index, your total memory use is 30,000 bytes. If you forgo the index structure and waste space in the main table, your total memory use is 1,000,000 bytes.

That means you waste 97% less memory with indexed access tables.

Stair-Step Access Tables

Another kind of table access is the stair-step method. This access method isn’t as direct as an index structure, but it doesn’t waste as much data space.

The general idea of stair-step structures is that entries in a table are valid for ranges of data rather than for distinct data points.

For example, if you’re writing a grading program, here’s a range of grades you might have to program:

> 90.0% A
< 90.0% B
< 75.0% C
< 65.0% D
< 50.0% F

This is an ugly range for a table lookup because you can’t use a simple data-transformation function to key into the letters A through F. An index scheme would be awkward because the numbers are floating points. You might consider converting the floating-point numbers to integers, and in this case, that would be a valid design option, but for the sake of illustration, this example will stick with floating point.

Here’s the code in Visual Basic that assigns grades to a group of students based on this example.

' set up data for grading table
Dim rangeLimit() As Double = { 50.0, 65.0, 75.0, 90.0, 100.0 }
Dim grade() As String = { "F", "D", "C", "B", "A"}
maxGradeLevel = grade.Length - 1
...
' assign a grade to a student based on the student's score
gradeLevel = 0
studentGrade = "A"
while ( ( studentGrade = "A" ) and ( gradeLevel < maxGradeLevel) ) 
    If ( studentScore < rangeLimit( gradeLevel ) ) Then
        studentGrade = grade( gradeLevel )
    End If
    gradeLevel = gradelevel + 1
wend

Although this is a simple example, you can easily generalize it to handle multiple students, multiple grading schemes, and changes in the grading scheme.

The advantage of this approach over other table-driven methods is that it works well with irregular data. The grading example is simple in that although grades are assigned at irregular intervals, the numbers are “round,” ending with 5s and 0s. The stair-step is equally well suited to data that doesn’t end neatly with 5s and 0s. You can use the stair-step approach in statistics work for probability distributions with numbers like this:

Probability Insurance Claim Amount
0.456935 $0.00
0.546654 $254.32
0.627782 $514.77
0.771234 $717.82

Ugly numbers like these defy any attempt to come up with a function to neatly transform them into table keys. The stair-step approach is the answer.

⚠️ Tables can provide an alternative to complicated logic, so ask yourself whether you could simplify by using a lookup table.

Programming

Code Complete 2 – Steve McConnell – Unusual Control Structures

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types
  • Chapter 15: Using Conditionals
  • Chapter 16: Controlling Loops

Recursion

For a small group of problems, recursion can produce simple, elegant solutions. For a slightly larger group of problems, it can produce simple, elegant, hard-to-understand solutions. ?

Java Example:

void QuickSort( int firstIndex, int lastIndex, String [] names ) {
    if ( lastIndex > firstIndex ) {
        int midPoint =  Partition( firstIndex, lastIndex, names );
        QuickSort( firstIndex, midPoint-1, names );
        QuickSort( midPoint+1, lastIndex, names );            
    }
}

In this case, the sorting algorithm chops an array in two and then calls itself to sort each half of the array. When it calls itself with a subarray that’s too small to sort-such as ( lastIndex <= firstIndex ) – it stops calling itself.

Tips for Using Recursion

  • Make sure the recursion stops – Check the routine to make sure that it includes a nonrecursive path.
  • Limit recursion to one routine – Cyclic recursion (A calls B calls C calls A) is dangerous because it’s hard to detect.
  • Keep an eye on the stack – With recursion, you have no guarantees about how much stack space your program uses. To prevent stack overflow, you can use safety counter and set the limit low enough or allocate objects on the heap using new.
  • Don’t use recursion for factorials or Fibonacci numbers – You should consider alternatives to recursion before using it. You can do anything with stacks and iteration that you can do with recursion. Sometimes one approach works better, sometimes the other does. Consider both before you choose either one.

goto

You might think the debate related to gotos is extinct, but a quick trip through modern source-code repositories like SourceForge.net shows that the goto is still alive and well and living deep in your company’s server.

The Argument Against gotos

The general argument against gotos is that code without them is higher-quality code
+ Dijkstra observed that the quality of the code was inversely proportional to the number of gotos the programmer used
+ Code containing gotos is hard to format
+ Use of gotos defeats compiler optimizations
+ The use of gotos leads to the violation of the principle that code should flow strictly from top to bottom

The Arguments for gotos

The argument for the goto is characterized by advocacy of its careful use in specific circumstances rather than its indiscriminate use.

A well-placed goto can eliminate the need for duplicate code. Duplicate code leads to problems if the two sets of code are modified differently. Duplicate code increases the size of the source and executable files. The bad effects of the goto are outweighed in such a case by the risks of duplicate code.

Good programming doesn’t mean eliminating gotos. Methodical decomposition, refinement, and selection of control structures automatically lead to goto-free programs in most cases. Achieving goto-less code is not the aim but the outcome, and putting the focus on avoiding gotos isn’t helpful.

Summary of Guidelines for Using gotos

Use of gotos is a matter of religion. My dogma is that in modern languages, you can easily replace nine out of ten gotos with equivalent sequential constructs.

  • Use gotos to emulate structured control constructs in languages that don’t support them directly. When you do, emulate them exactly. Don’t abuse the extra flexibility the goto gives you.
  • If goto improve efficiency, document the efficiency improvement so that goto-less evangelists won’t remove it.
  • Limit yourself to one goto label per routine
  • Limit yourself to gotos that go forward, not backward
  • Make sure all gotos labels are used.
  • Make sure a goto doesn’t create unreachable code.

https://t.co/AGH65l2L9F

— Nikola Brežnjak (@HitmanHR) March 12, 2018

Programming

Code Complete 2 – Steve McConnell – Controlling Loops

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types
  • Chapter 15: Using Conditionals

“Loop” is a structure that causes a program to repeatedly execute a block of code. Common loop types are for, while, and do-while.

When to use the while loop

If you don’t know ahead of time exactly how many times you’ll want the loop to iterate, use the while loop. Contrary to what some novices think, the test for the loop exit is performed only once each time through the loop, and the main issue concerning while loop is deciding whether to test at the beginning or the end of the loop.

  • while – loop tests condition at the beginning
  • do-while – tests condition at the end, which means that the body of the loop gets executed at least once.
  • loop-with-exit – structure more closely models human thinking. This is the loop in which the exit condition appears in the middle of the loop rather than at the beginning or the end.

When to use the for loop

A for loop is a good choice when you need a loop that executes a specified number of times. If you have a condition under which execution has to jump out of a loop, use a while loop instead.

When to use the foreach loop

It is useful for performing an operation on each member of an array or some other container. It has an advantage of eliminating loop-housekeeping arithmetic and therefore eliminating any chance of errors in the loop-housekeeping arithmetic.

Controlling the loop

You can use two practices. First, minimize the number of factors that affect the loop. Simplify! Simplify! Simplify! Second, treat the inside of the loop as if it were a routine-keep as much control as possible outside the loop.

Entering the loop

  • Enter the loop from one location only
  • Put initialization code directly before the loop – Principle of Proximity advocates putting related statements together.
  • Use while ( true ) for infinite loops – that’s considered a standard way of writing an infinite loop in C++, Java, Visual Basic, and other languages. for(;;) is an accepted alternative.

Processing the middle of the loop

  • Use { and } to enclose the statements in a loop – Use brackets every time. They don’t cost anything in speed or space at runtime, they help readability, and they help prevent errors as the code is modified.
  • Avoid empty loops – In C++ and Java, it’s possible to create an empty loop, one in which the work the loop is doing is coded on the same line as the test that checks whether the work is finished. Here’s an example:
    while( (inputChar = dataFile.GetChar() ) != CharType_Eof ) {
        ;
    }
    

    The loop would be much clearer if it were recoded so that the work it does is evident to the reader:

    do {
        inputChar = dataFile.GetChar();
    } while ( inputChar != CharType_Eof );
    

The new code takes up three full lines rather than that of one line, which is appropriate since it does the work of three lines rather than that of one line.
+ Keep loop-housekeeping chores at either the beginning or the end of the loop – As a general rule, the variables you initialize before the loop are the variables you’ll manipulate in the housekeeping part of the loop.

Exiting the loop

  • Assure that the loop ends
  • Don’t monkey with the loop index of a for loop to make the loop terminate
  • Avoid code that depends on the loop index’s final value

Exiting loops early

The break statement causes a loop to terminate through the normal exit channel; the program resumes execution at the first statement following the loop.

continue causes the program to skip the loop body and continue executing at the beginning of the next iteration of the loop.

Inefficient programmers tend to experiment randomly until they find a combination that seems to work. If a loop isn’t working the way it’s supposed to; the inefficient programmer changes the < sign to a <= sign. If that fails, the inefficient programmer changes the loop index by adding or subtracting 1. Eventually, the programmer using this approach might stumble onto the right combination or simply replace the original error with a more subtle one. Even if this random process results in a correct program, it doesn’t result in the programmer’s knowing why the program is correct.

How long should a loop be?

Make your loops short enough to view all at once. Experts have suggested a loop-length limit of one page (about 50 lines of code). When you begin to appreciate the principle of writing simple code, however, you’ll rarely write loops longer than 15 or 20 lines.

Creating loops easily – from the inside out

If you sometimes have trouble coding a complex loop, which most programmers do, you can use a simple technique to get it right the first time.

Here’s the general process:
+ Start with one case.
+ Code that case with literals.
+ Then indent it, put a loop around it, and replace the literals with loop indexes or computed expressions.
+ Put another loop around that, if necessary, and replace more literals.
+ Continue the process as long as you have to
+ When you finish, add all the necessary initializations.

Since you start at the simple case and work outward to generalize it, you might think of this as coding from the inside out.

Programming

Code Complete 2 – Steve McConnell – Using Conditionals

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types
  • Chapter 13: Unusual Data Types

A conditional is a statement that controls the execution of other statements; execution of the other statements is “conditioned” on statements such as if, else, case and switch.

Guidelines for if statements

  • Write the normal path through the code first; then write the unusual cases
  • Make sure that you branch correctly on equality – using > instead of >= or < instead of <= is analogous to making an off-by-one error.
  • Put the normal case after the if rather than after the else – put the case you normally expect to process first.
  • Check for reversal of the if and else clauses – a common mistake in programming if-else statements is to flip-flop the code that’s supposed to follow the if clause and the code that’s supposed to follow the else clause or to get the logic of if test backward.

Guidelines for if-else if statements

  • Simplify complicated tests with boolean function calls – To improve readability, you can replace them with calls to boolean functions, here’s example without boolean function calls.
    if ( 
        ('a' <= inputCharacter && inputCharacter <= 'z') || 
        ('A' <= inputCharacter && inputCharacter <= 'Z')    
        ) {
        // do something...
    }
    

    and here is the code simplified:

    if ( isLetter( inputCharacter) ) {
        // do something
    }
    
  • Put the most common cases first – That way you minimize the amount of exception-case handling code someone has to read to find the usual cases. You improve efficiency because you minimize the number of tests the code does to find most common cases.
  • Make sure that all cases are covered – Code the final _else clause with an error message or assertion to catch cases you didn’t plan for.

Case statements

Choosing the most effective ordering of cases

If you have a long _case` statement that handles dozens of events in an event-driven program, the order is significant. Following are some ordering possibilities:
+ Order cases alphabetically or numerically – If cases are equally important, putting them in A-B-C order improves readability.

  • Put the normal case first – If you have a normal case and several exceptions, put the normal case first.

  • Order cases by frequency – Put the most frequently executed cases first and the least frequently executed last.

Tips for using case statements

  • Keep the actions of each case simple – short code following each case helps make the structure of the case statement clear. If actions performed for a case are complicated, write a routine and call the routine from the case rather than putting the code into the case itself.

  • Use the default clause only to detect legitimate defaults – you might sometimes have only one case remaining and decide to code that case as the default clause. Though sometimes tempting, that’s dumb. You lose the automatic documentation provided by case-statement labels, and you lose the ability to detect errors with the default clause.

  • Use the default clause to detect errors – if the default clause is used for some purpose other than error detection, the implication is that every case selector is correct.

  • Avoid dropping through the end of a case statement – languages like C, C++, and Java don’t automatically break out of each case. If you don’t code the end of the case, the program drops through the end and executes the code for the next case.

  • Clearly and unmistakably identify flow-throughs at the end of a case – if you intentionally write code to drop through the end of a case, clearly comment the place at which it happens and explain why it needs to be coded that way. This technique should be avoided.

Programming

Code Complete 2 – Steve McConnell – Unusual Data Types

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables
  • Chapter 12: Fundemental Data Types

Structures

The term “structure” refers to data that’s build up from other types. You’ll generally want to create classes rather than structures so that you can take advantage of the privacy and functionality offered by classes in addition to the public data supported by structures. But sometimes structures can be useful, here are some reasons for using them:

  • Use structures to clarify data relationships – structures bundle group of related items together
  • Use structures to simplify operations on blocks of data – it’s easier to operate on the structure than to perform the same operation on each of the elements. It’s also more reliable, and it takes fewer lines of code.
  • Use structures to simplify parameter lists
    • Here is an example of a hard way to pass a group of related parameters:
      HardWayRoutine( name, address, phone, gender, salary )
      
    • And here is the easy way:
      EasyWayRoutine ( employee )
      
  • Use structures to reduce maintenance – Because you group related data when you use structures, changing a structure requires fewer changes throughout a program.

Pointers

Pointer usage is one of the most error-prone areas of modern programming, to such an extent that modern languages like Java, C#, and Visual Basic don’t provide a pointer data type.

Even if your language doesn’t require you to use pointers, a good understanding of pointers will help your understanding of how your programming language works. Conceptually, every pointer consists of two parts:

  • a location in memory and
  • a knowledge of how to interpret the contents of that location

General Tips on Pointers

  • Isolate pointer operations in routines or classes
  • Declare and define pointers at the same time
  • Delete pointers at the same scooping level as they were allocated
  • Check pointers before using them – make sure the memory location it points to is reasonable
  • Use extra pointer variables for clarity – the point is made elsewhere that a variable shouldn’t be used for more than one purpose. This is especially true for pointer variables.
  • Simplify complicated pointer expressions
  • Set pointers to null after deleting or freeing them – one reason pointer errors are hard to detect is that sometimes the error doesn’t produce any symptoms. By setting pointers to null after freeing them, you ensure that writing data to a dangling pointer produces an error.

Global Data

Global variables are accessible anywhere in a program. Even if global variables don’t always produce errors, however, they’re hardly ever the best way to program.

Common Problems with Global Data

  • Inadvertent changes to global data – You might change the value of a global variable in one place and mistakenly think that it has remained unchanged somewhere else
  • Bizarre and exciting aliasing problems with global data – “Aliasing” refers to calling the same variable by two or more different names. Here is the example in Visual Basic:
Sub WriteGlobal( ByRef inputVar as Integer )
    inputVar = 0
    globalVar = inputVar + 5
    MsgBox( "Input Variable: " & Str( inputVar ) )
    MsgBox( "Global Variable: " & Str( globalVar ) )
End Sub

Here’s the code that calls the routine with global variable as an argument: WriteGlobal( globalVar )

Here’s the surprising result:

Input Variable: 5
Global Variable: 5

The subtlety here is that globalVar and inputVar are actually the same variable! MsgBox() displays the same variable twice, even though they refer to two different names.
+ Code reuse hindered by global data – if the class you want to reuse reads or writes global data, you can’t just plug it into the new program.
+ Modularity and intellectual manageability damaged by global data – if you use global data, can you concentrate on one routine at a time? No. You have to concentrate on one routine and every other routine that uses the same global data.

Reasons to Use Global Data

  • Preservation of global values
  • Streamlining use of extremely common data
  • Eliminating tramp data – sometimes you pass data to a routine or class merely so that it can be passed to another routine or class.

Using Access Routines Instead of Global Data

Anything you can do with global data, you can do better with access routines. The use of access routines is a core technique for implementing abstract data types and achieving information hiding.

How to Use Access Routines

Hide data in a class. Declare that data by using the static keyword or its equivalent to ensure only a single instance of the data exists. Write routines that let you look at the data and routines that let you change data. Require code outside the class to use the access routines rather than working directly with data.

If you can’t avoid global variables, work with them through access routines. Access routines give you everything that global variables give you, and more.

Programming

Code Complete 2 – Steve McConnell – Fundemental Data Types

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables
  • Chapter 11: General Issues in Using Variables

The fundemental data types are the basic building blocks for all other data types.

Numbers in General

Avoid “magic numbers” – if you can program in a language that supports named constants, use them instead. A good rule of thumb is that the only literals that should occur in the body of a program are 0 and 1.

Integers

Bear these considerations in mind when using integers:
+ Check for integer division – when you’re using integers, 7/10 does not equal 0.7. It ussually equals 0
+ Check for integer overflow – you need to be aware of the largest possible integer. The larges possible unsigned integer is often 232.
+ Check for overflow in intermediate results
+ ( 1000000 * 1000000 ) / 1000000 = -727
– That’s because the intermediate result is too large for the integer data type

Floating-Point Numbers

Avoid additions and subtractions on numbers that have greatly different magnitudes, 1,000,000.00 + 0.1 probably produces an answer of 1,000,000.00 because 32 bits don’t give you enough significant digits to encompass the range between 1,000,000 and 0.1.

Change to binary coded decimal (BCD) variables. This is a roll-your-own approach to BCD variables. This is particlarly valuable if the variables you’re using represent dollars and cents or other quantities that must balance precisely.

Boolean Variables

Use boolean variables to document your program. Insted of merely testing a boolean expression, you can assign the expression to a variable that makes the implication of the test unmistakable.

Enumerated Types

An enumerated type is a type of data that allows each member of a class of objects to be described in English. You can use enumerated types for readability. Instead of writing statements like if chosenColor == 1 you can write more readable expressions like if chosenColor == Color_Red.

Anytime you see a numeric literal, ask whether it makes sense to replace it with an enumerated type

If language doesn’t have enumerated types, you can simulate them with global variables or classes.

Class Country {
    private Country {}
    public static final Country China = new Country();
    public static final Country France = new Country();
    public static final Country England = new Country(); 
}

Named Constants

A named constant is like a variable except that you can’t change the constant’s value once you’ve assigned it. Named constanst enable you to refer to fixed quantities, such as the maximum number of employees, by name rather than a number – MAXIMUM_EMPLOYEES rather than, 100, for instance.

Arrays

Arrays are the simplest and most common type of structured data. An array contains a group of items that are all of the same type and that are directly accessed through the use of an array index.

Make sure that array indexes are within the bounds of the array. The most common problem arises when a program tries to access an array element that’s out of bounds.

Creating Your Own Types (Type Aliasing)

Programmer-defined data types are one of the most powerful capabilities a language can give you to clarify your understanding of a program. Here’s how you’d set up the type definition in C++:

typedef float Coordinate;

This type definition declares a new type, Coordinate, that’s functionally the same as the type float. To use the new type, you declare variables with it just as you would with a predefined type such as float.

Coordinate latitude;
Coordinate longitude;
Coordinate elevation;

Here are several reasons to create your own types:
+ To make modifications easier
+ To avoid excessive information distribution
+ To make up for language weakness – C doesn’t have a boolean type, so you can compensate by creating the type yourself: typedef int Boolean

Programming

Code Complete 2 – Steve McConnell – The Power of Variable Names

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process
  • Chapter 10: General Issues in Using Variables

The Most Important Naming Consideration

The name must fully and accurately describe the entity that the variable represents. Names should be as specific as possible. Names like x, temp, and i that are general enough to be used for more than one purpose are not as informative as they could be and are usually bad names.

Variable names should be 10 to 16 characters long.

Computed-Value Qualifiers in Variable Names

Many programs have variables that contain computed values: totals, averages, maximums, and so on. If you modify a name with a qualifier, put the modifier at the end of the name. Try to avoid using num, instead use customerCount for total numbers of customers and customerIndex refers to a specific customer.

By establishing this convention, you avoid the confusion you might create if you were to use both totalRevenue and revenueTotal in the same program.

Naming Status Variables

Think of a better name than flag for status variables.

Here are some examples of flags with bad names:

if ( flag ) ...
if ( printFlag == 16) ...
if ( statusFlag & 0x0F) ...

Statements like statusFlag = 0x80 give you no clue about what the code does unless you wrote the code or have a documentation. Here are equivalent code examples that are clearer:

if ( dataReady ) ...
if ( reportType == ReportType_Annual ) ...
if ( characterType & PRINTABLE_CHAR ) ...

Clearly, characterType = CONTROL_CHARACTER is more meaningful than statusFlag = 0x80.

Naming Temporary Variables

They’re usually called temp, x, or some other vague and non-descriptive name. In general, temporary variables are a sign that the programmer does not yet fully understand the problem. Moreover, because the variables are officially given a “temporary” status, programmers tend to treat them more casually than other variables, increasing the chance of errors.

Naming Boolean Variables

  • Keep typical boolean names in mind:
    • done
    • error
    • found
    • success or ok – if you can, replace success with a more specific name that describes precisely what it means to be successful
  • Give boolean variables names that imply true or false
    • Names like status and sourceFile are poor boolean names because they’re not obviously true or false. What does it mean if status is true? For a better result, replace status with a name like statusOK, and _sourceFile_ with _sourceFileAvailable_ or _sourceFileFound_
  • Use positive boolean variable names – negative names like notFound or notDone are difficult to read when they are negated

Naming Constants

When naming constants, name the abstract entity the constant represents rather than the number the constant refers to. FIVE is a bad name for a constant (regardless of whether the value it represents is 5.0). CYCLES_NEEDED is a good name.

The key is that any convention at all is often better than no convention.

Guidelines for a Language-Independent Convention

  • variableName
  • RoutineName()
  • functionInsideClass()
  • ClassName
  • g_GlobalVariable
  • CONSTANT
  • i or j are integer indexes.

Sematic Prefixes

  • c – Count
  • first – The first element that needs to be dealt with in an array.
  • g – Global variable.
  • i – Index into an array.
  • last – The last element that needs to be dealt with in an array.
  • lim – The upper limit of elements that need to be dealt with in an array. Generally, lim equals last + 1.
  • m – Class-level variable
  • max – The absolute last element in an array or another kind of list. max refers to the array itself rather than to operations on the array
  • min – The absolute first element in an array or another kind of list.
  • p – Pointer.

Advantage of standardized prefixes – they give you all the general advantages of having a naming convention as well as several other advantages. Because so many names are standard, you have fewer names to remember in any single program or class.

Kinds of Names to Avoid

  • Avoid names with similar meanings. For example, input and inputValue
  • Avoid numerals in names. E.g. file1 and file2. You can almost always think of a better way to differentiate between two variables than by adding a 1 or 2 onto the end of the name.
  • Avoid words that are commonly misspelled in English: absense, acummulate, acsend, calender, concieve, defferred, definate, independance, occassionally, prefered, reciept and so on…
Programming

Code Complete 2 – Steve McConnell – General Issues in Using Variables

I just love Steve McConnell’s classic book Code Complete 2, and I recommend it to everyone in the Software ‘world’ who’s willing to progress and sharpen his skills.

Other blog posts in this series:

  • Part 1 (Chapters 1 – 4): Laying the Foundation
  • Chapter 5: Design in Construction
  • Chapter 6: Working Classes
  • Chapter 7: High-Quality Routines
  • Chapter 8: Defensive programming
  • Chapter 9: Pseudocode Programming Process

It’s easy to start using hazardous practices before you’re fully aware of your alternatives and then to continue to use them out of habit even after you’ve learned ways to avoid them.

Implicit Declarations

An implicit declaration is one of the most hazardous features available in any language. For example, if you use a variable in Microsoft Visual Basic without declaring it, the compiler declares it for you automatically (depending on your compiler settings).

What do you do if you program in a language with implicit declarations? Here are some suggestions:
+ Turn off implicit declaration
+ Declare all variables – as you type in a new variable, declare it, even though the compiler doesn’t require you to
+ Use naming conventions – establish a naming convention for common suffixes such as Num and No so that you don’t use two variables when you mean to use one
+ Check variable names – use cross-reference list generated by your compiler or another utility program

Guidelines for initializing variables

Improper data initialization is one of the most fertile sources of error in computer programming. Developing effective techniques for avoiding initialization problems can save a lot of debugging time.

The problem with improper initialization stem from a variable’s containing an initial value that you do not expect it to contain. This can happen for any of several reasons:

  • The variable has never been assigned a value. Its value is whatever bits happened to be in its area of memory when the program started
  • The value of the variable is outdated. The variable was assigned a value at some point, but the value is no longer valid
  • Part of the variable has been assigned a value and part has not. That can happen when you initialize some of the members of an object but not all of them

Guidelines for avoiding initialization problems:

  • Initialize each variable as it’s declared
  • Declare and initialize each variable close to where it’s first used
  • Use final or const when possible
  • Pay special attention to counters and accumulators. A common error is forgetting to reset a counter or an accumulator before the next time it’s used.

Scope

Scope, or visibility, refers to the extent to which your variables are known and can be referenced throughout a program.

One method of measuring how close together the references to a variable are is to compute “span” of a variable. Here’s an example:

a = 0;
b = 0;
c = 0;
a = b + c;

In this case, two lines come between the first reference to a and the second, so a has a span of two. The main advantage of keeping references to variables together is that it improves program readability.

Live time

A concept that’s related to variable span is variable “live time,” the total number of statements over which a variable is live. A variable’s life begins at the first statement in which it’s referenced; its life ends at the last statements in which it’s referenced.

Comments on scope

Many programmers approach to minimizing variables scope depends on their views of the issues of “convenience” and “intellectual manageability.” The difference boils down to a difference in emphasis between writing programs and reading them. Maximizing the scope might indeed make programs easy to write, but a program in which any routine can use any variable at any time is harder to understand.

Using each variable for exactly one purpose

It’s possible to use variables for more than one purpose in several subtle ways. You’re better off without this kind of subtlety.

  • Use each variable for one purpose only – it’s sometimes tempting to use one variable in two different places for two different activities. Usually, the variable is named inappropriately for one of its uses, or a “temporary” variable is used in both cases

  • Avoid variables with hidden meanings

    • The value in the variable pageCount might represent the number of pages printed unless it equals -1, in which case it indicates that an error has occurred
    • The variable bytesWritten might be the number of bytes written to an output file, unless its value is negative, in which case it indicates the number of the disk drive used for the output
  • Make sure all declared variables are used – the opposite of using a variable for more than one purpose is not using it at all

Page 1 of 3123»

Recent posts

  • Discipline is also a talent
  • Play for the fun of it
  • The importance of failing
  • A fresh start
  • Perseverance

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (35)
  • Daily Thoughts (77)
  • Go (3)
  • iOS (5)
  • JavaScript (127)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (2)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (77)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (40)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • Windows (8)
    • C# (2)
    • WPF (3)
  • Wordpress (2)

"There's no short-term solution for a long-term result." ~ Greg Plitt

"Everything around you that you call life was made up by people that were no smarter than you." ~ S. Jobs

"Hard work beats talent when talent doesn't work hard." ~ Tim Notke

© since 2016 - Nikola Brežnjak