-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #138 from vcheckzen/master
Add tip 048 and 049
- Loading branch information
Showing
9 changed files
with
95 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Tip #48 避免使用全局变量,尤其是可变变量 | ||
|
||
> 原始链接:[Golang Tip #48: Avoid Global Variables, Especially Mutable Ones.](https://twitter.com/func25/status/1767903551303586048) | ||
**全局变量**是我们放在函数或方法之外的变量,可供我们代码的任何部分使用和更改。 | ||
|
||
![001](./images/048/001.png) | ||
|
||
现在,我并不是说所有全局变量都是坏消息,但它们带来的麻烦往往大于其价值。 | ||
|
||
原因如下(使用上面的代码示例): | ||
|
||
- **难以跟踪变化**:当代码的任何部分都可以改变 `featureConfig.NewCheckoutProcessEnabled` 时,识别它被改变的位置会很困难。 | ||
- **测试变得棘手**:假设您正在测试新旧结帐流程。如果两个测试都涉及相同的全局 `featureConfig`,则您无法**独立**测试它们,因为其中一个测试会干扰另一个测试。 | ||
- **并发问题**:当多个请求同时尝试读取或更改 `featureConfig` 时,可能会导致不一致(竞态条件)。 | ||
|
||
> “那么,解决方案是什么?” | ||
**答案是依赖注入。** | ||
|
||
这是一种从外部满足对象需求的方法,而不是让它自己创建或从全局变量获取: | ||
|
||
![002](./images/048/002.png) | ||
|
||
是的,这种方法确实使事情变得有点复杂,但它也使得维护代码、测试代码和查找错误变得容易得多。 | ||
|
||
通过依赖注入,测试启用和禁用功能这两种场景变得非常简单: | ||
|
||
![003](./images/048/003.png) | ||
|
||
但是如果您的全局变量不会改变,不需要测试并且必须这样工作,那么在这些情况下坚持使用全局变量可能会更好。 | ||
|
||
此外,如果您使用在运行时发生变化的全局变量,请确保使用同步技术(如互斥锁)来保证顺序。 | ||
|
||
简而言之,从全局状态转移到依赖注入可以让您的代码保持灵活性,并且不会过度依赖或紧密 “耦合”。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Tip #49:赋予调用者决策权 | ||
|
||
> 原始链接:[Golang Tip #49: Give the Caller the Right to Make Decisions.](https://twitter.com/func25/status/1768270595521929430) | ||
想法是这样的:当你编写函数或包时,你必须决定: | ||
|
||
- 如何管理错误,是打印日志还是触发 panic? | ||
- 创建 goroutine 是否合适? | ||
- 将上下文超时设置为 10 秒是个好主意吗? | ||
|
||
关键原则是允许代码的使用者(调用者)拥有做出这些选择的控制权和**职责**,而不是在你的代码中为他们做出决定。 | ||
|
||
让我们看一些例子。 | ||
|
||
## 1. 处理错误 | ||
|
||
这是一个记录错误并将其返回给调用者的示例: | ||
|
||
![001](./images/049/001.png) | ||
|
||
与其在你的函数里触发 panic 或打印错误,不如**只**将错误发送给调用者。 | ||
|
||
这种方法可以让调用者找到最佳的处置方案,可以是记录错误,再试一次,或者在情况确实无法恢复时触发 panic。 | ||
|
||
> “为什么不在我们的函数和调用者的函数里同时记录错误,以便更容易地追溯?” | ||
这个想法与 [Tip #42:单次错误处理,减少噪音](./042.md) 相关。 | ||
|
||
大体来说,我们让调用者根据自己的情况来确定错误的严重程度。 | ||
|
||
## 2. Goroutines | ||
|
||
我见过一些用来运行后台任务的函数,像下图这样: | ||
|
||
![002](./images/049/002.png) | ||
|
||
当函数需要执行并发操作时,我们倾向于启动一个 goroutine。 | ||
|
||
但是,通常让调用者决定何时以及如何处理并发会更好,`go fire ()` | ||
|
||
上面的例子也缺乏控制,我们可能希望给予调用者权限来控制 goroutine 的生命周期。 | ||
|
||
## 3. 其他操作 | ||
|
||
这个原则不仅限于启动 goroutine 和错误处理,我之所以关注它们是因为它们与我们的语言密切相关。 | ||
|
||
它包括更多代码设计决策,它们都与允许调用者决定相关: | ||
|
||
- 操作在超时前应等待多长时间 | ||
- 使用什么级别的日志记录 | ||
- 是否使用数据库事务 | ||
- 以及更多... | ||
|
||
然而,就像软件开发中的许多技巧一样,一切都是权衡。你不会想用太多选项让调用者心智负担过重。 | ||
|
||
通过将关键决策交给调用者,您的代码将变得更具适应性、可重用性,并能够**适用不同的上下文**。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.