Rob Kraft's Software Development Blog

Software Development Insights

Archive for the ‘CodeProject’ Category

Malware for Neural Networks: Let’s Get Hacking!

Posted by robkraft on March 24, 2017

I don’t intend to infect any artificial intelligence systems with malware. But I do intend to provide an overview of the techniques that can be used to damage the most popular AI in use today, neural networks.

With traditional hacking attempts, bad actors attempt to plant their own instructions, their own computer code, into an existing software environment to cause existing software to behave badly. But these techniques will not work on neural networks. Neural networks are nothing more than a big collection of numbers and mathematical algorithms that no human can understand well enough to alter in order to obtain a malicious desired outcome. Neural networks are trained, not programmed.

But I am not implying that damage cannot be done to neural networks, or that they can’t be corrupted for evil purposes. I am implying that the techniques for malware must be different.

I have identified five types of malware, or perhaps I should say five techniques, for damaging a neural network.

1. Transplant

The simplest technique for changing the behavior of an existing neural network is probably to transplant the existing neural network with a new one. The new, malicious, neural network presumably would be one that you have trained using the same inputs the old one expected, but the new one would produce different outcomes based on the same inputs. To successfully implement this malware, the hacker would first need to train the replacement neural network, and to do so the hacker needs to know the number of input nodes and the number of output nodes, and also the range of values for each input and the range of results of each output node. The replacement neural net would need to be trained to take the inputs and produce the outputs the hacker desires. The second major task would be to substitute the original neural network with the new neural network. Neural networks accessible to the Internet could be replaced once the hacker had infiltrated the servers and software of the existing neural network. It could be as simple as replacing a file, or it could require hacking a database and replacing values in different tables. This all depends on how the data for the neural network is stored, and that would be a fact the hacker would want to learn prior to even attempting to train a replacement neural network. Some neural networks are embedded in electronic components. A subset of these could be updated in a manner similar to updating firmware on a device, but other embedded neural networks may have no option for upgrades or alterations and the only recourse for the hacker may be to replace the hardware component with a similar hardware compare that has the malicious neural network embedded in it. Obviously there are cases where physical access to the device may be required in order to transplant a neural network.

2. Lobotomy

If a hacker desires to damage a neural network, but is unable or unwilling to train a replacement neural network, the hacker could choose the brute force technique called the lobotomy. As you might guess, when the hacker performs a lobotomy the hacker is randomly altering the weights and algorithms or the network in order to get it to misbehave. The hacker is unlikely to be able to choose a desired outcome or make the neural network respond to specific inputs with specific outputs, but the random alterations introduced by the hacker may lead the neural network to malfunction and produce undesirable outputs. If a hackers goal is to sow distrust in the user community of a specific neural network or of neural networks in general, this may be the best technique for doing so. If one lobotomy can lead a machine to choose a course of action that takes a human life, public sentiment against neural networks will grow. As with a transplant, the hacker also needs to gain access to the data of the existing neural network in order to alter that data.

3. Paraphasia

Of the five hacking techniques presented here I think that paraphasia is the most interesting because I believe it is the one a hacker is most likely to have success with. The term is borrowed from psychology to describe a human disorder that causes a person to say one word when they mean another. In an artificial neural network, paraphasia results when a saboteur maps the response from the neural network to incorrect meanings. Imagine that Tony Stark, aka Iron Man, creates a neural network that uses face recognition to identify each of the Avengers. When the neural network inputs send an image of Captain America through the neural network layers, the neural network recognizes him, and then assigns the label “Captain America” to the image. But a neural network with paraphasia, or I should say a neural network that has been infected with paraphasia, would see that image and assign the label of “Loki” to it. Technically speaking, paraphasia is probably not accomplished by manipulating the algorithms and weights of the neural networks. Rather, it is achieved by manipulating the labels assigned to the outputs. This makes it the most likely candidate for a successful neural network hacking attempt. If I can alter the software consuming the output of a neural network so that when it sees my face it doesn’t assign my name to it, but instead assigns “President of the United States” to it, I may be able to get into secret facilities that I would otherwise be restricted from.

Open and Closed Networks

The first three hacking techniques could be applied to neural networks that are open, or that are closed. A closed neural network is a network that no longer adjusts its weights and algorithms based on new inputs. Neural networks embedded in hardware will often be closed, but the designers of any neural network may choose to close the neural network if they feel it has been trained to an optimal state. An open neural network is a network that continues to adjust its weights and algorithms based on new inputs. This implies that the neural network is open to two additional forms of attack.

4. Brainwashing

Many neural networks we use today continue to evolve their learning algorithms in order to improve their responses. Many voice recognition systems attempt to understand the vocalizations of their primary users and adapt their responses to produce the desired outcomes. Some neural networks that buy and sell stocks alter their algorithms and weights with feedback from the results of those purchases and sales. Neural network designers often strive to create networks that can learn and improve without human intervention. Others attempt to crowdsource the training of their neural networks, and one example of this you may be familiar with is captcha responses that ask you to identify items in pictures. The captcha producer is probably not only using your response to confirm that you are a human, but also to train their neural network on image recognition. Now, imagine that you had a way to consistently lie to the captcha collection neural network. For dramatic effect, let’s pretend that the captcha engine showed you nine images of people and asked you to click on the image of the President of the United States. Then imagine that, as a hacker, you are able to pick the image of your own face millions of times instead of the face of the President. Eventually you may be able to deceive the neural network into believing that you are the President of the United States. Once you had completed this brainwashing of the neural network, you could go to the top secret area and the facial recognition software would let you in because it believed you to be the President. I am not saying that brainwashing would be easy. I think it would be really difficult. And I think it would only work in the case where you could programmatically feed a lot of inputs to the neural network and have some control over the identification of the correct response. For best results, a hacker might attempt to use this technique on a neural network that was not receiving updates through a network like the Internet, but was only receiving updates from a local source. A neural network running inside an automated car or manufacturing facility may operate with this design. Brainwashing is similar to paraphasia. The difference is that in brainwashing, you train the neural network to misidentify the output, but in paraphasia you take a trained neural network and map its output to an incorrect value.

5. OverStimulation

Like a lobotomy, the overstimulation technique only allows the hacker to cause mischief and cause the neural network to make incorrect choices. The hacker is very unlikely to achieve a specific desired outcome from the neural network. Overstimulation can only occur on poorly designed neural networks and essentially these are neural networks that are subject to the overfitting flaw of neural network design. A neural network that is not closed and designed with an inappropriate number of nodes or layers could be damaged by high volumes of inputs that were not examples from the original training set.

Layers of difficulty

To all you aspiring hackers, I also warn you that our neural networks are getting more complex and sophisticated every day and I think this makes it even more difficult to hack them describing the techniques mentioned here. The deep learning revolution has been successful in many cases because multiple neural networks work in sequence to produce a response. The first neural network in the sequence may just try to extract features from the incoming sources. The identified features are the output of the first network and these are passed into a second neural network for more grouping, classification, or identification. After that these results could be passed on to another neural network that makes responses based upon the outputs of the previous neural network. Therefore, any attempted hack upon the process needs to decide which of the neural networks within the sequence to damage.

I am not encouraging you to try to introduce malware into neural networks. I am strongly opposed to anyone attempting to do such things. But I believe it is important for system engineers to be aware of potential ways in which a neural network may be compromised, and raising that awareness is the only purpose of this article.

Posted in CodeProject, Security | Tagged: , , , | Leave a Comment »

Robert’s Rules of Coders: #11 Separate User Interface Logic From Business Logic

Posted by robkraft on July 10, 2016

One goal to keep in mind as you write software is to write software that is easy to maintain and enhance in the future. We can do this by organizing code so that things that might change will be easier to change. Consider this example:



In the code above, User Interface (UI) code is mixed together with the business object code. We should try not to pass details about how the UI implements a feature unless the business object really needs to know. In this example, the Products business object really only needs to know three pieces of information from the UI:

  • The Price
  • Should a discount be calculated because this is for a nonprofit agency? (yes or no)
  • Should a discount be calculated because this is a bulk purchase? (yes or no)

If we change the code to pass boolean values to the Products business object instead of the checkboxes, we gain the following benefits:

  • The UI can easily be changed in the future to use something other than checkboxes, and this change will not require also changing code in the Products business object.
  • We increase our potential to use the Products business object with different types of user interfaces. This business object may currently expect a C# WPF checkbox control, which means the business object would not work if someone had a C# Windows checkbox control, or perhaps a C# Silverlight checkbox control. But if the Products business object accepted a boolean, which is a datatype common to more platforms, the business object will more likely work with different user interfaces.
  • Unit tests that we write won’t need to reference the specific UI components needed for building the user interface.

A more common way that developers often entwine UI code with business object code is shown below. This example is the opposite of the case above. Here logic that could, and should, reside in the business object is performed in the UI.



The reason we don’t like this code is that logic to calculate the discounted price should be moved from the UI to the Product business object. In doing so we would gain the following benefits:

  • We could reuse the Product business object in another program without needing to also add logic to the UI of the other program to calculate the discounted price.
  • If we need to change the calculation for the discounted price, we need to make the change in only one place and every program using that business object automatically is affected.
  • We can easily write a unit test on the Product business object to make sure that the code calculating our discounted price works correctly.

A better way to write the code from both examples above so that the UI and business logic is not entwined is shown below. I will admit that this is not the best example, because it does not use TryParse, nor does it have input checking and error handling, and it could use an interface, but those topics are not the point of this article, which is to encourage you to separate the UI logic from the business logic in your applications.



It is not bad sometimes to write code that entangles UI code and business logic, knowing that you will refactor the code to move the logic to the correct place before you consider the feature complete. It is often helpful to have all of the code in one big method until you have it correct, then you can improve the code by refactoring it.

As with any of Robert’s Rules of Coding, you don’t need to adhere to them all of the time and there are cases where it is better not to. But most programmers should follow the rules most of the time. I hope you agree.

Go to Robert’s Rules of Coders for more.



Posted in Code Design, CodeProject, Coding, Uncategorized | Leave a Comment »

Agile Baby Steps: A Parable To Help You Get Started

Posted by robkraft on March 20, 2016

We often hesitate to take the action that shows we are committed to doing something new. We read about it, analyze it, and try to understand it; but real learning requires that we go beyond reading. We must DO. The goal of this article is to get you to take action toward becoming Agile, without understanding or adopting all of the habits of an Agile development team. I am asking you to try out some new processes in your software development life cycle, without considering whether or not you are doing Agile development.

Side bar: Your ability to implement an Agile technique depends upon the process by which your software is implemented. An Agile development technique that works for one process may not work for another, so be cautious of Agile recommendations that state you must do something specific or you will fail at being Agile. Your goal is not to be “Agile” by anyone’s definition. Your goal is to write better software. 

  • Some software developers write code then send it to a quality assurance environment who then push it into production;
  • Some software developers write code for embedded systems where all the software must be completed before it is written to a chip;
  • Some software developers check in code that that runs through automated tests and gets published to a public web site without further human action;
  • And some software developers follow other models for implementation.

The process by which you take code from development into its final environment greatly affects which agile techniques will work for you.

The Parable Begins

Let me share with you a parable of two teams, each tasked with developing the same software, but each using a different methodology.

Team Agile used an agile methodology, and team waterfall used a waterfall method. Both teams were asked to build a web application to allow users to manage data in an existing client-server application.

Team Agile met with the end users, usually known as the product owners in agile, and learned the high level requirements and features desired for the entire application. Because they did not gather detailed requirements, they spent only eight hours on this task.

Side bar: Delaying the gathering of detailed requirements often adds value in several ways:

  1. You don’t spend time gathering and documenting detail requirements for features that later get cancelled or excluded from the project.  If the team spends ten hours detailing the requirements of a feature that management decides not to implement a month later, then the team wasted ten hours. Eliminating waste is the major focus of Lean and Kanban styles of Agile development.

  2. Another reason to delay gathering detailed requirements is that every team member will be smarter in the future than they are today.  Each will know more about the application and may learn that ideas considered early in development are not as effective as new ideas learned since. Perhaps a developer read about a new programming technique or tool; or perhaps the product owner learned about a better way to design a user interface. You can implement these new ideas and techniques even if you documented detail requirements for the old techniques, but that means the time spent gathering and documenting requirements for doing it the old way was wasted time.


Team Agile also asked the product owners which features were most important. The product owners initially said all of the features were necessary and important, but after more discussion the product owners provided this prioritized list of features:

  1. Users need to be able to log in
  2. To view data
  3. To edit data
  4. To add data
  5. To delete data

Prioritizing features is an important, and necessary feature of agile development, as we shall see later. If you do not prioritize the features you are going to work on, you will probably not receive the benefits that agile development can provide.

Meanwhile, in a parallel universe, the Team Waterfall also met with the end users to gather requirements. They spent much more than eight hours on this task because they needed detailed requirements for all the features. They planned for little interaction with the product owner after this meeting until the product was finished. Team Waterfall spent sixty-four hours on requirements.

The Login Feature – Deploy Early

Team Agile next then did some design for the project. They thought about all of the requirements they had learned about, but they only did a detailed design for the first feature they worked on; and that feature was the ability to log in. They spent four hours on the design of this feature.

Then Team Agile coded the login feature. The coding took eight hours. Next, Team Agile turned the application over to the Quality Assurance (QA) team. Even though the entire application was not completed the QA team found a few problems with the login feature. Team Agile fixed those problems, and the QA team could find no more defects.

Side bar: Agile development does not magically prevent programmers from creating bugs, but it does make developers aware of the bugs sooner, so they can fix them while the code is still fresh in their minds and before some errors might get propagated into more of the code.

Team Agile implemented the application in production. Now, this seemed a little silly to some people, because the application did not do anything other than let a user login; but it turned out to be very valuable. They discovered that the software did not work in production. The production environment had an older version of the web server that lacked some features the application depended on. Team Agile met with IT to discuss the problem and decide if the web app should be re-written, or if the production web server could be upgraded to a newer version. They decided the web server could be upgraded, but it did require two weeks for this to be completed.

Agile Manifesto Principle #1: -“Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.”

Side bar: Not all software can be deployed in small pieces, such as software embedded on chips or shrink-wrapped software. But some software, like the software in this parable, can be deployed in pieces. By taking the software as far as possible along the path of implementation you may discover problems. It is always best to know about problems sooner so they can be accounted for in the project schedule and possibly used to correct the product requirements, design, and code. A product developed using a waterfall method has a higher risk of failing to discover some problems until all the code is completed and thus incurs significantly higher costs to correct the problem.

Side bar: Agile methodologies reduce the risk of unknown and unexpected problems by revealing them sooner.

The View Feature

While Team Agile waited for the new web server to be implemented in production, they proceeded to work on the second feature, “Allow users to view data”.   They met with the users to get more detailed requirements about how they would like to view the data. They spent eight hours on this task. Team Agile then created a design, including some mockups and reviewed the mockups with the product owners. After this sixteen hours of work the developers were ready to begin coding.

I have not forgotten about Team Waterfall. During all this time that Team Agile did the activities above, Team Waterfall has been gathering requirements. Team Waterfall is now ready to design the application, and they will spend about forty four hours in design, which is a little less than the total amount of time Team Agile will spend on design. In this parable, Team Waterfall benefitted by designing the entire application all at once because it was all fresh in their minds as they did it. Team Agile, on the other hand, did parts of the design spread out of several months, and had to spend part of that time recalling why some decisions were made. However, the advantage still goes to Team Agile, as we shall see, because Team Waterfall will discover that much of their time spent in design was wasted.

Team Waterfall completed their design then started coding. They chose to code the view and edit features first, and at the same time because they believed them to be the most interesting and fun part of the code to write. For both Team Agile and Team Waterfall, the coding phase(s) of the application take the longest; around three hundred hours. At the same time that Team Waterfall is working on the total application design, Team Agile begins coding their second feature, “Viewing Data”.

Communication With Product Owner

For both teams, the time spent coding is the same for all features except for “Viewing Data”. Team Agile spent one hundred and twenty hours coding this feature, but Team Waterfall is going to spend one hundred and sixty hours coding this same feature for the following reasons.

  • In the first week, a developer attempted to implement a list box on a form as had been requested in the requirements. But the developer found that this data would be difficult to display given the list box features. He realized he could easily do this with a grid though.  So the developer brought this up with the product owner during the daily status meeting, and the product owner said he didn’t care if it was a list box or grid, he barely understands the difference between the two, and he would just prefer to defer that decision to the developer. So the developer used a grid instead of a list box and saved an estimated forty hours of work that would have been needed if he had tried to make the feature work using a list box.

Agile Manifesto Principle #4 – “Business people and developers must work together daily throughout the project.”

  • In the second week, another developer was working on a feature to let users pick their own colors for the forms. The requirement called for a text box in which the user could type a hexadecimal value representing the color, but the developer had recently learned about a component that could just as easily provide a color picker to make it much easier for the end user. Instead of adhering to the requirements the developer showed the product owner liaison an example of the color picker and asked if this change would be acceptable and the product owner liaison loved the idea, so it was implemented.

Agile Manifesto Principle #6 – “The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.”

Side bar: Once again, the ability for frequent interaction between the developers and the end users throughout development facilitates many improvements. Also, developers are often more aware of the capabilities of technology than the end users and can make suggestions for improving the application based on that knowledge. When the discussion for detailed requirements can be delayed and the developer writing the code can be involved, there is a greater chance for a better solution.

Side bar: A good technique for software development, and for many decisions in life, is that it is best to commit to a decision as late as possible because your knowledge later in the life cycle is greater than it will be earlier in the cycle.

Reports Feature – New Requirements

During Team Agile’s development of the “View Data” feature, the product owner realized they had omitted the reports feature from the project. The reports are used by every user and are much more important than the ability to delete, add, or even edit data. The product owner and the developers had a meeting about the omission and decided that the developers would add the report feature next, after they finished View feature.

Agile Manifesto Principle #2 – “Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.” The ability to accept new requirements and to change the priorities of features developed is one of the most noticeable and valuable aspects of agile development.

The development team finished the view feature and easily deployed it into production. The product owners started using the application, even though all of the features were not available.

Agile Manifesto Principle #3 – “Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale. “

Deploying the view feature provided several benefits:

  • The company could begin deriving value from the application. In financial terms, the Return On Investment (ROI) starts occurring sooner in Agile projects than in Waterfall projects.
  • The users became more productive because the web application was easier and faster to use than the client server application. It was also easier for the IT staff to make it available to more users.
  • The users found bugs in the application. Finding some of these bugs may prevent similar bugs from being developed in the remainder of the application. For example:
    • The users found that there were no accessibility keys. So the development team planned to add these to the view screens, and were proactive about adding this feature in future development.
    • The users became more productive because the web application was easier and faster to use than the client server application. It was also easier for the IT staff to make it available to more users.
    • Twenty percent of the users found that some features did not work on the particular browser they used, which was different than the browser used by the developers and most of QA.
    • A few bugs were found causing incorrect data to be displayed.
  • Side bar: Teams often desire to fix bugs right away, but in an Agile environment, especially one with short one-week or two-week iterations, this can be counterproductive. It is generally best to let the team complete what they started in an iteration, then make the fixes to the bugs a top priority for the next iteration.

Waterfall Team Progress

Let’s check in on Team Waterfall. At the same time Team Agile is coding and deploying the “View Data” feature, Team Waterfall chose to code the “View Data” and “Edit Data” features, and they are still in the process of doing this. They have nothing yet to show to the product owners, so let’s turn back to Team Agile, because they have some visible progress that we can check on.

Agile Manifesto Principle #7 – “Working software is the primary measure of progress.”

Team Agile finished the “View Data” feature, and started to develop the “Reports” feature next. The requirements and design only took sixteen hours, and by this time the reports of bugs in the “View Data” feature were coming in. However, the team felt they could and should complete the “Reports” feature before working on the bugs so that they did not incur the cost of switching back and forth between tasks. The product owners accepted this decision because the development iterations were short, and the development team said they could start fixing the bugs next week.

After finishing the “Reports” feature and deploying it to production, the team spent a week fixing the bugs in the “View Data” feature. Some of the bugs had made some views unusable, and other bugs, such as accessibility and support for other browsers, would affect how they developed all subsequent features.

Side bar: Agile development does not magically eliminate bugs, nor does it prevent errors in requirements, design, and communication. But Agile development does reveal most bugs sooner so they can be fixed more quickly and cost less to correct than they would in waterfall development.

Team Waterfall is still coding the “Edit Data” feature at this point in time. It took them longer to code the “View Data” feature than it took Team Agile because Team Waterfall made the list box work as documented in the requirements rather than go back and talk to the product owners about using a grid instead. Team Waterfall also spent time explaining to the product owner that they could not add the “Reports” feature to the product because they had already gathered all of the requirements and done the design and they would need to redo some of that for a new feature. Ultimately, the product owner agreed to increase the product budget and provide proper paperwork for a “Change Request” to the requirements of the system. Team Waterfall then spent eighteen hours gathering the requirements and changing their design, which included changing the design of some database tables they had not started coding against yet. Since Team Waterfall still has nothing to show, we will go back and see what is happening with Team Agile.

More New Feature Requests

Team Agile has started the requirements and design of the “Edit” feature. During development of the edit feature, the product owner realized they had omitted filtering and sorting abilities in the view feature and that filtering and sorting was really necessary to make the views more valuable. Team Agile decided they would add sorting and filtering to views right after they completed the editing feature.

The Cancellation of the Project

But in the next week a new project came in and the developers were asked to suspend this project and work on the new project. The new project was very important, of course, and would probably take the team a year to complete. Team Agile was given one week to wrap up this project and begin work on the new project. For Team Agile, the editing feature was almost done, but the date and time pickers only worked on one browser and the developers estimated it would take them three to five days to get new date and time pickers working on all browsers. Team Agile had to choose between these options:

  1. Add filtering and sorting to views and not release the edit feature
  2. Finish the edit feature so the date picker worked on all browsers and users would not have to type in dates, but not add filtering and sorting to views
  3. Add filtering and sorting to views and release the edit feature without a date picker, requiring users to type in the date.

Team Agile desired to complete the edit feature by making the date picker work because they did not want to provide the end users with a subpar, low quality product; and they thought it would make the developers look bad if the app did not have the simple date pickers. But the product owner said that the filtering and sorting of views was most valuable, and that they would take the editing feature even without the date pickers because the ability to edit data from the web application would provide some value to users even if the feature was not finished perfectly.

Side bar: Agile development often gives the product owner insight into the product development processes and decisions. This is almost always a benefit to the business because the product owner can help guide the product outcome to a solution that provides the best ROI for the business. However it can, occasionally, upset some developers when they feel they are asked to cut quality to get the job done. The developers may feel it will reflect poorly on them. It is up to the management teams to convey to the end user the decisions made in this situation were those of management, and not the developers.       Waterfall teams rarely have this dilemma because the product owner is unaware of all the decisions made.

Speaking of waterfall teams, as in the side note, what is going on with Team Waterfall now that this new project has arrived and they must work on the new project instead. Well, one benefit for Team Waterfall is that they can start on the new project right away instead of spending a week trying to wrap up the old project because there is no way Team Waterfall can deliver anything within one week on the old project; they never even started the Login feature of the application. The obvious enormous downside for Team Waterfall is that they will deliver nothing to the end users, and all the time spent on the application can now be considered waste. That is not the case for Team Agile. Even though the project was terminated early, the agile team delivered something of value that could be further enhanced in the future.

Agile Manifesto Principle #10 – “Simplicity–the art of maximizing the amount of work not done–is essential.”

I provide two summaries to this parable. The first, is a summary specific to the tale, and the second is a summary of general conclusions to be made about agile development.

Specific Summary

  • Team Agile delivered some business value, but all the time spent by Team Waterfall was a waste.
  • Team Agile reduced the development time of some features by frequent interaction with end users and by being open to changing the requirements.
  • Team Agile provided a better way for end users to choose their colors than team waterfall because the UI decision was not made until the feature was developed and in that time the developer had learned of a new component.
  • Team Agile accommodated the “Report” feature because they had a prioritized backlog and could easily queue it up to work on next. Team Waterfall did not prioritize their work, so any new development would probably just be added at the end. Team Waterfall would need to alter their existing requirements and design.
  • Team Waterfall never learned that their app would not work in production due to the older web server. It is probable that the team would be rushing to deliver this product by a deadline, only to discover right at the end that additional time would be required. It could have been even worse if IT was unable to upgrade the web server and the development team had to go back and change code to make the application work on an older web server.

General Summary

  • Agile teams often waste less time than waterfall teams.
  • Frequent interaction with end users can produce a better product with less waste. This is not exclusive to agile development, but it is more common to agile development than to waterfall.
  • The willingness to accept flexible requirements can produce a better product with less waste. This is more difficult to do when all requirements have been gathered up front and have been included in a design.
  • Delaying requirement and design details can lead to better decisions at the time the decision needs to be made.
  • Agile teams accept new requests easily by adding them in the backlog. They do not have a lot of time invested in any features in the backlog because they wait and do the detailed requirements and design for them when they are about to code them.

If you want to become more Agile today:

  • Create a prioritized backlog
  • Select features from the backlog that you will complete during your next iteration. A good iteration length is two weeks.
  • Make sure that you don’t just code the features, but that you include testing and deployment, if possible, to be done within your iteration.
  • Do not work on several things at the same time. Complete each feature as much as possible.
  • Finish what you start each iteration. Do not add interrupt what you started in an iteration by working on something new that came in to the backlog. Wait until the next iteration to start it.
    • Sometimes, something very high priority will come in that must be completed right away. Agile developers understand and accept this.

Posted in CodeProject, Process, Project Management, Uncategorized | Leave a Comment »

Robert’s Rules of Coders #9: Eliminate Deep Nesting by Using Switch Statements and Functions

Posted by robkraft on February 14, 2016

The ‘If’ statement is one of the fundamental coding constructs of almost every programming language. Along with the ‘If’ statement, most languages also support ‘else’ conditions and the ability to nest ‘If’ statements. But this simple construct can also become one of the biggest contributors to code that is difficult to understand and modify. This often happens when ‘If’ statements get nested within ‘If’ statements; but there are two simple techniques you can use to reduce this complexity, ‘Switch’ statements and functions.

Switch statements offer these benefits to most developers:

  • They are easier to read, and thus
  • They are easier to understand, and thus
  • They are easier to maintain.
  • They are also easier to debug
  • In many languages, they also can be compiled to execute a little more swiftly that nested ‘If’ statements

Here is an example of an ‘If’ statement than can be improved by converting it to a ‘Switch’ statement:

If aValue = 6 then

Stars = stars + 1


if aValue = 7

Stars = stars + 3


if aValue = 8

Stars = stars + 5


if aValue = 9

Stars = stars + 9

End if

End if

End if

End if

Here is the same logic from above, using a ‘Switch’ statement:

Switch aValue

Case 6:

Stars = Stars + 1

Case 7:

Stars = Stars + 3

Case 8:

Stars = Stars + 5

Case 9:

Stars = Stars + 9

I suspect that you will agree that it is easier to understand the code in the switch statement than the code in the nested ‘If’s. Another technique to eliminate nested ‘If’ statements is to move some of the code into separate functions. Although the hierarchy of ‘If’ statements may remain the same from the computer’s point of view, to most humans it becomes much easier to manage.

If input data is valid

If filename is valid

Create File

If file was created

Log “Success”

Return “Success”


If error due to size

Log “Failure”

Return “Could not create file because it is too large.”

If error due to permission

Log “Failure”

Return “Could not create file because you do not have permissions.”


Log “Failure”

Return “Unable to create the file. Reason unknown.”

End if

End if


Log “Failure”

Return “Your file name is invalid.”

End if


Log “Failure”

Return “The file input is invalid.”

End if

Here is the same logic from above, using functions:

String response = “”

Response = IsInputValid(myinput)

If (response= “”)

Return response

Response = IsFileNameValid(myfile)

If (response= “”)

Return response

return FileCreationResultMessage(myfile, myinput)

The functions called from the code above:

Function string IsInputValid(string input)

If input is not valid

Log “Failure”

Return “The file input is invalid.”


Return “”

End if

End Function

Function string IsFileNameValid(string input)

If input is not valid

Log “Failure”

Return “Your file name is invalid.”


Return “”

End if

End Function

Function string FileCreationResultMessage(string file, string input)

Create File

If file was created

Log “Success”

Return “Success”


If error due to size

Log “Failure”

Return “Could not create file because it is too large.”

If error due to permission

Log “Failure”

Return “Could not create file because you do not have permissions.”


Log “Failure”

Return “Unable to create the file. Reason unknown.”

End if

End if

End Function

As with any of Robert’s Rules of Coding, you don’t need to adhere to them all of the time and there are cases where it is better not to. But most programmers should follow the rules most of the time. I hope you agree.

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | 6 Comments »

Robert’s Rules of Coders: #8 Avoid Negative Conditionals And Method Names

Posted by robkraft on January 20, 2016

When you write code you should almost always assume that another person will attempt to read and understand that code some day in the future. That person could be your future self. Therefore, it is in your best interest to write code that can be quickly and easily understood by people, in addition to providing the correct instructions to the computer. Two ways to do this are to avoid negative conditions and negative words in method and variable names.

Avoid Negative Conditions

Let’s consider the following two ways you could write a bit of logic:

You could write:

If a > b then… //If a is greater than b

Or you could write:

If a !<= b then.. //If a is not less than or equal to b


A computer will understand both ways equally well, but it usually takes humans a little longer to understand the second way than the first. And when another developer adds a little more logic to the statement it takes humans even longer to figure out as shown in the next two statements:


You could write:

If a > b and c > a then… //If a is greater than b and c is greater than a


Or you could write:

If a !< b and c !< a then… //If a is not less than or equal to b and c is not less than or equal to a


When developers see the second way above they will probably write down numbers on a piece of paper to help them deduce the logic, even though ultimately it is the same as the first way. Of course changing the sequence of the conditions can also make the logic more readable, but in some languages that may come with a performance impact.


Consider Performance Impact of Condition Sequence

You could write:

If a > b and c > a then …



If c > a and a > b then …


Both ways provide the same output, but many languages will only evaluate the second condition if the first condition is true. This happens because the language is smart enough to realize that if the first half of the statement is false then the entire statement will be false. So in some cases, like in the methods below, it is probably more efficient to write the code the first way than the second way even though the results are the same:


The first, more efficient way to write the code:

If FastMethodThatReturnsTrueHalfTheTime() == true and SlowMethodThatUsuallyReturnsFalse() == true then…


The second, less efficient way to write the code:

If SlowMethodThatUsuallyReturnsFalse() == true and FastMethodThatReturnsTrueHalfTheTime() == true then…



Avoid Negative Words in Method Names

We often include method names in our ‘if’ statements and therefore we should probably avoid negative terms in the names of our methods. Consider the following examples of a method that checks for hyphens in a string:


String streetName = “Happy-Road”

If StringContainsHyphen(streetName) Then …

If StringDoesNotContainHyphen(streetName) Then …


The two statements above both seem easy to understand, but what happens if a coder checks if the results are false? Notice that it gets more difficult to interpret the second statement that contains the negative word “Not” in the name.


If StringContainsHypen(streetName) == false Then …

If StringDoesNotContainHypen(streetName) == false Then …


Avoid Negative Words in Variable Names

The guidance to avoid negative words in method names holds similar value for variable names, particularly the names of boolean variables.


We could name a boolean blnCountExceedsMaximum, or blnCountDoesNotExceedMaximum. We could also name it blnCountIsBelowMaximum or blnCountIsNotBelowMaximum. Now look at the following four statements and decide for yourself which is easiest to understand.


  • If blnCountExceedsMaximum == false then …

  • If blnCountDoesNotExceedMaximum== false then …

  • If blnCountIsBelowMaximum == false then …

  • If blnCountIsNotBelowMaximum== false then …


If you are like me, the second and fourth statements take a little longer to understand than the first and third.


Should you include “Is True” and “Is False”?

I have one last topic I think you should consider when writing ‘if’ statements. Should you include the “== true” and “==false”, or just leave the variable without that? A lot of languages do not require those values. The computer handles the following two statements equally well.


If blnSuccess == true


If blnSuccess


Personally, I don’t think it usually matters too much and I tend to code both ways. Sometimes, usually when my if statement has a method call in it or multiple conditions in it, I will include the “== true” or “== false” because I believe it adds clarity:


If (ExportDataToFile() == true and LastExportSucceeded == false) then


If you are going to test if a non-boolean variable is true or false, then I recommend including the “== true” or “== false” to let the next programmer know that this is what you intended.


//You could test if “number of failures” is not equal zero this way

If NumberOfFailures == true


//Or you could test if “number of failures” is not equal zero this way

If NumberOfFailures


In the second statement, it is not obvious that you intended to test the number as a boolean. Another programmer looking at the code might think you accidentally left part of the code out of the program. Rather than use either of those statements, it would probably be best to write:


If NumberOfFailures != 0


As with any of Robert’s Rules of Coding, you don’t need to adhere to them all of the time and there are cases where it is better not to. But most programmers should follow the rules most of the time. I hope you agree.

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Robert's Rules of Coders | Leave a Comment »

Robert’s Rules of Coders: #7 Use Constants For Values That Don’t Change

Posted by robkraft on October 17, 2015

All programming languages, at least that I know of, support the concept of variables that are used to hold values that change while the program is running.  But a lot of cases exist where we need to define a value to our code even though that value will not change as the program runs, and we have three options for providing this value.

We could simply code the value (3.14 in this example) where it needs to be used:

Circumference = 3.14 * diameter

We could create a variable and assign the value to the variable:

Double pi = 3.14

Circumference = pi * diameter

We can declare a special type of variable known as a constant:

Double const pi = 3.14

Circumference = pi * diameter

Of the three options above, using a constant is usually the best option for several reasons.

Variables over values

First of all, if the value will be used in many places in the program, you will often save yourself time by placing the value in a variable or a constant so that if the value ever changes you only need to change it in one place.  You may decide that instead of using 3.14 that you prefer to use 3.14159 in the calculations.  If your variable is a string for a format such as “mm/dd/yy” you may decide later that you want the format to change to “mm/dd/yyyy” and using a variable or constant makes the change easier, and more accurate because you are less likely to overlook some.

Use Variables To Make Code Changes Easier

Use Variables To Make Code Changes Easier

Second, when changing the value you are less likely to change the wrong value when you use a variable than if you use a value.  In the example below, you are less likely to change the tax rate from 3.14 to 3.14159 if you are using a variable than if you are using a value.

Variable Help You Change The Correct Value

Variable Help You Change The Correct Value

Third, variables make your code more readable. Many people may know that Pi is 3.14 and recognize the value in code, but few would recognize the number 8 as representing the number of planets:

  • For I = 1 to 8
  • //do some code
  • Next I

Is less clear in meaning than the following:

  • For I = 1 to NumberOfPlanets
  • //do some code
  • Next I

Constants Instead of Variables

Values that won’t change while the program is running can be defined as “constants” in most programming languages. This informs the compiler that the value will not change and the compiler can make the program a little more efficient. Often, what the compiler does is the equivalent of a find/replace everywhere the constant is used. This means that the variables will not need to be placed on the memory stack reducing the RAM required by the program to run.

By declaring that your variable is a constant, you also ensure that your own code does not attempt to unintentionally change the value of the variable while the program is running.

Here are some examples of good places to use constants instead of variables:

  • When your program has a name that you show on Title Bars and in log file messages such as:

String const PROGRAMNAME = “My Program Name”

Note: some languages have conventions for constant names such as using all upper case letters for the name. I recommend following the conventions of the language you code in.

  • When your program formats a value in many places, especially if that format may ever change:

String const DATEFORMAT = “mon , dd, yyyy”

  • Values that almost never changed that are used in multiple places:


  • Messages or part of messages that occur frequently in the code.  This also helps you reduce the number of spelling errors.

String const ERROROCCURREDHEADER = “An error has occurred!”

When you write programs that have code in multiple assemblies, or projects, or dlls, you may want some constants to be used across the whole program, and others used just within a single assembly.   Use scope and careful naming conventions to correctly place those constants.  If a constant will only be used within one assembly, then declare the constant within that assembly and don’t make it globally accessible.  If you want the same constant used by several assemblies, place it in an assembly all the others can reference and give it a good name like GlobalConstants.

Solution for Program with Three Projects:

  • Project1 named SharedAlgorithms
    • Contains a class named GlobalConstants with these constants:
      • String const ERROROCCURREDHEADER = “An error has occurred!”
      • String const DATEFORMAT = “mon , dd, yyyy”
  • Project2 named TaxCalculations
    • Contains a class named TaxConstants with these constants:
      • Double const TAXRATEFORMISSOURI = .08
      • Double const TAXRATEFORKANSAS = .12
  • Project3 named AppUI
    • Uses the constants from the SharedAlgorithms project, but not the constants from the TaxCalculations project because it does not need any of those values.

Warning: In many languages, you need to recompile both the AppUI project and the SharedAlgorithms project in the example above if the GlobalConstants are changed.  If you don’t, AppUI will continue to use the values the constants had at the time it was compiled, not the values the constants in SharedAlgorithms currently have.

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | Leave a Comment »

Robert’s Rules of Coders: #6 Don’t Use Magic Numbers

Posted by robkraft on September 7, 2015

When someone refers to a magic numbers in software, they probably have one of the following three scenarios in mind:

  • A value that is used to determine the behavior of the code, but the value itself provides no meaning
  • A value that has been hard coded in several locations in the program, that is unlikely to change, but might
  • A value that is well known in some software and that will not be changing

Using a magic number directly in your code can lead to problems and it is recommended that you avoid or minimize the use of them.  Let’s examine each of the three types of magic numbers and the risks associated with using them.

Example One with Magic Numbers

Example One with Magic Numbers

The first type of magic number in the above example is the value for the AccountType.  When looking at the code, most programmers will not know what the values of 1, 2, and 3 represent.  This type of magic number is common when the programmer is comparing the AccountType to a value that has come from a database or file and the value was persisted as a 1, 2, or 3.  But many programming languages today support the concept of an enumeration, or enum, that can be used to make the code more readable:

Example Two Eliminating A Magic Number

Example Two Eliminating A Magic Number

Using an enumeration in place of a hard-coded magic number offers several advantages:

  • The code is easier to understand for humans. The code is easier to write for humans because we don’t have to reference documentation elsewhere to know what an AccountType of 1, 2, or 3 means.
  • It is easier to alter a value. If the source of the data decided that the value 2 should represent “No Taxes” and 3 should represent “No Federal Tax”, the code could be adjusted where the enumeration is defined.  That is much easier than searching all of the code to replace 2s with 3s and 3s with 2s.
  • It is easier to review the code where the enumeration containing all of the possible values are defined for accuracy and completeness.

The same block of code above also includes another type of magic number with the values of 1.1 and 1.03 to represent tax rates.  I suspect you already realized that hard-coding the tax rate is risky because the values change so often.  But some magic numbers are less obvious such as in this example:

Example Three with a Magic Number

Example Three with a Magic Number

In this example the magic number is the number 50.  There are 50 states in the USA as I am writing the article, but that number could change.  If you have coded the number 50 representing states in several places in your program, someone will need to change them all if that number of states changes.

Example Four Without Magic Numbers

Example Four Without Magic Numbers

Using constants to eliminate this type of magic number provides several advantages:

  • The code is easier to understand for humans. We know right away that we are looping through the number of states and don’t have to question what the value of 50 represents.
  • It is easier to alter the value. If the USA adds one more state we can change the constant defined in one place in the code and be done with our changes. A programmer could do a find and replace across all of the code on the value 50 easily enough, but the number 50 might be used in other places referring to something other than the number of states in the USA.
  • A developer could accidentally type 60, 500, or even 49 instead of 50 and the compiler would allow the code to compile without warning.  This problem is less likely when the important value is only coded once and a variable name is used throughout the program.

The third class of magic numbers are numbers that indicate types of files or the beginning and ending of streams of bits in protocols.  These magic numbers are generally dependable, but you should still avoid coding them in the flow of your code logic primarily for readability.  One example is the use of FFD8 and FFD9 at the beginning and ending of JPEG files.  Instead of hardcoding this magic number inline in the code:

Example Five With Magic Numbers

Example Five With Magic Numbers

Consider defining a constant to improve readability.

Example Six Without Magic Numbers

Example Six Without Magic Numbers

There are some drawbacks to eliminating magic numbers, but the benefits of eliminating them usually outweighs the drawbacks.  Drawbacks include:

  • The programmer might want to know the value of the constant or enumeration and would need to refer to where the value is defined to discover it.  This could take a little time if the constant or enumeration is not defined closely to where it is being used.
  • It makes the source code a little bit longer. In compiled languages, this is almost never a concern, but it non-compiled languages like javascript it might have a small impact on performance.

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | Leave a Comment »

Robert’s Rules of Coders: #5 Organize Your Code

Posted by robkraft on August 30, 2015

When you write programs that consist of many lines of code, where the threshold of “many lines” probably begins around fifty lines of code, you should consider organizing your code in ways that will make it easier for you to maintain it in the future.  Breaking the code into many functions is a good start, but when you have a lot of functions it can become difficult to manage and remember them.  At this point you should consider grouping related functions, and in most programming languages placing the groups of related functions into separate files.

The major benefit is that you, and other developers, can more easily find the code you are looking for when you want to examine or modify it.

You may consider placing all functions you use to generate and send emails into a single file that you name Email.Code.  You may move all of your functions for formatting strings into a file name StringFormatting.Code.  Organizing your code into separate logically grouped files provides the simple benefit of helping developers find the code to be worked on more quickly.  For example, if you are on vacation and I need to fix a bug related to emails in your code, I can find the bug more easily if the email code is in its own file than if all of the program code is in one single large file.

Having many separate files for your code also helps you track changes in the code when you are using a source code control system; which you should be doing.  For example, if I made a change several months ago to the Email.Code and I now realize that my change might have broken something, I can use my source code control system to review the changes made to Email.Code more easily than I can use it to review the changes to All.Code.

Business developers often use the technique of object oriented programming to help determine how to organize their code into separate files.  The programmer may put all the code related to customers in Customer.Code, and all of the code related to products in Products.Code.  Although placing code in separate files is not what object oriented code is really about, it is a natural side effect.  Large object oriented applications may use several files for a single “object”. Instead of just a single file for Customers, the code may be broken into several files such as CustomerProperties.Code, CustomerPersistence.Code, and CustomerBusinessRules.Code.  Once again the primary reason for multiple files is usually because programmers have learned that many small source code files are easier to develop with than a single large file of code.  Another benefit when there are multiple developers may be that each developer focuses on a different area of expertise and one developer focuses on …Persistence.Code files and another developer focuses on …BusinessRules.Code.

An additional approach to organizing code, and I choose the word additional because it could and should be used along with organizing code by object and function, is to group code in different layers of the application architecture together.  Many applications today consist of at least three layers:

  • a User Interface (UI) layer,
  • a business logic layer,
  • and a data persistence layer that stores data in files or databases.

It is very beneficial for developers to keep the code in these layers separate because it makes it easier for the developer to make some changes in the future.  On such change could be storing data in a different type of database.  Another could be replacing the desktop UI with a web page UI.

In object oriented development, developers following the SOLID principles, will implement the “Single Responsibility” principle which leads them to limiting each “class” to doing just one thing, hence the term “Single Responsibility”.  Although this does not necessarily dictate that a developer will only have one class per file, that is often the case and thus followers of the “Single Responsibility” pattern are likely to organize code into separate manageable files.

So instead of placing all of your code in a single file like this:

File1: AllMyCode.code

All Code in One File

All Code in One File

Break the code into separate files like this:

File1: UICode.code

Code In 1st File

Code In UICode.Code file

File2: ProductCode.code

Code In ProductCode.Code File

Code In ProductCode.Code File

File3: CustomerCode.code

Code in CustomerCode.Code File

Code in CustomerCode.Code File

File4: EmailCode.code

Code In EmailCode.Code File

Code In EmailCode.Code File

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | Leave a Comment »

Robert’s Rules of Coders: #4 Make Functions Short

Posted by robkraft on August 18, 2015

Functions are easier to understand and thus easier to maintain when they are short.  You can often make functions shorter by finding patterns in a large function and extracting those lines of code comprising the pattern into a separate function and calling the separate function as shown below.

One Long Function

One Long Function

One Short Function With The Same Results

One Short Function With The Same Results

Note: The FormatForOutput function is not shown because I believe you can figure out what it does.

But even when you have a long function with no lines of code that are duplicated, you can often make the code more readable and easier to maintain by separating the code into functions.  Consider this example:

One Long Function

One Long Function

Long Function Broken Into Short Functions

Long Function Broken Into Short Functions

Note: The 4 new functions are not shown because I believe you can figure out what they do.

Most developers will be able to understand the 2nd example better than the first.  But there is another big benefit that applies in a lot of languages.  Let’s assume that an error occurs with a message of “Object variable is null”.  In the first example, the error message might show a call stack that says our program named Program1 called the method MainCodeBlock and this error occurred within MainCodeBlock.

Call Stack from First Example:

  • Program1
    • MainCodeBlock

But which line of code within MainCodeBlock?  We don’t know and it could have been caused by many of the lines.  However, if the same error occurs in the second example, our call stack would look like:

Call Stack from Second Example:

  • Program1
    • MainCodeBlock
      • SavePriceToDatabase

In the second example, we have narrowed down the problem to the SavePriceToDatabase method and have only a few lines of code to consider as the source of the error.  This is another benefit of smaller functions.

Finally, for those of you that write unit tests as most good programmers should, you have functions neatly wrapped up and ready to be called by those unit tests.

In summary, short functions provide these benefits:

  • They organize your code, making it easier to understand and maintain.
  • They make it easier to pinpoint bugs when you have a call stack.
  • They make it easier for you to write unit tests for your code.

Go to Robert’s Rules of Coders for more.

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | Leave a Comment »

Robert’s Rules of Coders: #3 Use Good, Meaningful Names

Posted by robkraft on August 6, 2015

Code is much easier for humans to read when the variable and function names reflect what they mean and do.  In ancient times, like the 1960s, some programming languages did not support long variable names, but today most every language supports long names with no penalties.  Although some exceptions may be tolerated for very common usages such as the variables “I”, “j”, and “k” for loops, you should strive to use meaningful names in all cases.  Would anyone honestly say that the first block of code below is easier to understand than the second?

Code with and without good names

Code with and without good names

Good, meaningful names not only make your code more readable, but they may also remove the need for you to add comments or documentation to the code.

When we first began writing javascript in the 1990s we used short variable names because we wanted to reduce the size of the files to make them faster.  Today, you should probably not do this because the data is compressed by default by technologies like gzip, and Internet speeds are faster, and if you are writing enough code that the size of your javascript is a factor you should be using a minifier tool to make the javascript smaller for you.

Aside from long names, what makes a variable or function name good?

  •  Good names reflect the value stored in the variable or explain what the function does. “Counter1” is better than “c”, but “ActionCounter” is even better. Giving variables relevant names reduces the time it takes people in the future looking at the code to figure out what it does. And that includes the future you. This applies to function names also. A function named “UpdateActivityCount” is better than “CountUpdater”.
  • Try not to use negative logic in variable and function names. It takes our brains a little longer to deduce the meaning of negative logic statements.
    • IsValid is usually a better name than IsNotValid
    • DoesValueExceedMaximum is usually better than DoesValueNotExceedMaximum
  • Follow the conventions of the language you are coding in. If the language uses CamelCase, you should use CamelCase. If the language uses Hungarian Notation (txtFirstName, intItemCount), you should use Hungarian notation. If the language uses all upper case for the names of CONSTANTS, you should use all upper case for CONSTANTS too.
  • Don’t reuse variable names for different purposes.
Example of Reusing a Variable

Example of Reusing a Variable

  • The function name should describe what it does not how it does it.  This allows you to change how the code in the function works without needing to change the function name. This helps the function remain a black box.
    • Name the function GetAllCustomers, not CallDatabaseUsingADOtoGetDataFromCMCUSTTable.
  • Avoid names that might match keywords. Naming a variable “Name” or “Date” might compile safely at first, but it might fail after an update to the language is installed, or if you include a new library in the project. Also, it may not be obvious to other developers that the variable name is one that you created instead of one that is built in.
  • Follow a consistent pattern
    • If your Foo object has a Retrieve method to get data from the database, then your Bar object should also have a Retrieve method to get data from the database, not a Get method. Using the same method and property names across objects when the methods serve the same functions reduces the learning curve for new developers.
    • You should also strive to use consistent noun and verb pairings.  Naming two functions CalculateLastSaturday and CalculateLastSunday is usually easier for programmers to remember than having one function named CalculateLastSaturday and the other named FigureOutFinalSunday.

Finally, remember to rename your variables if the meaning of the value they store changes and rename your functions if the things the function does changes.  We are writing code for humans, not for computers.

Are there any more good rules that should be added to this list?

Posted in Code Design, CodeProject, Coding, Robert's Rules of Coders | Leave a Comment »