Estimation is easily one of the hardest topics in software engineering. I've tried to gather a couple of key points below:
- You can get exactly correct estimate only completing a task.
- Once you have completed a task, you have something to compare against.
- Estimates based on history and familiarness are more accurate than the ones you have to guess (uncertainty factor).
- The more uncertainty, the more room for error you should give. This is the reason why programmers often pad their estimates by multiplying them with pi. That takes uncertainty into account since there are always problems you fail to foresee.
- Especially junior programmers tend to give happy path estimates. That represents the shortest time it would take to complete the task. To get a more realistic figure, apply padding, or provide a range instead (min, max times, think standard deviation).
- Environmental factors can skew your estimates. Having dependencies on other tasks can lead to cascades that delay completion. If the team is too tired and/or there's technical debt, that's a multiplier you should take into account as well. Early on in a project it might be fast to get features done, but as technical debt is accrued, the progress will get slower. Strong development practices can counteract this.
- Time spent estimating is time not spent doing. Even the most thorough analysis won't get anything done. Instead you can try something more intuitive and adjust your estimates as information is gained. As I said early on, you have correct estimate only at the end. The degree in which your estimate can go wrong goes down as you get closer to completion.