The push button is commonly used in all sorts of electronic projects. One of the first lessons in interfacing a microcontroller to the outside world (after blinking an LED) is to sense a push button state. This is where the harsh realities of the analog world (as opposed to the relatively perfect digital software world) are introduced through denouncing. Jack Gansell has a classic report on debouncing that I won't attempt to add to, other than to say you should read it if you haven't already.
The binary bit-shift method described in this paper offers a classic, simple and efficient way to debounce buttons and switches.
One thing I'd like to add about interfacing with buttons in general, however, is that there are actually 4 states to a button (not just pressed or not pressed).
1) Pressed Edge
3) Released Edge
I'd recommend including a state machine capable of detecting all 4 states for every project with a button, even if you don't think you need all of them up front. The logic takes very little program space, adds little in terms of processing time, and allows you to quickly add new button related functionality as the project progresses.
You may use a push button to increase volume, for example, in which the volume is incremented by a set amount every time the button is pressed. In this case, all you want to detect is the Pressed Edge of the button. If you were to just check the button input state (0 or 1) instead of looking for the Pressed Edge, for example, a single press may lead to 25 volume increase commands depending on the length of a button press and the button input sampling rate.
Later, however, you may decide that holding the button down for more than 0.5 seconds should cause the volume to gradually increase until the button is released. If you've implemented the 4 state button interface from the start, this modification is trivial. Now you can use the Pressed Edge state to increase the volume by one increment and monitor the length of the Pressed state to allow for a gradual automatic volume increase.
Implementing all 4 states actually only requires the observation of the Pressed Edge and the Released Edge. One state after the Pressed Edge is detected the state becomes Pressed until one state after the Released Edge is detected, at which point the state becomes Released. This allows for noise (random bits) in either the Pressed or Released state to occur without screwing up the state machine.
Software button interfacing can be surprisingly complicated, but I've found this method to be very intuitive as well as a good way to future proof your code.