Agile Development



Once in a while there is new wave, a new idea. Many developers faced traditional development methods and saw them fail. They stuck their heads together, distilled problems and focused on solving them. As always their is a radical approach first, something that shakes foundations, followed by adopted methods that can be made fit for you.
I have experienced both traditional and Agile development and for me Agile development has shown many advantages.

Let me get right to the point: For a software company the key factor to success is above all: time-to-market. If you can't make it to the market you will not earn any money and you will not get feedback if your are heading in the right direction. Development takes time and many projects failed - for certain reasons. Heads cleverer than mine have conceived techniques that are pragmatic and focus on getting a software ready to ship. Even though you and I will not use all of their proposals it is important to know your options.

The message and goal of object oriented and Agile development is change. Kent Beck once said: "Embrace change".
Try to develop as open to change as possible but do not waste time to develop any possibility. This is something to bear in mind and Agile development will help us to cope with that.

But now let us take a closer look at some ideas of Agile development.
There is an Agile manifesto.
  • It puts emphasis on people rather than on tools,
  • collaboration with the customer than contract negotiations,
  • working software than documentation and last but not least:
  • it emphasizes change rather than sticking to a plan.


As you might see the first and most important point are people - us developers. We are the ones that build software. We work in teams which means that social skills are more important than programming skills in the long view. You can learn how to program but to change a human nature can be daring or even impossible.

The second point is constant feedback from the customer. If you negotiate a plan and than develop for three years the requirements have definitely changed. Think of the process of Agile development as a cybernetic process. Feedback is input that gets processed and leads to constant adjustments to steer the software development home. This is a highly collaborative process and modern tools make it easy to prototype software (RDE tools like InterfacerBuilder and Cocoa Bindings).

When we talk about change we certainly have to focus on already written code. Often you will have to redesign (refactor) existing code to make changes possible. This in itself is an art and important. Don't just "do" it - find a solution that is elegant and simple.

But lets get back and delve a little deeper.
Many ideas are based on the great book mentioned on the side-note. I have learned some of them the hard way and thus the text is also filled with my own experiences.


Blame doesn't fix bugs


We have seen that the most important point are we. Developers are team players. The way we work is directly connected to the output. If team-members don't get along it will have an impact. We are professionals and our focus is on the product.
If you find faulty code of someone else it's tempting to just blame her/him. But this doesn't fix the problem nor does it help. It can even cause damage because some people are really reactive and don't respond to criticism as they should. Both parties will be insulted and still no code is fixed, time wasted and the mood is down. I've seen this and it's bad. So think about it: your team-mate is as human as yourself and wants to get treated like you would.

There are two reactions: active and passive. Active: When you find faulty code that you can't fix yourself go to the original developer and talk to him, approach him friendly and in a professional manner. Passive: You did something wrong and get addressed then ask how you can help to solve the problem. That is what it's all about: Solving the problem and getting the software to ship.
In a good team there is no gossip or talks behind one's back. That's the professional attitude. If you find that this is not possible on your team then think about changing the team - rather sooner than later. It can be sucking out a lot of energy, lead to frustration and take your output to nearly zero.


Don't criticize team-mates


As mentioned above development is a team effort. We developers have to work together. So when we discuss a new design it would be easy to give an unexperienced member a hard time by telling him how bad and flawed his design is and how incompetent he is. This will silent him down and all but one are happy. This is the easiest way to destroy a team and keep new ideas out. Negativity will kill innovation. Believe me - I've been down this road.

We have to focus on the problem. Sure a design can be flawed. We are humans - we make mistakes. If you think you see a possible problem address it with a question. The way you ask is important! No accusation, no judgement. Simply ask how the designer would solve the problem you see. Maybe there is a solution you haven't thought of or maybe this remains a problem and all can work on it to find a better solution. The original designer will see his flaw and even learn from it. He will keep an open mind. See how much better this is? You will have to criticize because nothing is worse than a bad design. But criticize the idea - not the developer! Always stay open and bring forth your concerns in a professional manner. Ask the right questions - they should clarify the matter. All together you will find a better solution than anyone could have alone. This is your objective. Don't fight about whose idea is better but find a solution.

Keep in mind: all solutions have trade offs. You need to find the one which has to fewest. So everybody on the team should bring up as many pro and cons as possible. It also may help to chose a mediator during such a discussion. As this could go on for ever set a deadline. You will never find the best solution. At a certain point the gain won't pay off anymore. Time is money! (Remember: time to market).
Finally (hopefully) you came to a decision. Then it is utterly important that everybody on the team supports it. Nothing worse than trench fights! It will be a compromise and you can and will live with it.


No quick fixes


If there is a bug - and there are many of them - don't just apply a quick fix. There are two problems with that: it might cause bugs elsewhere and the clarity of code diminishes.
First of all you should understand the problem and the cause of the bug. Then you should understand the process - why was code written that way. With that knowledge you can begin to fix the bug.

If you hit on a module that you can't understand and is marked as "Don't touch" you probably hit a very fragile module that will cause trouble in the future as nearly nobody will be able to apply fixes here without risking to break everything else. Toss it away and redo it - time well spent.

No that you fixed the problem write a unit test. Even better write a unit test before you apply the fix. See that it fails. Now apply the fix and it should pass. Add the unit test to your constant testing environment so this bug never appears again. (As a customer of a certain software I hoped the company would have done this - there are bugs that emerge once in while again and again - over many versions. I finally have lost faith in that company...)


The principle of the broken window


As code evolves over years you will definitely find old and maybe not so clever designs and even possible or real bugs. Designs could be too tight or too complicated. Don't be blind. If you hit on such a piece of code - even if it was not written by you - try to find a solution. Maybe refactoring will be the right thing to do or just some small changes. Strive to clean up code even if it may take some time. Discuss this matter with your teammates and they will come up with ideas.
If you leave such fragile (dirty) spots in the code the repository will feel like a big city with many old and rotten houses where windows are broken. Researchers discovered that if you leave it that way more and more windows are smashed. But if you renew broken windows sooner or later the smashing will stop and that part of the city will strive again. The same is true for your repository. Hitting on such a dirty spot may take the courage to rebuild but it will pay off!


A word on learning


Computer science is interesting, fascinating and exciting. What makes it so fascinating is the sheer speed of innovations. Everyday you can learn more.
If you start nowadays there is hardly a chance to learn it all. You will have to focus and to specialize. As a programmer you will most likely be familiar with OOP and design patterns as the basic toolset. You know at least one programming language and one script language. And you know that every new technology is somehow based on older ideas.
This is your chance! Don't loose the connection. Always be informed of what is happening in the field you have specialized in and read the news of what else is going on. Slowly broaden your knowledge. Plan regular learning time, write down topics or buzzwords you encounter and dig deeper. Learn new languages, new concepts and share your new (and old!) knowledge with others (team members, user groups, mailing lists...)

As there is a time to learn there also is a time to unlearn. You know the saying: old habits die hard. As time moves on so does technology including programming languages, frameworks and compiler optimizations. The things you have learned once formed a mental model that you keep applying even though it might be inappropriate nowadays. A good example is manual unrolling of loops to speed code up or very dense function calling by writing just one line and continue to call functions or methods handing over the (unseen) result of a function that gets called in the same line. This makes code reading hard and can introduce errors.
The paradigma changed: CPU time or memory usage are not the most expensive costs - but developer time. Sometimes it's hard to let go but when you learn something new maybe it's time to unlearn something old. Reflect your habits. Certainly don't forget what you have learned but be wise to choose the right (appropriate) approach. Maybe a new technology will save time, maybe even a lot of time.


Learning in your Team


Coding is a team effort and so is learning. There are always specialized team members and those who could benefit from their wisdom and experience. To have an effective team knowledge has to be spread. The will to learn and the will to share are signs of a good developer - and a great team-player.
The way to share knowledge should not be limited to questions when you run into a problem. Even though this might happen more than once a day there should be fixed dates when the whole team comes together for a small informal meeting (during lunchtime once or twice a week) and a small discussion takes place. Pick a theme and let the most specialized member prepare a short presentation or demo with a discussion session afterwards. Nothing that takes long - not even to prepare - no multimedia needed. Small and effective. The goal should be to gain everybody's interest and to bring the message across.
Themes can be new technologies (or updates on old ones), aspects of good programming (styles, OOP, patterns, etc.), new languages or rather seldom used features of the language in use, developer tools, scripting or go through a book chapter by chapter. This way you can level the knowledge in your team and even raise the level altogether which is really valuable. Still stay focused on the project. It will be best (and noticeable by management) if the project progress benefits from it, too.


Technologies


There are always new hypes and often they are nearly the same as some existing ideas plus the addition of a new way to translate this idea. And there are technologies that are proven and that the team is aware of. Quite often you will have to choose a certain technology and you should be aware of your choice. Don't be blind and adopt the hype just because everyone is talking about it. And don't choose the well known one just because you know it and it has proven to be the best.
Before you make a decision evaluate. Find out what you need, which one will fulfill your need best and base this on facts. (Believe is not a fact. ;-)) Introducing a technology that later has to be removed is really expensive and if you are responsible for that move you will probably risk your job. Look around for alternatives, ask your team-mates, compare and test them before you make your decision.
Questions to be asked: Does technology xyz solve my problem? Will I be tied to it? How much does it cost (TCO)?
Don't code what you can download!


Development Rhythm


It has proven to be a good solution to stick to a certain rhythm or schedule during development. There are times when you produce new code, times when you test and times when you maintain/review code. There are meetings and there are deadlines. All have to be orchestrated together and as you can see they all deal with time. A rhythm is constant - things appear at the same time over and over again. And you should stick to this rhythm. If the rhythm stops the project progress is in danger.
There is a technique called time boxing. For an activity there is a hard and fixed deadline which cannot be extended. You will have to finish within that time - no matter what. A time box is a short, finite period with a clear goal. If you encounter a problem which may result in a delay you are forced to make hard decisions. Maybe you will have to drop a feature. But you won't take longer.
This hard approach enforces rhythm and keeps the project moving. The goal is to split a task into small, manageable junks which will actually succeed. It would be ideal to code a small fraction each day, test the code, check it in and go home with no leftovers. This might include overtime but this should not happen constantly as it burns you out.
A team has to find it's rhythm. A period can vary from team to team and is often something between one week and one month.


The role of the customer


Developers design and create software. But software has to follow business rules. Without doubt no-one is better suited to make decisions in that direction like the customer. Therefore a very close working relationship has to be established. The customer should be on site. And this representative should be someone who can make decisions and who will actually work with the software later on. Whenever there are business-logic decisions to be made he has to be involved. There might be other topics and the team should establish a rule of which decisions the customer will have to make.
A journal of these decisions plus the reasons why they were made can help later on so it should be included in the work process. Also a glossary of business terminology should be established. Businesses have their own meaning of words that sound familiar. Such a glossary can be a wiki where every party has easy access to.

Two things to note:
1) It should be clear that each decision the customer makes affects the product and the customer will have to work with it later on. So the customer (representative) has to have the right knowledge and background. If you find out that the representative is from a totally different department or some-one who was available at that time but doesn't have a clue it is better to get back to the customer and explain the situation. You have to get reliable information. Redoing parts is expensive and will lead to frustration or even bad feelings on the customer's side. It is your job to guarantee that the information you get are valid and correct.
2) "I don't know" is a valid answer. Advise the customer as good as you can and plan to make changes at that part of code. What can help are prototypes. Strive to show them the way the software might work as often as possible. This is your chance to discover mistakes, misunderstandings or errors and correct them before any real coding is done.
The customer has to provide feedback as early as possible. Nothing is worse if he gets what he asked for and not what he wanted. Requirements are fluid, they evolve and change. If your customer sees a certain behaviour or feature in a prototype he might change his mind, come up with new ideas and improvements. Maybe you have to negotiate new features but the important thing is that you satisfy his needs. A short demo after each iteration is also useful - show him what you got so far and ask for feedback.


Is design dead?


Certainly not. You need to design software. What matters is the level of detail. You need directions. You need to discuss features beforehand and a possible ways to implement them. You need options. All these are there for you to come to a possible solution, the one with the least tradeoffs. It will be a structure that can be coded.
But the design should not be too detailed. It would consume time and mark developers as typists. We developers know our business as well and sometimes a bit more freedom can result in a better solution than that a designer might have thought of.
So how can you design a software system? There is strategic design beforehand that lays out the basic structure of the software - more a kind of a strategy, a starting point giving the right direction. Then there is tactical design which comes before coding time and is more implementation oriented. Here you talk about classes, their responsibilities and the collaborators (CRC card design for example).
Over time the design will evolve and it needs space to do so. It shows directions, accurate but not precise. It is an intend - not a recipe.
Eisenhower once said: "The plan is worthless. the planning is essential."


The repository


As you will definitely know the reason for a repository is collaborative working (not backup). Code in the repository is working and tested. To achieve this you have unit-tests or even a build system with automatic unit tests.
Think of the repository as code that can be released anytime!
The workflow to achieve this is to run your tests and make sure they all pass. Then check out the latest revision. Resolve possible conflicts, (clean) build and run your test again. If all pass check in.

If you have to refactor a large portion of code it might be wise to branch from the trunk and develop in isolation until your code runs again. But branches should be used wisely. Don't overdo it otherwise chaos might take over. The main branch (trunk) should be the standard place to introduce new features. If you would branch new features you run two risks: Development moves on and your code is getting incompatible over time. And your new classes' interfaces are hidden from your team mates. Therefore it is wise to integrate as early and as often as possible. You should work towards this. It has shown that early integration is easier to do than work for a long period on your own and then try to commit the whole changes. Many problems will arise that could have been prevented. Early integrations means that possible conflicts will show early, you can see how a subsystem reacts and address these issues. If you wait to long your changes can have such an impact on existing code that it might be getting difficult to catch and change all necessary code within time - or at all. A big-band integration can cause havoc.

The code in the repository should be ready to deploy. You should be able to check it out, build it and then have a running and fully functional application. To test your app under different environments and different machines you might want to automate deployment onto these machines. It is a good idea to automate as much as possible so that you gain a reliable and repeatable solution. This automation should be tested as well. If your app relies on certain external libraries or frameworks or any other prerequisites make sure you test the behaviour of the installer if those prerequisites are not present at install time.


Iterations


An iteration is a repetitive phase of analysis, design, implementation, testing and feedback. This has to be distinguished from incremental development which means that features and application functionality are developed in several small groups at a time. Each round builds on the result of the previous one.

As I said at the beginning what matters is time to market. To launch your product find the core features and implement them. Release your product, gain some feedback. From now on add new features in each iteration. Let the product evolve and keep releasing minor versions. This circle should be fast, release every month. Try to get your product to the customer as soon as possible. Apart from revenues you get feedback and feature requests. This can be important for your future decisions - this way you stay close to the market.
The opposite would be to plan a project over three years and then release a full featured version. First point: it will take four to five years in which many things will have changed, then you need plentiful of cash to keep developing for such a long time and there might be an established, perhaps better software on the market already which will be a burden for you to enter the market. Finally you could have developed for your own needs but not those of your customers.

Then there is a psychological factor as well. Humans want fast results. As developers we want them, too. Can you image how it feels to have a plan to release a software in four years from now? Possibly you keep coding for three years without seeing a functional product. This is not really motivating.
Thus develop in increments and use a short iterative circles. Release your app with minimal chunks of functionality (sometimes based on user feedback).


Unit tests


There are really great books on unit tests (see my book recommendations). There are many types of tests the most common will probably be the boundary conditions tests. Unit tests assure that your code performs it's task as it should be (and provide examples of code usage). Therefore you should write those tests with as much care as your code. I have seen tests that test one condition. I have broadened that test to test some more conditions and it failed at once. This shows that ill written tests are pure evil in that they assure developers that their code works when it doesn't.

But you should use unit test in another context as well. Never let a bug come up again! Once identified write a unit test in such a way that whenever the same problem arises (it would silently) that the alarm goes of. Never be caught twice on the same mistake.
Plus if you have to change code or even redesign at a bigger scale write unit tests and assure that they pass. Then make your changes and run those test again. If all went well they will pass.

Even though I don't use test driven design (TDD) it is a great idea in it's own way. Write tests before you code. Then you know your boundaries and you will have a solid check confirming that your code will meet its expectations.
What I like most about TDD is the fact that in order to test you have to come up with an usable object interface. This in general is a good idea. Design your classes in such a way that they can be tested. This is a good remedy for spaghetti coding.

Another plus is automated testing. You run your tests on your machine after each build - usually you let the build system (IDE) take care of that. As an addition to this you can have an installment of a continuous integration system that automatically checks out the latest revision after your commit, build and runs all tests and checks if everything is ok - otherwise you are notified. Best thing is to configure that system to run the tests on different machines with different environments - like different operating systems (and/or versions) you want to support, different architectures etc.


The user is always right


Even though you ran your product through all unit tests without them failing and checked if business logic is in accordance with the requirements this still doesn't guarantee that there are no bugs or flaws in your software. We are well aware of that.
But was is a bug? Besides from the usual meaning if a user encounters a problem he can't solve even though your app should be able to do, it's a bug. It can be a bug in the documentation leading the user the wrong way or a certain feature was implemented in a way the user doesn't understand (even though the manual correctly explains how to use that feature). As a user myself I once "suffered" from this (with 10+ years of computer experience): In an application you can save all currently open documents as a setting called workspace which also saves the order, appearance etc. Plus there is a menu item called "Save window sizes" but to my surprise the size isn't saved over new-starts. I contacted support and they helped me: I should use "Save workspace" instead to save window sizes for good.
So the "Save window sizes"-menu is misleading. I'm sure that many users are confused and some of them might even contact support like I did. So this should be considered a bug - even if the manual might correctly state how to do it right. Something like this should not be considered the user's problem - it's the team's problem. Such feedback is as (or even more) valuable as the feedback from unit tests. This is what takes your product ahead and your customers get the feeling you take them serious.
There is truth in every complaint and the real problem has to be fixed.


Coding


When you write code there are two sides of writing: that it compiles and does what it is supposed to do without errors and code that has to be read by you and your team-mates to be understood. Code maintenance is really import that's why your code should be easy to read and easy to understand. Code clarity is way more important today than performance considerations - especially with compilers that know how to optimize quiet well.
The days of dense coding should be over. I don't want to go into detail as there are many great books out there about good coding practices. There are patterns and anti-patterns to help you design your software and communicate your ideas. There is something like a notion - a kind of silent agreement - about how something should be done and how everybody would do this and expects it to be done.
But code clarity includes more: the use of meaningful, correct method and variable names plus the use of named constants and enums where appropriate. This not only helps code reading but shows your intent. And it helps to avoid errors. You should be able to use a method correctly without the need to read the documentation.

This way when you read code you understand what is happening and you wouldn't need any documentation at all - except for a short description of behaviour or noncode-issues. Avoid "noise" through unnecessary comments. Documentation in general is a problem. I got caught by outdated descriptions myself. I made changes and forgot to change the docu as well. This is bad as teammates will read the documentation first and get the wrong idea about what or how your class will do something.
So what should be in the documentation for a method? Certainly you'd like to start with a statement of its purpose (Why does this method exist?). Then what you expect as input and what are the post-conditions (object-state, return values, especially in the case of errors). Plus mentions what exceptions are thrown under what conditions.

Earlier I said that the most important thing is time-to-market. This should not mean to code as fast as possible, find the most simple way and throw your product on the market and let the user do the testing. For sure not. But as always there is a balance that should be kept.
If the design is too tight you might encounter really big problems in the future if you want to expand this feature. But then if the design to universal - rather academic instead of pragmatic - it might get to hard to understand and it might take to much time to implement. So if you think that your design should be open for the future and you use the best abstraction possible to achieve this, you will definitely be able to add those features later. But are you ever? Is that part of plan or is it just a possibility? Will you make a design harder to understand and to maintain plus spend more time to code and test without any benefit?
You see: to make the right decisions you have to know the trade-offs of each possibility and you have to have a plan. That is the pragmatic way. Don't overcomplicate things unless you are sure that you gain something from it later. Thus: Keep it simple.
The goal is simplicity. This doesn't mean simplistic or amateurish but chosen wisely - the pure essence of it. Elegant code is obvious in its clarity and utility. It's hard to create and means a lot of experience - plus you can't enforce it.
It is like a destillation process - you are finished when there is no line of code that you can take away without reducing features and there is no compromise at all. Remember: as compelling as patterns are there might be simpler solutions.

A big problem is: old habits die hard. A solution that was applied to a given kind of problem in the past a hundred times should always be re-evaluated to make sure it is still the best solution.
Part of this: "If you can download it don't code it." Many problems are the same and there might be solutions for them already out there on the net. Would you really write a database yourself? Even though you could and even though you might be able to make it the fastest available it will cost one hell of time and money.You will have to maintain it and it will never reach the same robustness and multitude of features of those that are on the market for so many years used by a million of users. This is an extreme example - you have to evaluate. What counts is time-to-market.

God-Classes


There is an anti-pattern called God-Classes. These are classes which can do a lot of things and which hate delegation. (Side-note: I noticed - and this is still under investigation - that sometimes the spirit of a programmer is reflected in the way his classes behave or are conceived. Developers that don't like to loose control write classes that don't like to delegate. Well, you get the picture. Anyone in with me?)
Each class should have one exact purpose. Every method of a class should contribute to this purpose. That is cohesion. Maybe you heard: "One class should have only one reason to change." Or The Single Responsibility Principle. What you gain from this is easier reuse and clarification. Both worthwhile a delegate. Still it should not be atomic. With some experience you will see where the borders are. But it is a clear indication that when you have ro replicate code to be used in different classes (copy and paste is easy) that this task could be a separate class...

Encapsulation


You know this principle. Good OO-practice. One step further is the segration of one's object methods into commands and queries. A query just queries an object about its state without changing it. You will declare those methods as const in C++.
A command on the other hand will likely change the state of an object and might thus provide information (parameters). In the most simple form think of a setter as a command and a getter as a query.
So why the fuss? Well, if you use a getter to get an instance variable of an object, you as the caller may not change it. It is clearly the responsibility of the object to implement any necessary changes. That's encapsulation. Tell the owner what to do and stick to your own job ("Tell, don't ask").

See methods as contracts


If you implement a method you promise a certain thing to happen. This can be seen as a contract. If you design a class hierarchy all subclass which override methods of the base class must always full this contract. This means that subclasses require no more and promise no less than the base class' methods.
A word on inheritance: Inheritance is the well known is-a-relation. That means that classes in the inheritance hierarchy share a common-to-all idea. They naturally belong together. If you find yourself making a subclass of a base class just to reuse some code without that subclass fitting into the described idea than it is time to reflect the design. Just because it is handy and avoids code duplication it is not right. Think of a base class Clock which has subclasses that show time in different manners like Watch, Alarm-Clock, Stopp Watch etc. Now you need the current time for your VCR. Will you make a VCR a subclass of a Clock? Is a VCR a Clock? No, it uses a clock - or has a clock.
So a VCR has a member of type Clock. Such has-a or uses-a-relations are called delegates are often the preferred solution to inheritance because they are more flexible and reusable.

Debugging - Error chasing and squishing bugs


It is nearly impossible to develop error-free software (other than "Hello world") and it is every developer's effort to grab as many errors as possible before release. To control program flow you will usually use a debugger to see if your code behaves as expected. But there also is one step before that: the compiler. It will emit warnings to let you know of possible errors. The more dynamic a language is the more complicated it is for a compiler to catch any possible mistakes but nowadays they really do a great job. Treat those warnings as errors.
If for example an Objective-C compiler tells you that a method is unknown - due to the dynamism of the language it will not treat this as an error - take a closer look. Maybe you have forgotten to declare that methods or import a header file. Or maybe that method might not exist so your program will happy crash when trying to call that method.
Your goal should be that an app compiles without any errors and without any warnings and passes all unit test. This is a prerequisite to even think about debugging.

Every framework/language has its gottachs and pitfalls and sometimes it can be time-consuming to find a solution. You will do a lot of research and thinking and finally come up with an idea of what when wrong and how to remedy it. Then there are two thing to do: 1) fix the problem and 2) write down what the problem was and how you fixed it. Every team should have a wiki (or comparable solution) to keep record of the newly gained knowledge. It should be easily searchable so that you can start there if you have a problem. The more details are provided in the descriptions the better of are you team-mates to understand your solution. Also include references (URLs) to articles you found that might help and add code segments to clarify things. After a while this wiki will get really precious especially for newcomers. Another benefit: How often did you have the feeling that you hit this problem before and you can't remember how you fixed it? It might be more than a year back and way out of memory. Now you can look it up and you will never get burned twice.

There are errors that occur during runtime that depend on user input or availability of resources. Such errors are usually treated (surrounded) by exceptions (handlers). Sometimes your app can handle an exception and execution can continue. And there are times when you can't handle them -then re-throw them. The worst thing to do is to silently ignore them. The user of your classes has to be informed if something went wrong. Just returning 0 or nil will not suffice - use an exception if it is more than an error, something exceptional, a real failure. An exception also is an object that can hold information of what went wrong and where. Maybe the calling class can handle it. The last object in this chain is the NSUncaughtExceptionHandler (in Objective-C) that you can set inorder to catch your app's exceptions that no other object could handle. Inform the user of what went wrong and quit the application. There has to be a clear way of program flow which is binary: if things go well take that road, if they go wrong, take the other road. If it is unrecoverable you have to quit otherwise your app might corrupt data. But let the user know about it.

Error messages should always be understandable for ("in the language of") quit the user. Apple gives examples of how they should be designed. Make them meaningful and give the user advice as how to recover from an error (if possible). Don't just tell them that something went the bad way but tell them what was the (probable) cause and how to avoid this situation or what to do next. If your app is capable of recovering from an error and just needs an decision ask the user.
Exceptions or unrecoverable errors might be programming mistakes. As a developer you are longing for that information. Thus you need to provide it. I have seen extra apps with their sole reason for existence being to mail a bug report of a crashing (main) app with stack traces, machine information and a user description of what he did. This is luxury but anything that gets near that will help you to make you app better.

Collaboration


The team. It's the most important thing in the developer's world. Software is always a team effort. So what can you do to enhance team collaboration?
One obvious goal is to let everybody know what you're working on. That way everybody knows what everybody is doing. A regular meeting, maybe after coffee in the morning, will provide that information: Plan it as a stand-up meeting (nothing cozy here!) where each team member will give a short statement about what he did yesterday and what he will do today what obstacles are in his way (maybe someone can help him there...). Not much more than 2 minutes - just a brief report. Benefits? You know what others are doing, maybe you can help somebody because you know the solution to his problem and can share your ideas, you can search for help yourself, you can identify redundant work and it motivates you to see the overall progress of the project.

The focus of your team should always be on solutions, on the project itself and the finishing of the product. Time to market! Personal fights lead to frustration and de-motivation. Keep that in mind if you address someone (or are addressed by someone) with a problem. We all together develop on the same project. This also means that code is shared. As said before only check in code that compiles without warnings and that passes all unit tests. Shared code means that many developers look at the same code which is good - that way errors can be caught and improvements inserted (no hacks!). And you will code more disciplined because you know that others will be looking at your code. This all can be enforced by rotating developers across different modules. So sooner or later everybody could work on every module which is shared knowledge and a good thing. If someone gets ill this will not effect project progress.

In Extreme Programming (XP) there is the concept of Pair Programming, the principle of two developers sitting infront of one computer revolving the roles of typer and navigator. The idea is constant code review. Code review should be an integral part of the development process. The goal is to catch any possible errors, to refactor code, to make it more readable and easier to maintain and to catch code duplication. All in all a good thing but it has to be done. There are some ideas out there as to when to review code but something that might work easily is to review code after each task. The reviewer must not be the writer of the code for obvious reasons. After you finished a review let everyone know what and why you changed it (by using comments for example).

Speaking of team effort: Usually a team is mixed with developers which are highly experienced and newcomers. It is always good to share your knowledge. Care about newcomers and enjoy to see them develop their skills. This is different from playing "Being God" which will be frustrating to those who want to learn. Teach in a motivating way, be a guide and you will also gain from this. This will also level the team and make development easier.
Techniques that have proven to be adequate is to show people how to solve a problem instead of simply providing a solution. You know the saying: "Give the starving a fish and he will live another day. Teach them how to fish and he will survive.".

Another thing I find worth mentioning is information flow. Always keep others informed of your status and your ideas. If there is a delay or problem tell or post it. Chances are high that someone can help you. In a good team you know what the others are doing and you also know when someone is on vacation etc. This minimizes surprises and helps to build trust in the team members.

Conclusion


All in all Agile Development provides many ideas - not all of them might be realized at once or at all. But is always good to know about alternatives. For me these methods are of high value and often good solutions to aching problems.

MadeOnMac