TLDR: There is always going to be a bug, you will never completely finish. It probably sucks but it may be good enough for civilians to use. Ship it.
This coding thing has become so complicated. There are so many thing to consider( performance, security, UX, privacy, timelines, testing, SEO and the list is endless). There are so many moving parts, so many tiny little things to do, so many goals (that shift), it
This applies more so for big project, where you are not the only cowboy in that rodeo. Everybody does their bit, delivers their code and repeat this till the project is done. And by then, it could be improved, thus is the work of a developer.
1. Code is convoluted
Nobody can understand the entire project. we understand its bits. e.g If you are working on mass mailing for a project, you focus on it, do it well then wrap it up and upload it. As you work on this mass mailing, you focus and understand its unique problems, and solve
them. You ignore everything else and become a mail expert. You get to deal with keeping mail from getting flagged as spam, then you deal with personalizing it, then you can encrypt it. Here you break up the project, understand, code and ship it. The alternative would be to wait until you finish the
entire app. which will take longer and will be harder to test
Testing works better if you test after every increment. This way, even when a bug crops up, its easier to find the culprits. Given that we want to ship often, the we need to test often, so we favor automating this process.
With a public kind of software, you need to get feedback early. Developers may have different priorities to users, and may discover that users preferences will differ from ours. So waiting 2 years to complete the app before letting humans play with it may shock your team. Shipping early enables you to prioritize the parts that your users
care about. Developers can refactor later if you are getting into this developer thing, or need to level up, get used to writing code that is ready to deploy.