And when it's come to pull requests, Many pull requests shock me with the unexpected design.
If we go with more autonomous, Let people think of their solution, People come up with very different approaches compare to how it should be.
Your statements seemingly imply an expectation that the developers have full autonomy on everything that was not explicitly discussed during the sprint planning. That really shouldn't be the case.
- If we go with too much detail, The discussion may not be accurate we will saw design changes during we hand-on and implement it.
- If we go with more autonomous, Let people think of their solution, People come up with very different approaches compare to how it should be.
Trying to notarize every design decision before starting to work on it is micromanagement. But leaving developers with full individual autonomy is an absolute lack of management. Healthy management lies inbetween the two extremes, there is a balance to be struck here.
Sprint plannings focus on what should be worked on. How it should be implemented is a completely different discussion. It makes no sense to solve the problem (i.e. deciding the exact implementation) before you start working on the problem (i.e. during the sprint itself).
Big picture - before the sprint planning
To be fair, there is some overlap here. For larger tasks, splitting it into separate tasks often requires at least a big picture understanding of the architecture. Big picture architectural decisions should (a) not be autonomously decided by just any developer and (b) be made either before the sprint planning (e.g. new features) or in some fringe cases during the sprint planning (e.g. when deriving tasks from an existing backlog).
To save on time, it's often more efficient to let the architects/senior devs/lead devs preliminarily address the big picture decisions on their own time before you involve the other developers.
If the big picture decisions end up being flawed, and you only notice this at the end of the sprint, then you've got bigger fish to fry. There's no one-size-fits-all solution to any and all issues that could lead to a bad architecture, other than ensuring that you've put the best people up to the task.
Little picture - after the sprint planning
When the sprint planning is done, developers start picking up the tasks. They will be required to make some low level design decisions on how to implement the required change.
However, that doesn't mean that the low level design is the Wild West. Developers still have to adhere to approaches that are actually applicable, apply good practice, fit with the existing codebase and use their common sense.
That doesn't make it impossible for a developer to go astray (unintentionally), but there should be several systems in place that should catch this early on. Code reviews are the last line of defense for bad design decisions. However, as you're pointing out, they happen at the end of the sprint and if something went wrong early on, it can lead to a lot of reworking.
Therefore, your team should be relying on checks and balances that occur during the sprint, such as:
- Developers should apply some reasonable self-assessment to coordinate complex implementations with other team members, whether that's a lead dev, mentor, or peer. This can be a simple "hey I'm going to use X for task Y" can be a very valuable sanity check. I'm not saying that developers should know when they're making a mistake (because mistakes are by definition made without realizing they're mistakes), but developers should be able to have a sort of spidey sense for when they need to sanity check the decisions they're making.
- Daily standups enforce similar sanity checks by having developers regularly summarize their tasks. Alert senior/lead developers should be on the lookout for developers whose summary implies either a bad design decision or overall uncertainty about the design.
- Junior developers or those who have historically been known to walk an unusual design path should be followed up on more closely, at least when working on a feature-building (as opposed to bugfixing) task.
- Pair programming (even if only parttime) can help reduce bad design decisions, but be wary of pairing off two juniors (or those who have historically been known to walk an unusual design path) without any oversight.
- In certain cases, it can be valuable to have a midway code review. I often do these when dealing with a task that has me first set up a design and then spend some time implementing it. When having set up the design, I already open this up for code review while I work on the further implementation. Any bad design decisions can thus be caught earlier (assuming someone actually reviews it of course).
If all checks and balances fail you, and you still end up with pull requests that "shock you with the unexpected design", then you're going to have to rely on retrospectives to figure out what went wrong, and how to prevent it from happening again.
There is no hard and fast solution here - retrospectives are intended specifically for you to acknowledge issues and find tailored solutions to prevent them from reoccuring. Possible solutions include:
- Realizing that a certain developer lacks certain knowledge, and providing them with the proper resources to learn and grow
- Amending the checks and balances to catch this issue earlier next time it occurs
- Sometimes it suffices for a team to talk through a miscommunication and learn from it, it doesn't always require actions from management.
This is not a complete list - you're going to have to tailor solutions to your particular problems.