The Pragmatic Programmer

pragmatic_programmer

The Pragmatic Programmer is one of those books which is usually included in the recommended readings for a software developer, and deservedly so. The book, released in 1999, has been so successful that the two authors, Andrew Hunt and David Thomas, have since created their own publishing company, the Pragmatic Bookshelf (with titles spanning a broad range of programming topics).

This book must really have been a breakthrough when it hit the bookstores about 15 years ago. 1999 is one year before Kent Beck released his seminal book Extreme Programming Explained: Embrace Change which exposed the agile software process to the masses. Both Andrew Hunt and David Thomas originally signed the Agile Manifesto, together with Kent Beck himself and a few others, and it shows. But it would be dismissive to describe this as a book on agile since it’s much more.

The book is structured as a series short 46 sections. Each section has challenges and even exercises where appropriate. It touches on design concepts such as orthogonality, decoupling, DRY (which it coined), Domain Specific Languages, Design By Contract, Metaprogramming, Refactoring; it has pages on process topics like build automation, “design to test”, test automation, estimation, requirements collection.

But where the book really shines is where it shows you how to “become a better programmer” (today we might say a software craftsman) and to take pride from it.

The pragmatic programmer is an early adopter, is inquisitive and realistic, and tries to be “familiar with a broad range of technologies and environments”.

The pragmatic programmer takes responsibility, values quality but recognizes when the software is “good enough”. The pragmatic programmer is a continuous learner (the “learn at least one new language every year” advice is often quoted), thinks critically about what he reads and hear, and knows how to communicate. The books explains how you can build these qualities.

All in all, the Pragmatic Programmer is easily one of the best book on software development I have ever read. It has really inspired me to continue my journey to become a “better programmer”.

The Mythical Man Month

mythical_man_month

The effects of manpower on scheduling
Brooks spends a lot of time covering scheduling and manpower. One of the most poignant statements he makes is coined Brooks Law:

Adding manpower to a late software project makes it later

He backs up his law with numerous examples and antecdotes, but he makes a key point as to why adding more people lengthens a schedule rather than shortens it:

Since software construction is inherently a systems effort – an exercise in complex interrelationships – communication effort is great, and it quickly domiantes the decrease in individual task time brought about by partioning. Adding more men then lengthens, not shortens, the schedule.

When it comes to scheduling and manpower, Brooks makes the point that “the number of months of a project depends upon its sequential constraints. The maximum number of men depends upon the number of independent subtasks.” In other words, independence of tasks in the most important factor in determining if adding people to a project will reduce schedule.

Assembling schedules
At numerous points, Brooks hammers home the point that test and debug are the most misunderstood and under estimated tasks in a schedule. From his experience he uses the following formula for creating a schedule: “1/3 planning, 1/6 coding, 1/4 component test and early system test, 1/4 system test all components in hand.” He follows with this observation:

In examining conventionally scheduled projects, I have found that few allowed one-half of the projected schedule for testing, but that most did indeed spend half of the actual schedule for that purpose

The risk of not putting in enough time for system test and debug is the following:

Failure to allow enough time for system test, in particular, is peculiarly disastrous. Since the delay comes at the end of the schedule, no one is aware of schedule trouble until almost the delivery date. Bad news, late and without warning, is unsettling to customers and to managers.

There’s a lot of suggestions, recommendations, and tips that you can pull from book that will help everyone involved in a project do a better job of estimating schedules, or at a minimum, recognizing problems with their scheduling philosophies.

Additional quote and excerpts
Here is a collection of other quotes that I highlighted while reading the book. Many of these stand on their own, although they are even more powerful when read in the overall of context of the book.

The architect of a system, like the architect of a building, is the user’s agent. It is his job to bring professional and technical knowledge to bear in the unalloyed interest of the user, as opposed to the interests of the salesman, the fabricator, etc.

The architect must always be prepared to show an implementation for any feature he describes, but he must not attempt to dictate the implementation.

The task of the manager is to develop a plan and then to realize it.

Where a new system concept or new technology is used, one has to build a system to throw away, for even the best planning is not so omniscient as to get it right the first time.

Many poor systems come from an attempt to salvage a bad basic design and patch it with all kinds of cosmetic relief.

It is more important that [schedule] milestones be sharp-edged and unambiguous than that they be easily verifiable by the boss.

…each software organization must determine and proclaim that great designers are as important to its success as great managera are, and that they can be expected to be similarly nurtured and rewarded.

It is necessary to separate the architecture, the definition of the product as perceivable by the user, from its implementation.

Having a system architect is the most important single step toward conceptual integrity.

Obviously, I could go on and on, but you should get the point by now. The point being if you are involved in software development in anyway whatsoever, be it development, project management, personnel management, or executive management, the book is worth your time. Sure, a few concepts are dated, but the vast majority still apply today and will help you avoid making mistakes that were discovered forty years ago and are still made today.

I continue to be amazed by how books about such dynamic subjects can stay relevant, and at times become more relevant, than when they were written. To me, it clearly demonstrates how well Brooks approached his work. For Brooks to take a subject as dynamic as software development, which has changed immensely over 40 years and which continues to evolve rapidly today, and create a timeless classic is quite an accomplishment. It goes to show that fundamentally sound ideas are timeless. In other words, one of the biggest lessons I took from the book is that following good, sound advice is better than chasing the latest development trend or fad of the day.

Rapid Development

rapid_development

I recently finished Rapid Development which I half-jokingly refer to as an encyclopedia of software development practices. McConnell is probably best known for Code Complete 2. That book cover how to code well in a similarly encyclopedic manner. Code Complete 2 is a lot more applicable when you first start developing. Rapid Development is more useful when you’ve been doing it for a few years.

Part 1 – Efficient Development
The first 100 pages is about how to develop software efficiently and rapidly. To develop software rapidly means different things, increasing speed, decreasing risk and increased visibility to business owners are all dimensions to rapid software development. And at some point you have to make trade-offs between these types of rapidity. The other big takeaway from this section is that developing software successfully is more about not screwing up than doing one thing really well. He actually has a checklist of common mistakes (which can be found online here) that lead to projects being delayed. If you make any of the common mistakes then the project is likely to be delayed or fail.

He groups the problems into four categories peoples, process, product and technology. Even when the book was written in the early 90s the people and products category had three times more problems than technology and product. Since then the ratio has become even more skewed. Technology problems are the ones we concentrate the most on because they are the most comfortable for us to solve. But we often to don’t notice people or process problems or just accept them as the cost of doing business. The checklist was what initially got me interested in the book, and it was nice to see the reasoning behind each item on it.

Part 2 – Rapid Development
The second section is the meat of the book and covers in detail the areas that affect development speed. He covers every topic that can affect it from estimation, to teamwork, feature control, life cycle planning, etc. Each of these topics gets between 20 to 50 pages, with an extensive further reading section at the end of each chapter. These chapters are designed for people to skip parts of so if you find a certain section dragging it’s easy (and even encouraged) to go to the next one. If you want a fuller understanding of all the issues related to developing software on time though it’s worth reading every chapter. A nice thing about the encyclopedic nature of this book is that each section will reference the other related sections. This means the book is set up for wiki-walk style reading, once you find an issue that you’re interested in you can jump into the related topics and those topics have related topics, etc

Part 3 – Best Practices
McConnell finishes with some rapid development practices that can be used to improve the different dimensions of rapid development (speed,risk,visibility). These practices can be used together or in a alone and McConnell lists the pros and cons of each. Getting your team to do “Voluntary Overtime” for the project will get it done much faster but has a high chance of burnout. A lot of these practices seem to be standard practice if you’re doing some form of agile, although they may go by different names. One I had not seen before that seemed especially useful was having the developers maintain a top 10 risks list for a project.

Conclusion
This book was an interesting mix of (current) best practice, dated ideas and timeless advice. At almost 20 years old that is to be expected but it still threw me for a loop. When the book goes on about the importance of source control, nightly builds, and iterative design I had to remind myself that those things became standard practice in part because of this book. In that way it is a victim of its own success. Other parts like hearing about 4GLs and RAD just reminded me that the next big thing can fall to the wayside quickly. The parts of this book I found most helpful were the parts on estimation, feature scrubbing and development styles. Good technique in these categories has not changed huge amount. Process and people change slower than product and technology.

This is a book I would recommend to a developer with two caveats. One it covers the people and process topics amazingly in depth and you should concentrate on those parts. The product and technology part seem to have aged the poorest and the advice in it may be out of date so you may just want to skim them. Secondly some of the process suggestions felt specific to shrink-wrap software. Which has different maintenance and development costs than web development. It’s still worth reading and if you can’t read the book at least print out a copy of the checklist of common mistakes, laminate it, hang it next to your Kanban board and think about if you’re making a mistake on it every day.

Code Complete 2

code_complete2

I recently embarked on a journey to read (or re-read) all the great classic books in the software literature. This is the first in a series I will do on this site.

Code Complete is a massive work, so this summary is, necessarily, very high level. It is not a book that one can absorb completely in one reading, but one can absorb its high level themes (summarized nicely in the second to last chapter).

“Conquer Complexity”
High quality code manages complexity. No one can think of all of the levels of abstraction needed to fully understand a program at once; just admit it and try to make your code less complex. Complexity can be managed at every level of the development process from having a well thought out high level design to choosing good variable names.

“Pick Your Process”
Having a process is important. It does not matter exactly what the process is; in fact, the process should be tailored to the problem at hand. The purpose of a process is to allow for coordination between people. When a project is small (1, maybe 2 people), then it is the talent of the individual that matters most. When a project is large, it is managing communication that matters most.

“Write Programs for People First, Computers Second”
Computers do not care about programs being readable, but people do, and people are going to read your programs many time. Readable code has a plethora of advantages including lower error rates, being easier to debug and modify, and having shorter development time. Make code readable first, and only optimize when you can make measurable improvements to measurable performance bottlenecks.

“Program into Your Language, Not in It”
Do not limit your programming by the features your language supports. Write libraries that will support the programming features you want for the problem at hand. One example McConnell gives writing an assertion library if your language does not support assertions.

“Focus Your Attention with the Help of Conventions”
Conventions, like processes, do not matter in their particulars. Some conventions are better than others, but for the most part, conventions tend to be arbitrary. However, having conventions makes code easier to read and modify because a convention can communicate a lot without using much space or requiring much thinking.

“Program in Terms of the Problem Domain”
This is a particular method of managing complexity. Higher level code should be supported by lower level code that hides implementation specific details from the higher level code. When done well, this makes the code easier to read and easier to modify. Even at the construction level, this can be done by choosing good class names and abstractions, factoring code into methods to maintain a common level of abstraction, and choosing good variable names.

“Watch for Falling Rocks”
Look out for warning signs, such as classes with an abnormally high number of defects. These warning signs do not necessarily mean that something is wrong with that part of the program, but they are a good indicator that you should be a little bit suspicious. These warning signs could show up after construction (error rate) or during construction (compiler warning, indications from your self or other that your program is hard to understand).

“Iterate, Repeatedly, Again and Again”
In addition to being my favorite section heading in the book, this principle emphasizes that iteration is appropriate at all points of the software development process. Requirements are rarely fixed in stone, bugs are always present, and developers can always find a better way to rewrite code. Iteration gives all of these improvements a chance to actually make it into the product under development.

“Thou Shalt Rend Software and Religion Asunder”
No one convention, process, or tool set is the be all and end all of software development. Developers should be wary of absolutes and try to avoid blind faith in the processes they use. Solutions should be adapted to the problem at hand, not vice versa. The key to keeping an open mind and becoming effective and flexible is experimentation. Be willing to try new things, measure the effectiveness of those experiments, and be willing to change based on the results.

Those are the high level principles. These principles occur over and over again through the seven parts of this book.

“Laying the Foundation”
This section discusses the general process of software development and the role of construction (a.k.a. programming) in that process. Construction is important, according to McConnell, because it is the only part of the software development process that absolutely must happen to produce a working software project. Construction is also an area that, traditionally, has not has as much attention to it as other areas (such as high level design or testing). However, McConnell stresses that all parts of the development process are important in creating a successful project and gives pointers throughout the text to resources that discuss other parts of the software development process in more depth. He notes that pre-construction planning is particularly important since no amount of good construction and through testing can save a bad design.

“Creating High-Quality Code”
This section introduces a point emphasized again and again throughout the book. Software’s “Primary Technical Imperative” is managing complexity. High quality code exposes people reading it to consistent levels of abstraction separated by clear boundaries. Complexity is managed by minimizing the essential complexity one has to deal with at any given time and trying to keep accidental complexity from spreading throughout the code base. High quality classes and routines provide consistent abstractions, document their assumptions, and check their invariants defensively; they fail sooner rather than later. Even a simple class or routine is worthwhile if it decreases the complexity of reading the code where it is used.

One of the most practically useful facts I got out of Code Complete was learning about the “Pseudocode Programming Process”. This process is a way of developing code by starting with detailed pseudocode. When constructing a program, a developer should (iteratively) write pseudocode that is high level enough to be in the domain of the problem but low level enough for translation to real code to be nearly mechanical. Developing pseudocode ensures that the developer understands the problem at a low enough level for implementation, encourages the programmer to think about error checking before implementing the nominal path through the code, may indicate what when to factor code into separate routines (and suggest names for those routines). Those parts of the high level pseudocode that the developer decides to leave in provide automatic, high level commenting of code.

“Variables”
The chapters in this section discuss data initialization (do it close as close to the declaration as possible), variable scope (keep it as small as possible), limiting variables to a single purpose, effective variable names (keep them specific, use a naming conventions), and tips for using fundamental and more complex data types.

“Statements”
This section discusses methods for effectively organizing and using straight line code, conditionals, and loops as well as more exotic control structures such as exceptions, gotos, and various table driven control structures. This section discusses how deep nesting of control structures tends to make code complex. If possible, it should be avoided by restructuring the code or factoring the nested code into its own routine. The more paths there are through a code fragment, the more complex it is; the number of paths a developer must consider at a single time should be minimized.

“Code Improvements”
Discusses software quality, collaboration, developer testing, debugging, refactoring, and code tuning. One key point of this section is that the goals of a certain construction project should be clear. Some goals are bound to go against each other, and if developers do not know which are most important, they will do a bad job of trying to optimize all of them at once. The most obvious example of this tendency is that aggressive optimization may make code less readable and prevent beneficial refactorings. This section also points out that code reviews, testing, debugging, refactoring, and code tuning all have the potential to improve code quality, but it is when they are used thoughtfully in unison that their potential is maximized.

“System Considerations”
Discusses some higher level issues in constructing a system. As project size increases, project quality and development speed tend to go down in a faster than linear manner. This is because as the project increases, more and more overhead gets taken up by managing communication and more details tend to get lost in the cracks. It is for this reason that having a process and conventions becomes more important on large projects; the more that is automatic, the less that quality and and development time will suffer. This section also discusses how to manage programmers and essential tools that every developer should know about and use. This section also discusses several integration processes and emphasizes that which process is right depends on the project being developed.

“Software Craftsmanship”
This section talks about good practices in actually structuring code and how to write good, effective comments and code that documents itself as much as possible. This section also describes the importance of personal character in becoming an excellent developer. McConnell posits that intelligence is less important than other personal characteristics such as humility, curiosity, intellectual honesty, communication and cooperation, creativity and discipline, effective laziness, and good habits. The point emphasized throughout the discussion on personal character is that a good developer needs to be happy and willing to learn from other developers and be willing to admit when their are right and wrong if they want to earn the trust and respect of others.

My Blog

In this post, I will write about the motivation behind my blog. The why. Why do I want sit on front of my computer after a long day, sitting in front of my employer’s computer? The reason is simple. I want to document my skills. I want to re-ignite my passion of hobby programming.

For that, I need a project. So here is my idea. With literally hundreds of websites that I use requiring account registration, I am in dire need for a good repository that keeps track of my accounts. Storing simple things like URL, User Name, and Password, and a few comments. Obviously, there is a need for robust security. But I will not focus much on that, as my main aim is to research, implement and measure different platforms, not develop commercial applications.

Research – the different platforms. Implement – the concept in the different platforms. Measure – benefits, performance and ease of use.

Possible application platforms are as follows:

  • .NET windows application – using some of the really popular third party tools like Telerik, DevExpress, etc.
  • HTML5 applications – Microsoft MVC, Sencha, Telerik Kendo UI.
  • Native Android App.
  • Native Apple iStore App.

Please stay tuned for my next post – where I will be looking at different tools to make and share my videos.

An Update

Wow! I was looking back at this and a lot has changed since my last post back in August 2009.

I moved from New Zealand to Australia. Went to Portugal for a conference where I presented my paper on Steganography (more on this in later posts).

Published a book on Steganography (http://www.amazon.com/Inaudible-Secrets-Improvements-Audio-Hiding/dp/3838357701/ref=sr_1_1?s=books&ie=UTF8&qid=1321665701&sr=1-1).

Meanwhile, started work as an Applications developer here in Townsville, Queensland.

On a personal front, I now have a beautiful baby girl, Seher.

So while it has been busy.. there was still something that was keeping me from posting. You know how it is.. an obstacle that keeps you from doing something.. and while you intend to remove it and the obstacle itself is very small, it takes a while to finally come around and address it.

In my case, the obstacle was formatting of code (C#, VB.NET, SQL). I found it quite hard on these posts, and was just short of writing CSS files to prettify it. But just today, I stumbled upon http://www.manoli.net/csharpformat/ which is a great tool to convert source code and display pretty HTML. So looking forward to using this to prettify my future posts 😉

Cheers.

A Polling Service

As mentioned, I am starting off the technical posts.

I found the following use of windows services very useful. Just wanted to share this with everyone.

There are certain situations where you need to monitor changes, and trigger actions, like changes in data in a database. Sure, you can use database triggers, but here is an alternative to using database triggers, which involves using a windows service.
I will not go over the basic steps of creating a windows service here. Rather, I will go through the idea of polling for information in a windows service. If interested in the basic structure of a windows service, this article in Codeproject is a good source of information.
A service class is created. Apologies for the (lack of) indentation – I blame the Post editor :-
1: public class MonitorService : System.ServiceProcess.ServiceBase
2: {
3: ///
4: /// Required designer variable.
5: private System.ComponentModel.Container components = null;
6: ServicePollingService pollingService;
7:
8:
9: public MonitorService()
10: {
11: // This call is required by the Windows.Forms Component Designer.
12: InitializeComponent();
13: }
14:
15:
16: // The main entry point for the process
17: static void Main()
18: {
19: System.ServiceProcess.ServiceBase[] ServicesToRun;
20:
21: // More than one user Service may run within the same process. To add
22: // another service to this process, change the following line to
23: // create a second service object. For example,
24: //
25: // ServicesToRun = new System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
26: ServicesToRun = new System.ServiceProcess.ServiceBase[] { new PollingService() };
27: System.ServiceProcess.ServiceBase.Run(ServicesToRun);
28: }///
29: /// Required method for Designer support ///
30:
31: private void InitializeComponent()
32: {
33: components = new System.ComponentModel.Container();
34: this.ServiceName = "Monitor Service";
35: }///
36: /// Clean up any resources being used.
37: protected override void Dispose( bool disposing )
38: {
39: if( disposing )
40: {
41: if (components != null)
42: {
43: components.Dispose();
44: }
45: }
46: base.Dispose( disposing );
47: }///
48: /// Set things in motion so your service can do its work.
49: protected override void OnStart(string[] args)
50: {
51: pollingService = new PollingService();
52: pollingService.Start();
53: }///
54: /// Suspends this service.
55: protected override void OnPause()
56: {
57: pollingService.Suspend();
58: }///
59: /// Resume this service.
60: protected override void OnContinue()
61: {
62: pollingService.Resume();
63: }///
64: /// Stop this service.
65: protected override void OnStop()
66: {
67: pollingService.Stop();
68: }
69: }
70:

 

Like most service classes, PollingService has a Start and a Stop method. The Start method starts a listener thread which monitors changes – it could periodically run another function/stored procedure, etc to “poll” or look for changes. This is shown below:
1: public class PollingService
2: {
3: private Thread listenerThread;
4:
5:
6:
7:
8: // Response Server States.private const int STOPPED = 1;
9: private const int RUN = 2;
10: private const int STOP = 3;
11:
12:
13: private int state = STOPPED;
14: public const string ServiceName = "Polling Service";
15:
16: public PollingService()
17: {
18: }///
19: /// Starts the Listener thread.
20: public void Start()
21: {
22: listenerThread = new Thread(new ThreadStart(this.Listener));
23: listenerThread.Start();
24: }
25:
26: ///
27: /// Stops the Listener thread.
28: public void Stop()
29: {
30:
31: // Signal to the worker thread that it should stop ...
32:
33: state = STOP;
34: listenerThread.Interrupt();
35: // Save required data here.
36: }
37:
38: ///
39: /// Suspends the Listener thread.
40:
41: ///
42: public void Suspend()
43: {
44: listenerThread.Suspend();
45: // Save required data here.
46: }
47: ///
48: /// Resumes current thread.
49: ///
50:
51: public void Resume()
52: {
53: // Initialize again.
54: listenerThread.Resume();
55: }
56:
57: ///
58: /// Listens for changes.
59: ///
60:
61: protected void Listener()
62: {
63: try
64: {
65: state = RUN;
66: while ( state == RUN )
67: {
68: PollForChanges();
69:
70: // Where the intervals come from configuration.
71:
72: Thread.Sleep(new TimeSpan(hoursInterval, minutesInterval, secondsInterval));
73: }
74: }
75: catch ( ThreadInterruptedException )
76: {
77:
78: // No need to log the fact that the thread has been interrupted.}
79: catch ( Exception e)
80: {
81:
82: // Log to database or event log.
83:
84: LogHelper.LogError(e.ToString());
85: }
86: finally
87: {
88: state = STOPPED;
89: LogHelper.LogWarning(string.Format("The {0} has shutdown.", ServiceName));
90: }
91: }
92:
93: ///
94: /// The Main method which polls for changes and
95: /// processes them.
96: ///
97:
98: private void PollForChanges()
99: {
100: try
101: {
102: // Method which processes the changes
103: ProcessChanges();
104: }
105: catch(Exception e)
106: {
107: LogHelper.LogError(e.ToString());
108: }
109: finally
110: {
111: // Save data
112: }
113: }
114:
115:

These type of services have proved extremely useful for us over the past few years – it has allowed us to monitor changes, pull/push data – quite good for integrating diverse systems.

Hope you find this useful.

What makes a good software developer?

I have often thought about this – “What makes a good software developer?” The answer to me, is not that straightforward – in fact, I may appear to be contradicting on some points. I will attempt to go over them (in no particular order):
A good software developer has to have:
  • The ability to see the bigger picture (or as my senior colleague used to say “the ability to see the forest through the trees”) as well as pay attention to detail. As a software developer, one is required to keep the overall architecture in mind, and design and program solutions that are in harmony with the bigger picture. The bigger picture may also be extended to mean that it is not necessary that all business problems or needs are met by software solutions – that sometimes changes to business processes are required to fulfill a business need.
  • The ability to be pragmatic while preserving the integrity of the software solution. This can be a bit of a gray area – you have to be pragmatic to a certain extent to deliver what the users require, and you have to maintain the integrity of the solution to have clear boundaries and a clean architecture. In some cases, these may be a bit mutually exclusive – for example, it is of no use having a realtime application going through five web services for a simple business function – while this may maintain the purity of the solution, in practice, it is unworkable and a pain to support.
  • The ability to keep an open mind, being receptive to new ideas, at the same time, not pursuing infeasible or bad ideas. Sometimes it may require you to investigate new ideas, sometimes it may require you to completely trust your team members, but the overall objectives need to be kept in mind – what we are delivering (the intention and the scope of the delivery), and the limitations or bounds in terms of time and resources.
  • The ability to filter out unneeded “noise” and be solution-focused. Many people go around in unproductive circles, get involved in the “drama”, rather than being solution-focused, having a plan, and resolving issues effectively. A good software developer needs to look at things objectively and be driven by sound skills and principles which help in delivering a solution.
  • The ability to work well in a team, as well as work well individually. This may seem easy.. but it can be challenging – especially working in a team made up of people from different technical backgrounds. I think that for a team to function properly, the roles and responsibilities of the team members need to be clearly defined. A healthy atmosphere needs to be created where productive discussions about different ideas are encouraged and an atmosphere where people move away from autonomous to consensual decisions. Working individually has its own challenges – you have to have a broader skill set, to name one.
  • The ability to contribute to, adhere to, and support processes/standards, and question them when needed. Processes and standards are put in place to make our lives easier. When a process/standard hinders software development rather than aid it, it needs to be questioned/improved/rectified.
  • Finally, a good software developer has a passion for the IT industry. It is quite essential for the software developer to be actively involved in new technologies, take an interest in current trends (eg cloud computing). Have a good understanding of where technology is at and being aware of how particular business needs could be met by fit-for-purpose technological solutions.
Most of the above points are not necessarily specific to software development – they can be taken out of the software development context and be applied to most industries.
Any comments, thoughts, discussion are most welcome.