Reuse vs. maintainability and ease of testing - reusability

Everyone likes to talk about reusability. Where I work, whenever some new idea is being tossed around or tested out, the question of reusability always comes up. "We want to maximize our investment in this, let's make it reusable." "Reusability will bring higher quality with less work." And so on and so on.
What I've found is that when a reusable component or idea is introduced, everyone is immediately afraid of it and writes it off as a bad idea. Once applications become dependent on it, they say, it won't be maintainable, and any changes will result in the need to do regression testing on everything that uses it. People here point to one component in particular that has been around a long time and has a whole lot of dependents and grouse that it's become impossible to change becuase we don't know what the changes will break.
My responses to this complaint are:
It's good that change to a component
that has many dependents is slow,
because it forces the designers to
really think through the changes.
Time should be taken to get the
component right in the first place. Corrollary: If you're finding the need to change it all the time, it was never very reusable to begin with, was it?
Software development is hard and requires work. So does testing. You just gotta do it.
Unfortunately, what people hear in these responses are "slow," "time" and "effort."
I would love if there was a magic "make this reusable" switch I could flip on things I build so as to win brownie points from management, but things don't work that way. Making something reusable takes time and effort and you're still not guaranteed to get it right.
How do you deal with the request for "reusability" when delivering on it seems to bring nothing but complaints?

Reusability is only worthwhile if something will actually be reused. Make sure you have some practical reuse cases before you write something reusable.
Even if a reusable library is 10x harder to maintain than an ad-hoc version of itself, you're still saving on maintenance overall if the reusable library is used in place of ad-hoc versions in 10 different places.

Reusability is to make code reusable in term of similar behavior or "IS_A" relationship. If you just want to reuse code block by seeing them using again and again but they have no similar characteristic, you should better leave them alone to be loosely coupling. By that, we can have more flexibility to modify later.

One thing that we often do is to use versions and avoid the constant retesting. Just because there is a new version of common code doesn't mean everything has to use the new version right away. When something is getting updated for other reasons, update to the new version of the common code.

Related

Interface Builder (XIB) or Code when merging in a team environment?

Merging interface builder files with others (and even myself from a different computer) can be a real challenge. The XIB xml is certainly better than NIBs but even as xml, I've found cases where merging and getting a consistent and valid XIB was harder than just taking the other and manually redoing the changes made.
I'm wondering what other folks are doing who have multiple folks who can potentially collide on XIBs.
Was merging a consideration for going all code? Do you use XIBs just for layout and code the rest? Or, have you had any luck merging XIBs and over time you just get better at manually reading?
EDIT: My current approach is using it for strict layout (what it's really good at and painful to code) and setting all the options and data via code. I find code much easier to merge but laying out controls in code is tedious. Thoughts?
Was merging a consideration for going all code?
Yes, No, and "Portions Of". It depends on things like:
The people involved
the complexity of the UI
the quality of the implementation you need.
the expected lifetime of the implementation
But yes, it has been, and it often is when the case is just not trivial -- Otherwise, you just fight it by decomposing XIBs into smaller pieces. That can work pretty well (or not), depending on what you are faced with.
Do you use XIBs just for layout and code the rest?
Depends on a lot of things.
XIB-only has its restrictions, and is much like code duplication. I use it at times for prototyping, other times because that's what somebody else favored.
"A little of both" can require a lot of glue. At times, it can be pretty disorganized -- e.g. "where's that action really set?". Of course, this can also be used to achieve what some would consider a good balance of XIB and programmatic separation. The simpler the XIB is, the less often it will need to be adjusted, and less likely it will cause merge conflicts.
Code-only is my preference, but there are people who just prefer WYSIWYG, and people aren't very familiar writing UIs programmatically. As well, if quality, reusability, and maintainability not requirements (e.g. bang out a prototype), then code-only can be overkill.
Or, have you had any luck merging XIBs and over time you just get better at manually reading?
No real luck -- just by breaking them into smaller components. Unfortunately, the "Decompose Interface" option (from IB3) is not available in Xc4's editor.
I have found that IB is better for layout as you mention, but probably that's just me cause I was raised this way.Plus code is way more re-usable than layouts.
As far as I'm concerned during the runtime both act the same though I'm not 100% sure about that. Prototypes are less painful in IB than in code, I know that for sure and clients will not take any value on you prototyping in code.
What I do is don't bother trying to merge, just accepts the branch version completely or you version. It means you have to be a bit disciplined about who get to change the interface code, and on commits and updates, in practice we haven't found it a problem but I guess it depends on your environment.
Don't use this as an excuse to stop using interface builder, there is nothing worse than trying to dig through someone else's code to find a button so you can work out what happens when a use clicks it.
Without Interface Builder you are not respecting the MVC separation.

UI First or logic first?

While working on projects, I often come to the dilemma of working on UI first or on logic first. Having UI first gives a nice overview of how the end product is going to look like whilehaving logic first uncovers any possible roadblocks in technology.
However, it is not always that crystal clear.. some times UI may need data to be populated to really show what it means and simulating the data could be more difficult than inplementing the logic.. what is your preferred approach for development and why? Which is more efficient and effective?
( I am seeing this issue more and more with iphone projects)
Neither.
You will have to so some thinking at the beginning of the project anyway, deciding the general approach you will take and what operations you will support.
Do that reasonably well and you will have defined the interface between the view and the underlying logic. Look at the Model-View-Controller approach for some inspiration.
What you want to have early on is an idea of what are the basic operations your logic code needs to do to in order to achieve a purpose. Usually it will be a simple function call but sometimes it may involve more than that. Have that clear first.
Next, a complex system that works is based on a simple system that works.
Which means you will need to have a basic UI you'll use to test a basic logic implementation first.
A simple form with a button which presents a message is basic enough. Then, it can grow, you implement a piece of functionality and then you add a simple UI you can test it with.
It is easier to do both piece by piece as the logic and UI for a small piece of the logic are conceptually similar and it will be easy to keep track of both while you implement and test.
The most important part is to keep the UI and logic decoupled, making them talk through a common interface. This will allow you to make quick edits when needed and improve the looks of the GUI towards the end.
You will be better able to just scrap the UI if you don't like it. All you'll need to do is use the same interface, one which you know how to do because you wrote it and you already implemented it.
If at some point you realize you've made a big mistake you can still salvage parts of the code, again because the UI and logic are decoupled and, hopefully, the logic part is also modular enough.
In short: think first, do both the UI and the logic in small increments and keep things modular.
Iterate between both (logic and UI). Back and forth. The UI may change as you understand how and what you can do with the logic and whatever constraints that may present. The logic may change as you change the features, behavior, or performance requirements of an easy-to-use, responsive, and decent looking UI.
I usually do the minimum possible of each until I have some barely working mockups. Then I use each mockup to test where my assumptions about the proper UI and/or logic might be right or wrong. Pick the most flawed, and start iterating.
Apple suggests mocking up the UI on paper first. (Have an eraser handy...)
If possible, in parallel.
But personally, I advocate logic first.
I start with the fundamentals first and that means getting the logic coded and working first. There are two reasons for this:
If I can't get the logic working correctly having a pretty UI is useless and a waste of my time
You will most likely change the UI when you work on the logic aspect making the UI process longer and more expensive
I usually get my UI in order first. The reason? As I prototype different designs, sometimes my idea for the app changes. If it does, then it's no consequence - there is no code to rewrite.
However, sometimes it is helpful to get the fundamentals first in order to determine if the app is going to work or not. If it's not going to function, then why waste time making interfaces?
I like to start by laying out the different parts of my project in something like Vizio.
I make boxes for the different views I expect to have, and I fill them with the information I expect them to contain.
I make another set of boxes for my expected model objects (logic). I fill them with the information I expect they will work with, and I draw lines between models and views where I think it will be necessary.
I do the same thing for object graphs (if I plan on using CoreData), and for database tables if I am going to have an external database.
Laying everything out visually helps me decide if I am missing any important features or interactions between project components. It also gives me something to quickly refer to if I later lose track of what I was doing.
From that point, I tend to work on a model until it has enough done to fill out part of a view, then I work on a view until it can interact with the model.
I also try to identify views or models that could be reused for multiple purposes so that I can reduce the overall amount of work I have to do.
Take the agile approach and work on small amounts of both in iterations. Slowly building each functional piece of the program so as to not build any monolithic piece at once.

I'm rewriting my code around 10 times before finishing. Is this wrong?

When i start writing something complex, I find that restart the writing like 10 times before I end up with what I want, often discarding hundreds of lines of code.
Am I doing something wrong, or do others have workflows like this?
EDIT: Right now, I'm working on a modular compiler. The last project I was working on was a server in java. Before that it was some concurrency stuff.
I do a fair bit of planning, and I never start coding before I've got interfaces for everything.
Given that, is it normal to just wipe the slate clean repeatedly?
Discarding many lines of code is usually a positive aspect of refactoring. That's great. But starting over ten times means that you probably haven't analyzed your problem and solution. It's fine to backtrack and sometimes to start over but not that often. You should lay out your code in such a way that when you backtrack and refactor, you keep most of what you created because it will exist in nicely isolated and logical chunks. (Using vague language since language of choice wasn't specified.)
From author's comment:
Usually I restart because I get
confused by all the stuff going on in
my code.
Study your craft and make good use of design patterns and other best programming philosophies to lend your code a well-defined structure... something you'll recognize months and even days down the road.
If you're starting something complex, a little planning before you start writing would seem to be a good idea.
Design first.
Perfectly normal. No matter how much I plan ahead, I very often have an "Aha!" moment once the hands hit the keyboard.
Just as often it's a "What the heck was I thinking?" moment.
It's all good. You're making better code.
All the suggestions here are valid, however, remember that there's a moment in a programs lifetime that is "good enough". It's easy to fall into a trap of never ending refactoring, just because you see that "yes, this could be done better!". Well, face the truth -- unless your program has just a few lines, there's ALWAYS a way to do it better.
I believe there are happy programmers out there that don't suffer from that, but at least I need to keep reminding myself that there's a line that's called "good enough".
And it's especially true if you're writing code for someone else -- nobody will note that you did something "nicer", all that counts is "does it work well?".
Also, a VERY GOOD practice is at least to get it to WORK before rewriting. Then you can always fall back to a working previous solution.
(since 12 years I'm constantly rewriting a game I'm writing, and I'm nowhere near the end...)
On a complex problem, this is common. If you aren't totally stabbing in the dark, it really helps to sketch out our ideas first, but then again you're just moving the 'retries' from code to paper.
If it helps you get to a good solution, how can it be wrong?
It depends on how well I know the problem space. If it is familiar territory, then I'd be worried if it took 10 iterations. If it is unfamiliar territory, then it might take as many as 10 iterations, but at least some of them would be reduced to prototype - or an attempt at a prototype - before being discarded.
If you are learning something with each iteration then there probably isnt a problem. Deadlines and pesky things like that might make your life a little more difficult. :)
When I am working on a new problem I like to pseudocode it out in comments in the actual function handler, as part of generating the stub for my TDD. Then add the code in to each step I had in the comments of the function body.
It helps me to keep focused on what the problem that I am solving is, and not get lost in the details to early.
The single biggest change you can do to help yourself would be to plan your code first. On paper.
Your plan doesn't have to be super in-depth (although sometimes that's good too). Just sketch out a rough idea of what you want your program to do. Jot down the key functionality points. "I want it to do this, this and this".
Once you have that, sketch out a rough design. Classes, methods, functions, objects. Give it a little form. Do a rough allocation of functionality to various portions of your design.
Depending on the nature of the project, I might take a rough design such as that and turn it into a much more detailed design. If it's a small project, maybe not. But no matter the projected complexity, time spent designing will reward you with better code, and less time spent coding. If you have obvious mistakes that require you to refactor large portions of your program, they should be apparent in your initial design and you can adjust it. You won't have wasted hundreds of lines of code on an obvious mistake.
Compilers are very complex applications, and you can't write an optimizing compiler from start to finish in one pass - no matter how much thought you put into it at first. Usually you attempt to get something to work correctly from start to finish and then go back to modularizing it and adding new features like optimizations. This process means lots of refactoring and replacing whole sections outright. This is also part of the learning processes - as no one can know everything and remember it!
(I'm also working on a .NET compiler as part of the MOSA project - www.mosa-projet.org.)
solve your problem on paper . . . dont be in such a rush to type.
There are two situations. (1) I've been able to confidently plan ahead and isolated my abstractions. (2) I haven't.
For (1), an effective technique is to put in dummy versions of certain classes or functions just to drive the rest of the code. (or conversely, to write said classes and functions and drive them with a test script.) This allows you to tackle only part of the complexity in each pass.
As much as everyone says people should plan in advance, it often doesn't work that way, resulting in situation (2). Here, be careful to manage what you are trying to accomplish in one iteration of code. As soon as you find your brain unable to juggle all the things you are doing, scale back your ambition for what you want to achieve before the next compile-and-test. Allow your code to be flawed but easy-to-write on the first pass, and then develop it through refactoring. This improves efficiency over repeatedly wiping the slate clean.
For example, one way I used to get into messes was by sniffing out common code and refactoring into subroutines too early, before I really knew the shape of the code. I've since started allowing myself to duplicate code on the first pass, and then going back and factoring it into subroutines later. It has helped tremendously.
It's called refactoring buddy and it's good, you just need to limit it so you won't end up wasting all your time refactoring code you have and is working instead of writing new code.
Some of the reasons why one must refactor are:
Enhancing performance.
Organizing code.
You need to write your code in a different way to get something to work.
To do something in a different way because it saves a lot of work (i.e.: Using MXML instead of ActionScript).
You used the wrong name for a variable.
Consider learning some framework in whatever language you're using (or in any language for that matter).
I think that learning frameworks made my code a million times better. By learning the frameworks (and more importantly how they work) I learned not just design patterns, but how to implement them realistically.
Consider looking at rails, cakephp, or django (assuming you're in a scripting language; I don't know any desktop language frameworks. Sorry!). Then see how their pieces fit together.

Getting your head around other people's code

I'm occasionally unfortunate enough to have to make alterations to very old, poorly not documented and poorly not designed code.
It often takes a long time to make a simple change because there is not much structure to the existing code and I really have to read a lot of code before I have a feel for where things would be.
What I think would help a lot in cases like this is a tool that would allow one to visualise an overview of the code, and then maybe even drill down for more detail. I suspect such a tool would be very hard to get right, given that is trying to find structure where there is little or none.
I guess this is not really a question, but rather a musing. I should make it into a question - What do others do to assist in getting their head around other peoples code, the good and the bad?
Hmm, this is a hard one, so much to say so little time ...
1) If you can run the code it makes life soooo much easier, breakpoints (especially conditional) break points are you friend.
2) A purists' approach would be to write a few unit tests, for known functionality, then refactor to improve code and understanding, then re-test. If things break, then create more unit tests - repeat until bored/old/moved to new project
3) ReSharper is good at showing where things are being used, what's calling a method for instance, it's static but a good start, and it helps with refactoring.
4) Many .net events are coded as public, and events can be a pain to debug at the best of times. Recode them to be private and use a property with add/remove. You can then use break point to see what is listening on an event.
BTW - I'm playing in the .Net space, and would love a tool to help do this kind of stuff, like Joel does anyone out there know of a good dynamic code reviewing tool?
I have been asked to take ownership of some NASTY code in the past - both work and "play".
Most of the amateurs I took over code for had just sort of evolved the code to do what they needed over several iterations. It was always a giant incestuous mess of library A calling B, calling back into A, calling C, calling B, etc. A lot of the time they'd use threads and not a critical section was to be seen.
I found the best/only way to get a handle on the code was start at the OS entry point [main()] and build my own call stack diagram showing the call tree. You don't really need to build a full tree at the outset. Just trace through the section(s) you're working on at each stage and you'll get a good enough handle on things to be able to run with it.
To top it all off, use the biggest slice of dead tree you can find and a pen. Laying it all out in front of you so you don't have to jump back and forward on screens or pages makes life so much simpler.
EDIT: There's a lot of talk about coding standards... they will just make poor code look consistent with good code (and usually be harder to spot). Coding standards don't always make maintaining code easier.
I do this on a regular basis. And have developed some tools and tricks.
Try to get a general overview (object diagram or other).
Document your findings.
Test your assumptions (especially for vague code).
The problem with this is that on most companies you are appreciated by result. That's why some programmers write poor code fast and move on to a different project. So you are left with the garbage, and your boss compares your sluggish progress with the quick and dirtu guy. (Luckily my current employer is different).
I generally use UML sequence diagrams of various key ways that the component is used. I don't know of any tools that can generate them automatically, but many UML tools such as BoUML and EA Sparx can create classes/operations from source code which saves some typing.
The definitive text on this situation is Michael Feathers' Working Effectively with Legacy Code. As S. Lott says get some unit tests in to establish behaviour of the lagacy code. Once you have those in you can begin to refactor. There seems to be a sample chapter available on the Object Mentor website.
I strongly recommend BOUML. It's a free UML modelling tool, which:
is extremely fast (fastest UML tool ever created, check out benchmarks),
has rock solid C++ import support,
has great SVG export support, which is important, because viewing large graphs in vector format, which scales fast in e.g. Firefox, is very convenient (you can quickly switch between "birds eye" view and class detail view),
is full featured, intensively developed (look at development history, it's hard to believe that so fast progress is possible).
So: import your code into BOUML and view it there, or export to SVG and view it in Firefox.
See Unit Testing Legacy ASP.NET Webforms Applications for advice on getting a grip on legacy apps via unit testing.
There are many similar questions and answers. Here's the search https://stackoverflow.com/search?q=unit+test+legacy
The point is that getting your head around legacy is probably easiest if you are writing unit tests for that legacy.
I haven't had great luck with tools to automate the review of poorly documented/executed code, cause a confusing/badly designed program generally translates to a less than useful model. It's not exciting or immediately rewarding, but I've had the best results with picking a spot and following the program execution line by line, documenting and adding comments as I go, and refactoring where applicable.
a good IDE (EMACS or Eclipse) could help in many cases. Also on a UNIX-platform, there are some tools for crossreferencing (etags, ctags) or checking (lint) or gcc with many many warning options turned on.
First, before trying to comprehend a function/method, i would refactor it a bit to fit your coding conventions (spaces, braces, indentation) and remove most of the comments if they seem to be wrong.
Then I would refactor and comment the parts you understood, and try to find/grep those parts over the whole source tree and refactor them there also.
Over the time, you get a nicer code, you like to work with.
I personally do a lot of drawing of diagrams, and figuring out the bones of the structure.
The fad de jour (and possibly quite rightly) has got me writing unit tests to test my assertions, and build up a safety net for changes I make to the system.
Once I get to a point where I'm comfortable enought knowing what the system does, I'll take a stab at fixing bugs in the sanest way possible, and hope my safety nets neared completion.
That's just me, however. ;)
i have actuaally been using the refactoring features of ReSharper to help m get a handle on a bunch of projects that i inherited recently. So, to figure out another programmer's very poorly structured, undocumented code, i actually start by refactoring it.
Cleaning up the code, renaming methods, classes and namespaces properly, extracting methods are all structural changes that can shed light on what a piece of code is supposed to do. It might sound counterintuitive to refactor code that you don't "know" but trut me, ReSharper really allows you to do this. Take for example the issue of red herring dead code. You see a method in a class or perhaps a strangely named variable. You can start by trying to lookup usages or, ungh, do a text search, but ReSharper will actually detect dead code and color it gray. As soon as you open a file you see in gray and with scroll bar flags what would have in the past been confusing red herrings.
There are dozens of other tricks and probably a number of other tools that can do similar things but i am a ReSharper junky.
Cheers.
Get to know the software intimately from a user's point of view. A lot can be learnt about the underlying structure by studying and interacting with the user interface(s).
Printouts
Whiteboards
Lots of notepaper
Lots of Starbucks
Being able to scribble all over the poor thing is the most useful method for me. Usually I turn up a lot of "huh, that's funny..." while trying to make basic code structure diagrams that turns out to be more useful than the diagrams themselves in the end. Automated tools are probably more helpful than I give them credit for, but the value of finding those funny bits exceeds the value of rapidly generated diagrams for me.
For diagrams, I look for mostly where the data is going. Where does it come in, where does it end up, and what does it go through on the way. Generally what happens to the data seems to give a good impression of the overall layout, and some bones to come back to if I'm rewriting.
When I'm working on legacy code, I don't attempt to understand the entire system. That would result in complexity overload and subsequent brain explosion.
Rather, I take one single feature of the system and try to understand completely how it works, from end to end. I will generally debug into the code, starting from the point in the UI code where I can find the specific functionality (since this is usually the only thing I'll be able to find at first). Then I will perform some action in the GUI, and drill down in the code all the way down into the database and then back up. This usually results in a complete understanding of at least one feature of the system, and sometimes gives insight into other parts of the system as well.
Once I understand what functions are being called and what stored procedures, tables, and views are involved, I then do a search through the code to find out what other parts of the application rely on these same functions/procs. This is how I find out if a change I'm going to make will break anything else in the system.
It can also sometimes be useful to attempt to make diagrams of the database and/or code structure, but sometimes it's just so bad or so insanely complex that it's better to ignore the system as a whole and just focus on the part that you need to change.
My big problem is that I (currently) have very large systems to understand in a fairly short space of time (I pity contract developers on this point) and don't have a lot of experience doing this (having previously been fortunate enough to be the one designing from the ground up.)
One method I use is to try to understand the meaning of the naming of variables, methods, classes, etc. This is useful because it (hopefully increasingly) embeds a high-level view of a train of thought from an atomic level.
I say this because typically developers will name their elements (with what they believe are) meaningfully and providing insight into their intended function. This is flawed, admittedly, if the developer has a defective understanding of their program, the terminology or (often the case, imho) is trying to sound clever. How many developers have seen keywords or class names and only then looked up the term in the dictionary, for the first time?
It's all about the standards and coding rules your company is using.
if everyone codes in different style, then it's hard to maintain other programmer code and etc, if you decide what standard you'll use have some rules, everything will be fine :) Note: that you don't have to make a lot of rules, because people should have possibility to code in style they like, otherwise you can be very surprised.

How important is it to write functional specs? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 10 months ago.
Improve this question
I've never written functional specs, I prefer to jump into the code and design things as I go. So far its worked fine, but for a recent personal project I'm writing out some specs which describe all the features of the product, and how it should 'work' without going into details of how it will be implemented, and I'm finding it very valuable.
What are your thoughts, do you write specs or do you just start coding and plan as you go, and which practice is better?
If you're driving from your home to the nearest grocery store, you probably don't need a map. But...
If you're driving to a place you've never been before in another state, you probably do.
If you're driving around at random for the fun of driving, you probably don't need a map. But...
If you're trying to get somewhere in the most effective fashion (minimize distance, minimize time, make three specific stops along the way, etc.) you probably do.
If you're driving by yourself and can take as long as you like, stopping any time you see something interesting or to reconsider your destination or route, you may not need a map. But...
If you're driving as part of a convoy, and all need to make food and overnight lodging stops together, and need to arrive together, you probably do.
If you think I'm not talking about programming, you probably don't need a functional spec, story cards, narrative, CRCs, etc. But...
If you think I am, you might want to consider at least one of the above.
;-)
For someone who "jumps into the code" and "design[s] as they go", I would say writing anything including a functional spec is better than your current methods. A great deal of time and effort can be saved if you take the time to think it through and design it before you even start.
Requirements help define what you need to make.
Design helps define what you are planning on making.
User Documentation defines what you did make.
You'll find that most places will have some variation of these three documents. The functional spec can be lumped into the design document.
I'd recommend reading Rapid Development if you're not convinced. You truely can get work done faster if you take more time to plan and design.
Jumping "straight to code" for large software projects would almost surely lead to failure (as immediatley starting posing bricks to build a bridge would).
The guys at 37 Signals would say that is better to write a short document on paper than writing a complex spec. I'd say that this could be true for mocking up quickly new websites (where the design and the idea could lead better than a rigid schema), but not always acceptable in other real life situations.
Just think of the (legal, even) importance a spec document signed by your customer can have.
The morale probably is: be flexible, and plan with functional or technical specs as much as you need, according to your project's scenario.
For one-off hacks and small utilities, don't bother.
But if you're writing a serious, large application, and have demanding customers and has to run for a long time, it's a MUST. Read Joel's great articles on the subject - they're a good start.
I do it both ways, but I've learned something from Test Driven Development...
If you go into coding with a roadmap you will get to the end of the trip a helluva lot faster than you will if you just start walking down the road without having any idea of how it is going to fork in the middle.
You don't have to write down every detail of what every function is going to do, but define you basics so that way you know what you should get done to make everything work well together.
All that being said, I needed to write a series of exception handlers yesterday and I just dove right in without trying to architect it out at all. Maybe I should reread my own advice ;)
What a lot of people don't want to admit or realize is that software development is an engineering discipline. A lot can be learned as to how they approach things. Mapping out what your going to do in an application isn't necessarily vital on small projects as it is normally easier to quickly go back and fix your mistakes. You don't see how much time is wasted compared to writing down what the system is going to do first.
In reality in large projects its almost necessary to have road map of how the system works and what it does. Call it a Functional Spec if you will, but normally you have to have something that can show you why step b follows step a. We all think we can think it up on the fly (I am definitely guilty of this too), but in reality it causes us problems. Think back and ask yourself how many times you encountered something and said to yourself "Man I wish I would have thought of that earlier?" Or someone else see's what you've done, and showed you that you could have take 3 steps to accomplish a task where you took 10.
Putting it down on paper really forces you to think about what your going to do. Once it's on paper it's not a nebulous thought anymore and then you can look at it and evaluate if what you were thinking really makes sense. Changing a one page document is easier than changing 5000 lines of code.
If you are working in an XP (or similar) environment, you'll use stories to guide development along with lots of unit and hallway useability testing (I've drunk the Kool-Aid, I guess).
However, there is one area where a spec is absolutely required: when coordinating with an external team. I had a project with a large insurance company where we needed to have an agreement on certain program behaviors, some aspects of database design and a number of file layouts. Without the spec, I was wide open to a creative interpretation of what we had promised. These were good people - I trusted them and liked working with them. But still, without that spec it would have been a death march. With the spec, I could always point out where they had deviated from the agreed-to layout or where they were asking for additional custom work ($$!). If working with a semi-antagonistic relationship, the spec can save you from even worse: a lawsuit.
Oh yes, and I agree with Kieveli: "jumping right to code" is almost never a good idea.
I would say it totally "depends" on the type of problem. I tend to ask myself am I writing it for the sake of it or for the layers above you. I also had debated this and my personal experience says, you should since it keeps the project on track with the expectations (rather than going off course).
I like to decompose any non trivial problems loosely on paper first, rather than jumping in to code, for a number of reasons;
The stuff i write on paper doesn't have to compile or make any sense to a computer
I can work at arbitrary levels of abstraction on paper
I can add pictures and diagrams really easily
I can think through and debug a concept very quickly
If the problem I'm dealing with is likely to involve either a significant amount of time, or a number of other people, I'll write it up as an outline functional spec. If I'm being paid by someone else to develop the software, and there is any potential for ambiguity, I will add enough extra detail to remove this ambiguity. I also like to use this documentation as a starting point for developing automated test cases, once the software has been written.
Put another way, I write enough of a functional specification to properly understand the software I am writing myself, and to resolve any possibile ambiguities for anyone else involved.
I rarely feel the need for a functional spec. OTOH I always have the user responsible for the feature a phone call away, so I can always query them for functional requirements as I go.
To me a functional spec is more of a political tool than technical. I guess once you have a spec you can always blame the spec if you later discover problems with the implementation. But who to blame is really of no interest to me, the problem will still be there even if you find a scapegoat, better then to revisit the implementation and try to do it right.
It's virtually impossible to write a good spec, because you really don't know enough of either the problem or the tools or future changes in the environment to do it right.
Thus I think it's much more important to adapt an agile approach to development and dedicate enough resources and time to revisit and refactor as you go.
It's important not to write them: There's Nothing Functional about a Functional Spec