Which approach is better when working with a source control software like TFS or VSS? I have experienced different approaches and I can't tell which one is better. Should we let developers decide upon it? Or should a team has a unique strategy for check-in check-out operations?
Commit early, commit often so that you don't lose data.
Branch early, branch often (for features), merge often so that you don't annoy your colleagues with lots of tiny commits to their branches when they don't want them.
Don't break the build - being the "stable" branch of your current development project from which internal releases and/or "continuous integration" builds are made.
Use a distributed VCS such as Mercurial or Git so you can enjoy the features of a local repository on your own PC. Don't forget to have back-ups of this, either by physically creating backups of your local repository, or by having a centrally managed and back-upped repository to which you can commit your local changes, in your own branch, with your own strategy.
It depends on your general branching strategy.
When you do feature branching or developers have private branches, then they should be encouraged to check in frequently. It does not matter, as their branch is only merged into the main branch when it is stable.
When other developers are working on the same branch, then the developer should check nothing in that breaks things for others, so larger commits are probably preferable to small and potentially dangerous ones in such scenarios.
In general, a developer should not check-in code that breaks the build and personally I'd say, that you can check-in code whenever the current set of unit-tests is statisfied.
Check in in logical chunks. It helps to review the code when you view commit annotations.
It's easier to read: "Commit A: Added class X", "Commit B: Fixed bug Y", than to view: "Commit A: 10 bug-fixes, 5 new classes, few experimental features, and last, but not the least, source code formatting changes :evilgrin:", or "Commit A: Experimental features, checkin to avoid data loss, I'll delete it later, I promise".
Checking in early is not to prevent data loss. It's about integrating early. The longer you wait with your code, the longer someone else may be working on legacy code - something you did something with but did not share.
Check in frequently enough so you don't lose too much work when your machine breaks, and that merging your changes doesn't become too difficult when you do check in.
Check in infrequently enough that your individual commits encompass a tangible amount of progress and, of course, leave the repository in a consistent state - compileable at the very least, ideally passing all unit tests.
It's not necessary to complete a feature before checking in. While not doing so may require some "cheating" with unit tests, it's better than not checking in for a week or more, risking to lose all that work, and finally facing an impossible merge.
Depends on your VCS and it's capabilities, especially merge. As eleuded to by @MadKeithV, if you use GIT or Mecurial, using local clones, commit early and often. If you use dinasours such as CVS and SVN as you main repo, then less often can be an advantage, and consider replacements.
Theres good reason to use GIT locally and deliver upto a central repo (Can be GIT/CVS/SVN or almost anything you want) at approiate times. Even better, some devs can adopt this practice and not need to force it on those that don't want it.
Devs should have some say, and the scheme needs to be fexible. We have a rule, no broken code. Incomplete code is OK, but must 'fail' in an obvious way (i.e. Unit Test not passing) and clearly be incomplete - half baked commits are dangerous.
It has to work for the Team, and each team is different.