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
Books

Doing Good Better: How Effective Altruism Can Help You Make a Difference

My favorite quotes from the book Doing Good Better by William MacAskill:

The money is less valuable to you, the more you have of it.

The challenge for us is this: How can we ensure that, when we try to help others, we do so as effectively as possible?

If you make more then 52k$/year you’re in the top 1% of the world’s population in terms of income. If you make more than 28k$/year you’re in the 5% richest people in the world. 11k$/year you’re richer than 85% of the people. Let that sink in.

When thinking about risk from transport, you can think directly in terms of minutes of life lost per hour of travel. Each time you travel, you face a slight risk of getting into a fatal accident, but the chance of getting into a fatal accident varies dramatically depending on the mode of transport. For example, the risk of a fatal car crash while driving for an hour is about one in ten million (so 0.1 micromorts). For a twenty-year-old, that’s a one-in-ten-million chance of losing sixty years. The expected life lost from driving for one hour is therefore three minutes. Looking at expected minutes lost shows just how great a discrepancy there is between risks from different sorts of transport. Whereas an hour on a train costs you only twenty expected seconds of life, an hour on a motorbike costs you an expected three hours and forty-five minutes. In addition to giving us a way to compare the risks of different activities, the concept of expected value helps us choose which risks are worth taking. Would you be willing to spend an hour on a motorbike if it was perfectly safe but caused you to be unconscious later for three hours and forty-five minutes? If your answer is no, but you’re otherwise happy to ride motorbikes in your day-to-day life, you’re probably not fully appreciating the risk of death. Boy, do I love that my parents didn’t give in to my ‘motorbike desire’ way back as a teenager ❤️

We’re about one hundred times richer than the poorest billion people in the world, and we can do several hundred times more to help them than we can to help others in the rich countries we live in.

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

Programming

Code Complete 2 – Steve McConnell – Pseudocode Programming Process

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

The benefits you can expect from using the pseudocode:

  • makes reviews easier – you can review detailed designs without examining the source code
  • supports the idea of iterative refinement
  • makes changes easier – a few lines of pseudocode are easier to change than a page of code
  • it’s easier to maintain than other forms of design documentation

Steps in building a routine

  1. Design the routine
  2. Code the routine
  3. Check the code
  4. Clean up loose ends
  5. Repeat as needed

1. Design the routine

  • Check the prerequisites to see that the job of the routine is well defined and fits cleanly into the overall design
  • Define the problem the routine will solve
  • Name the routine – good routine names are one sign of a superior program and they’re not easy to come up with
  • Decide how to test the routine
  • Research functionality available in the standard libraries – the single biggest way to improve both the quality of your code and your productivity is to reuse good code
  • Think about error handling – think about all the things that could possibly go wrong in the routine
  • Think about efficiency – in a vast majority of systems, efficiency isn’t critical. Design your routine so that it will meet its resource and speed goals
  • Research the algorithms and data types – if functionality isn’t available in the available libraries, it might still be described in an algorithms book
  • Write the pseudocode – you might not have much in writing after you finish the preceding steps. The main purpose of the steps is to establish a mental orientation that’s useful when you actually write the routine
  • Think about the data
  • Check the pseudocode – once you’ve written the pseudocode and designed the data, take a minute to review the pseudocode you’ve written. Back away from it, and think about how you would explain it to someone else
  • Try a few ideas in pseudocode, and keep the best (iterate)

2. Code the routine

  • Start with pseudocode
  • Write the routine declaration
    • Turn the original header comment into a programming-language code comment above declaration
  • Write the first and last statements, and turn the pseudocode into high-level comments
    /* Header comment about what routine does */
    Status ReportErrorMessage(
        ErrorCode errorToReport
    ) {
        //set the default status to "fail"

        //if the error code is valid, display the error message 
        //and declare success

        //if the error code isn't valid, notify the user that an internal 
        //error has been detected

        //return status information
    }
  • Fill in the code below each comment
/* Header comment about what routine does */
Status ReportErrorMessage(
    ErrorCode errorToReport
) {
    //set the default status to "fail"
    Status errorMessageStatus = Status_Failure;

    //if the error code is valid, display the error message 
    //and declare success
    if ( errorMessage.ValidCode() ) {
        DisplayMessage( errorMessage.Text() );
        errorMessageStatus = Status_Success;
    }

    //if the error code isn't valid, notify the user that an internal 
    //error has been detected
    else {
        DisplayMessage( "Internal Error: Invalid error code in ReportErrorMessage()" );
    }

    //return status information
    return errorMessageStatus;
}

Each comment should normally expand to about 2 to 10 lines of code.

3. Check the code

  • Mentally check the routine for errors

A working routine isn’t enough. If you don’t know why it works, study it, discuss it, and experiment with alternative designs until you do.

Compile the routine after reviewing it. It might seem inefficient to wait this long to compile. You’ll benefit in several ways, however, by not compiling until late in the process. After the first compile, you step up the pressure: “I’ll get it right with just one more compile.” The “Just One More Compile” syndrome leads to hasty, error-prone changes that take more time in the long run.

  • Step through the code in the debugger
  • Test the code

4. Clean up leftovers

  • Check the routine’s interface. Make sure that all input and output data is accounted for and that all parameters are used
  • Check for general design quality. Make sure the routine does one thing and does it well, that it’s loosely coupled to other routines, and that it’s designed defensively
  • Check the routine’s variables (inaccurate variable names, unused objects, undeclared variables, and so on)
  • Check routine’s statements and logic
  • Remove redundant comments

Alternatives to the PPP

  • Test-first development – popular development style in which test cases are written before writing any code
  • Refactoring – development approach in which you improve code through a series of semantic preserving transformation
  • Design by contract – development approach in which each routine is considered to have preconditions and postconditions
  • Hacking? – some programmers try to hack their way toward working code rather than using a systematic approach like the PPP. If you’ve ever found that you’ve coded yourself into a corner in a routine and have to start over, that’s an indication that the PPP might work better
Books

Resilience: Hard-Won Wisdom for Living a Better Life

My favorite quotes from the book Resilience: Hard-Won Wisdom for Living a Better Life by Eric Greitens which I rated 5/5 on my Goodreads account:

What you will become is a result of what you are willing to endure.

Use what hits you to change your trajectory in a positive direction.

The world breaks everyone and afterward many are strong at the broken places. But those that will not break it kills.

God, grant me the serenity to accept the things I cannot change, Courage to change the things I can, And wisdom to know the difference.

Great changes come when we make small adjustements with great conviction.

Action without direction rarely leads to progress.

Anyone who does anything meaningful will have critics.

A focus on excellence will, over time, lead to happiness.

Not what we have, but what we enjoy constitues our abundance.

Any fool can learn from his mistakes. Wise man learns from mistakes of others.

If you want to feel differently – act differently! At first it will feel like a lie, but ‘be’ what you would like to be and you’ll become it.

People who think you’re weak will offer you an excuse. People who respect you will offer you a challenge.

If you want to live a purposeful life, you have to create your purpose.

Working hard yourself makes you more appreciative and respectful of the hard work of others.

He who fears he shall suffer, already suffers what he fears.

  1. Why am I here?
  2. What’s going around me?
  3. What am I going to do about it?
  4. How will my actions affect others?

When the child is skillful he boasts. When the warrior has a skill, he teaches. When the child is strong, he attacks the weak. When the warrior is strong, he protects the weak. The child criticises others to make himself feel better. The warrior is his own most demanding critic.

Warriors are expected to combine courage and ferocity in battle with decency and humanity in victory.

My #notes from a great #book Resilience Hard-Won Wisdom for Living a Better Life by Eric Greitens https://t.co/HSJDYOniIj

— Nikola Brežnjak (@HitmanHR) September 4, 2017

Programming

Code Complete 2 – Steve McConnell – Defensive programming ?️

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

Defensive-programming techniques make errors easier to find, easier to fix, and less damaging to production code.

Assertions

An assertion is a code that’s used during development-usually a routine or macro- that allows a program to check itself as it runs. When an assertion is true, that means everything is operating as expected.

Use error handling code for conditions you expect to occur and assertions for conditions that should never occur.

Design by contract

Preconditions and post conditions are part of an approach to program design and development known as “design by contract”.

  • Preconditions are properties that the client code of a routine or class promises will be true before it calls the routine or instantiates the object.
  • Postconditions are the properties that the routine or class promises will be true when it concludes executing.

For highly robust code, assert and then handle the error anyway.

Some experts argue that only one kind is needed. But real-world programs and projects tend to be too messy to rely solely on assertions.

Error-Handling Techniques

Depending on the specific circumstances, you might want to:

  • Return a neutral value
  • Substitute the next piece of valid data
  • Return the same answer as the previous time
  • Substitute the closest legal value
  • Log a warning message to a file
  • Return an error code
  • Call an error-processing routine/object
  • Shut down

Correctness means never returning an inaccurate result; returning no result is better than returning an inaccurate result.

Robustness means always trying to do something that will allow the software to keep operating, even if that leads to results that are inaccurate sometimes.

Safety-critical applications tend to favor correctness to robustness.

Consumer applications tend to favor robustness to correctness. Any result whatsoever is usually better than the software shutting down.

Exceptions

Exceptions have an attribute in common with inheritance: used judiciously, they can reduce complexity. Used imprudently, they can make code almost impossible to follow.

What you should know about using exceptions:

  • Use exceptions to notify other parts of the program about errors that should not be ignored
  • Throw an exception only for conditions that are truly exceptional
  • Don’t use an exception to pass the buck – handle error locally
  • Avoid throwing exceptions in constructors and destructors unless you catch them in the same place
  • Throw exceptions at the right level of abstraction

Use barricades

Defining some parts of the software that works with dirty data and some that work with clean data can be an effective way to relieve the majority of the code of the responsibility for checking for bad data.

Debugging Aids

Another key aspect of defensive programming is the use of debugging aids, which can be a powerful ally in quickly detecting errors.

Be willing to trade speed and resource usage during development in exchange for built-in tools that can make development go more smoothly.

Determining how much defensive programming to leave in production code

One of the paradoxes of defensive programming is that during development, you’d like an error to be noticeable-you’d rather have it be obnoxious than risk overlooking it. But during production, you’d rather have the error be as unobtrusive as possible, to have the program recover or fail gracefully.

Here are some guidelines for deciding which defensive programming tools to leave in your production code and which to leave out:

  • Leave the code that checks for important errors
  • Remove code that checks for trivial errors
  • Remove code that results in hard crashes
  • Leave the code that helps the program crash gracefully

Being defensive about defensive programming

Too much defensive programming creates a problem of its own. Code installed for defensive programming is not immune to defects, and you’re just as likely to find a defect in defensive-programming code as in any other code-more likely if you write the code casually.

My #notes from a great #book CC 2 by Steve McConnell chapter on Defensive programming ?️ https://t.co/KnBqvEySJd

— Nikola Brežnjak (@HitmanHR) September 4, 2017

Programming

Code Complete 2 – Steve McConnell – High-Quality Routines

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

Routines are used to:

  • reduce complexity
  • introduce an intermediate, understandable abstraction
  • avoid duplicate code
  • hide sequences
  • hide pointer operations
  • improve portability
  • simplify complicated boolean tests and
  • improve performance

Functional cohesion

Functional cohesion is when a function performs one and only one operation.

Cohesions that are considered to be less than ideal:

  • Sequential cohesion
    • exist when a routine contains operations that must be performed in a specific order, that share data from step to step.
  • Communicational cohesion
    • occurs when operations in a routine make use of the same data and aren’t related in any other way.
  • Temporal cohesion
    • occurs when operations are combined into a routine because they are all done at the same time. Think of temporal routines as organizers of other events.

Unacceptable kinds of cohesion:

  • Procedural cohesion
  • Logical cohesion
  • Coincidental cohesion

Good routine names and length

Research shows that the optimum average length for a variable name is 9-15 characters and 15-20 for a routine name.

To name the function use the description of the return value. In object-oriented languages, you don’t need to include the name of the object in the procedure name because the object itself is included in the call.

Avoid names like: document.PrintDocument().

A large percentage of routines in object-oriented programs will be accessor routines, which will be very short. From time to time, a complex algorithm will lead to a longer routine, and in those circumstances, the routine should be allowed to grow organically up to 100 – 200 lines.

Don’t write routines longer than about 200 lines.

How to use routine parameters

Interfaces between routines are some of the most error-prone areas of the program. Here are a few guidelines for minimizing interface problems:

  • Put parameters in input-modify-output order
  • If several routines use similar parameters, put the similar parameters in a consistent order
  • Use all the parameters
  • Put status or error variables last
  • Limit the number of a routine’s parameters to about seven

Psychological research has found that people generally cannot keep track of more than about seven chunks of information at once. (Miller 1956.)

The difference between function and procedure is that procedure doesn’t return a value.

You should use macro routines with care and only as a last resort.

Page 4 of 12« First...«3456»10...Last »

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