鹅厂程序员的9个生存法则
👉腾小云导读
本文作者在腾讯多年,主要从事的是腾讯云CDN、EdgeOne产品的后台研发工作。作者在云计算领域遇到了不少代码设计和程序设计的问题,他对于如何把项目中的代码标准化、提高开发维护的效率,做了总结梳理。本篇为各位分享作者总结的代码设计、架构设计原则和工作思维。欢迎阅读~👉目录
1 万物皆可抽象
1.1 遵循DRY原则
1.2 SOLID 原则
1.3 应用设计模式
2 高可用设计
2.1 设计高可用的系统架构
2.2 日志和监控,包含服务级和业务级
2.3 做好容灾设计
2.4 系统稳定是一名后台开发的生命线
3 想尽一切办法“偷懒”
3.1 优化重复流程、一切自动化
3.2 使用模板和标准化流程
3.3 应用项目管理工具和流程
4 从价值出发,专注于最重要的事
5 沟通与协作也是身为开发的必备技能
6 凡事有交代,件件有着落,事事有回音
7 保持开放和学习的心态
8 职业发展
9 横向发展
01
1.1 遵循 DRY 原则
1.1.1 实现逻辑重复
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
def divide(self, a, b):
if b == 0:
# ...throw DivideByZeroException...
pass
return a / b
class AdvancedCalculator(Calculator):
def power(self, a, b):
result = 1
for i in range(b):
result *= a
return result
def square_root(self, a):
if a < 0:
# ...throw InvalidInputException...
pass
return math.sqrt(a)
1.1.2 功能语义重复
return x ** 2
def square2(x):
return pow(x, 2)
return x ** 2
1.1.3 功能语义重复
def __init__(self, db):
self.db = db
def check_if_user_existed(self, email, password):
if not EmailValidation.validate(email):
# ...throw InvalidEmailException...
pass
if not PasswordValidation.validate(password):
# ...throw InvalidPasswordException...
pass
# ...query db to check if email&password exists...
def get_user_by_email(self, email):
if not EmailValidation.validate(email):
# ...throw InvalidEmailException...
pass
# ...query db to get user by email...
class UserService:
def __init__(self, user_repo):
self.user_repo = user_repo
def login(self, email, password):
existed = self.user_repo.check_if_user_existed(email, password)
if not existed:
# ...throw AuthenticationFailureException...
pass
user = self.user_repo.get_user_by_email(email)
return user
另外还有一个隐藏的执行重复问题,login()并不需要调用check_if_user_existed(),只需要调用一次 get_user_by_email() ,从数据库中获取用户的 email、password 等信息跟用户输入的 email、password 信息做对比,依次判断是否登陆成功。
def __init__(self, user_repo):
self.user_repo = user_repo
def login(self, email, password):
if not EmailValidation.validate(email):
# ...throw InvalidEmailException...
pass
if not PasswordValidation.validate(password):
# ...throw InvalidPasswordException...
pass
user = self.user_repo.get_user_by_email(email)
if user is None or password != user.password:
# ...throw AuthenticationFailureException...
pass
return user
class UserRepo:
def __init__(self, db):
self.db = db
def check_if_user_existed(self, email, password):
# ...query db to check if email&password exists...
def get_user_by_email(self, email):
# ...query db to get user by email...
1.2 SOLID 原则
在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)是由罗伯特·C·马丁在21世纪早期引入,指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。
1.2.1 单一职责原则(Single Responsibility Principle,SRP)
class UserManager:
def __init__(self, user_repo):
self.user_repo = user_repo
def create_user(self, name, email, password):
if not EmailValidation.validate(email):
# ...throw InvalidEmailException...
pass
if not PasswordValidation.validate(password):
# ...throw InvalidPasswordException...
pass
user = User(name, email, password)
self.user_repo.save_user(user)
def get_user_by_email(self, email):
if not EmailValidation.validate(email):
# ...throw InvalidEmailException...
pass
user = self.user_repo.get_user_by_email(email)
return user
class UserRepo:
def __init__(self, db):
self.db = db
def save_user(self, user):
# ...save user to db...
def get_user_by_email(self, email):
# ...query db to get user by email...
```
1.2.2 开闭原则(Open-Closed Principle,OCP)
当我们在软件开发中添加新功能或修改现有功能时,我们希望这些更改不会破坏现有的代码。这就是开闭原则(Open-Closed Principle,OCP)的核心思想:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
换句话说,我们应该通过添加新的代码来扩展软件的功能,而不是修改现有的代码。这样做的好处是,我们可以保证现有的代码仍然能够正常工作,同时也可以避免引入新的错误。
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
在这个例子中,Shape 类定义了一个抽象方法 area,表示计算形状的面积。Rectangle 和 Circle 类继承了 Shape 类,并实现了 area 方法来计算矩形和圆形的面积。如果我们需要添加一个新的形状,例如三角形,我们只需要创建一个新的类并实现 area 方法即可,而不需要修改现有的代码。
这个例子中的代码符合开闭原则,因为它对扩展开放(我们可以添加新的形状),对修改关闭(我们不需要修改现有的代码)。
1.2.3 里氏替换原则(Liskov Substitution Principle,LSP)
里氏替换原则(Liskov Substitution Principle,LSP)是 SOLID 原则中的第三个原则,它强调了子类应该能够替换其父类并且不会影响程序的正确性。
里氏替换原则强调的是设计和实现要依赖于抽象而非具体;子类只能去扩展基类,而不是隐藏或者覆盖基类,它包含以下4层含义
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。
def __init__(self, width, height):
self.width = width
self.height = height
def get_width(self):
return self.width
def set_width(self, width):
self.width = width
def get_height(self):
return self.height
def set_height(self, height):
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, size):
self.width = size
self.height = size
def set_width(self, width):
self.width = width
def set_height(self, height):
self.width = height
这个例子中的代码符合里氏替换原则,因为我们可以用 Square 类的实例替换 Rectangle 类的实例,并且程序的行为不会受到影响。这是因为 Square 类继承了 Rectangle 类的行为,并且没有改变它。
1.2.4 接口隔离原则(Interface Segregation Principle,ISP)
接口隔离原则也叫Interface Segregation Principle、ISP,要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。2002 年罗伯特·C·马丁给“接口隔离原则”的定义是:客户端不应该被迫依赖于它不使用的方法(Clients should not be forced to depend on methods they do not use)。
该原则还有另外一个定义:一个类对另一个类的依赖应该建立在最小的接口上(The dependency of one class to another one should depend on the smallest possible interface)。
以上两个定义的含义是:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
感觉可能与单一职责原则很像,接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:
1.2.5 依赖倒置原则(Dependency Inversion Principle,DIP)
|
1.2.6 小结
1.3 应用设计模式
创建型模式 | 单例模式 | 确保一个类只有一个实例,并提供一个全局访问点。 |
工厂方法模式 | 定义一个创建对象的接口,让子类决定实例化哪一个类。 | |
抽象工厂模式 | 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。 | |
建造者模式 | 将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 | |
原型模式 | 通过复制现有的实例来创建新的实例。 | |
结构型模式 | 适配器模式 | 将一个类的接口转换成客户期望的另一个接口。 |
桥接模式 | 将抽象部分与实现部分分离,使它们可以独立地变化。 | |
组合模式 | 将对象组合成树形结构以表示“部分-整体”的层次结构。 | |
装饰器模式 | 动态地给一个对象添加一些额外的职责。 | |
外观模式 | 为子系统中的一组接口提供一个统一的接口。 | |
享元模式 | 使用共享技术有效地支持大量细粒度的对象。 | |
代理模式 | 为其他对象提供一个代理以控制对这个对象的访问。 | |
责任链模式 | 为请求创建一个接收者对象的链。 | |
命令模式 | 将一个请求封装为一个对象,从而使您可以用不同的请求对客户进行参数化。 | |
解释器模式 | 给定一个语言,定义它的文法的一种表示,并定义一个解释器。 | |
迭代器模式 | 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。 | |
中介者模式 | 用一个中介对象来封装一系列的对象交互。 | |
备忘录模式 | 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 | |
观察者模式 | 当一个对象的状态发生改变时,其相关依赖对象会被自动更新。 | |
状态模式 | 允许一个对象在其内部状态改变时改变它的行为。 | |
策略模式 | 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。 | |
模板方法模式 | 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 | |
访问者模式 | 在不改变数据结构的前提下,定义作用于某种数据结构中的各元素的新操作。 |
02
2.1 设计高可用的系统架构
2.2 日志和监控,包含服务级和业务级
2.3 做好容灾设计
2.4 系统稳定是一名后台开发的生命线
稳定是后台开发的生命线。我们应该注重系统的稳定性和可靠性,从设计、开发、测试、部署、运维等各个环节,都要注重稳定性和可靠性验证。我们应该遵循“稳定优先”的原则,保证系统的稳定性和可用性,为用户提供更好的服务和体验。
03
这里说的“偷懒”并不是让大家真的去偷懒,而是一种思考问题的方式。
打个比方,产品经理经常会要求我们导出近期一段时间内,用户的活跃数据、用户的付费意愿、域名的带宽增长情况、某个新上功能的使用情况等,每次的要求都有所不同,非常耗费和占用研发的时间。后面我们想了个办法,我们将这些运营基础数据(用户纬度、域名纬度、功能纬度),通通上报到公司的BI系统(类似于一个运营报表生成平台),让产品自行决策需要哪些数据、怎么使用这些数据,这样研发既不需要再给产品经理导出数据,又可以让产品经理自己随意“折腾”,双方的效率都得到了很大的提升。
下面这些方法论可以供给大家参考。
3.1 优化重复流程、一切自动化
3.2 使用模板和标准化流程
3.3 应用项目管理工具和流程
04
在我过去的经验里面,很多时候前方接触客户的同学经常会叫着说“XX客户要求实现一个怎么怎么样的需求,我们赶紧搞起来”,但往往这个时候,我会反问一句:“这个事情不做会怎么样?做了又能带来什么收益?我们是不是应该从整个系统设计的角度,提前就满足好这类客户的需求,而不是临时抱佛脚?”。其实我们会发现,往往就因为这么多问一句,会发现其实这个需求并没有那么重要,更重要的是我们需要提炼出更多通用化系统化的能力,提前满足到这类用户/客户的场景,对于我们整个系统和产品的长远发展来说显得尤为重要。
如果我们总是在干一些快速和短期的事情,就需要思考我们是否真的在朝着我们的目标在进发了。
05
更好地理解需求
协同工作
解决问题
在软件开发中,问题是难以避免的。程序员需要与团队成员、用户、客户等进行沟通,以便更好地解决问题。只有通过良好的沟通,才能及时发现和解决问题,保证项目的顺利进行。如果程序员没有良好的沟通能力,就很难与团队成员、用户、客户等进行有效的沟通和问题解决,从而导致问题的滋生和扩大。
推动和解决
在大公司里面,推动沟通能力也是一种掌控资源的能力,我们往往会发现,沟通不好的人推动事情总是很慢,总是获得不到他想要的资源,导致事情一直难以获得落地。
打个比方,TEAM A 的小 X 是一名程序员,虽然技术能力很强但不善言辞,他在项目上有一个获取 IP 地理位置的需求,刚好另一个团队 TEAM B 有这块的一些积累,小 X 希望能调用他们的接口,获取到 IP 的一些地理位置信息。但奈何 TEAM B 的同学对这个事情提不起兴趣,觉得这不是他们的义务,也没什么收益,所以不管小 X 怎么努力,TEAM B 的人就是不予理睬,不配合。这时候小 X 的一位同事小 Y 发现了这个问题,并协助他一块解决,小 Y 是怎么做的呢,首先小 Y 拉上了 TEAM A 和 TEAM B 团队的领导,并说明了这个事情的重要性、对公司的意义、对双方团队的收益,很快,TEAM B 的领导马上就安排了一名团队核心骨干同学参与支持,并解决了问题,小 X 对小 Y 佩服得五体投地。
所以,沟通能力对于程序员来说也非常重要,千万别小看沟通这项技能,毕竟身为程序员,除了写代码以外,还有很长的时间都在和人在打交道。
06
遵循“凡事有交代,件件有着落,事事有回音”原则,能够更好地完成自己的工作任务,提大家整体的协作效率,在我看来也是非常重要的一项行为准则。
07
技术更新迭代速度非常快
学习是程序员的必备技能
学习可以提高工作效率和质量
08
如果三个里面有两个都是“NO”,那么你可能需要考虑一下换份工作了,换一个更广阔的平台,找到一条合适自己的道路。每个人都是一个自由而独立的个体,我们大可不必吊死在一棵树上。
09
作为一名开发,往往会将自己的视野仅仅聚焦在手头在做的事情上面,忽略了自己身份是一个职业人的事实。因此,多做“横向发展”非常重要:
增强职业竞争力
除了技术能力之外,软性技能也非常重要。例如沟通能力、团队合作能力、领导力等,都可以帮助我们更好地完成工作任务,提高工作效率和质量。如果程序员只关注技术能力,而忽略了软性技能,就会在职业竞争中处于劣势,毕竟我们的工作内容可不只有敲代码这件事。
拓宽职业发展道路
多元化发展可以拓宽职业发展道路。程序员可以通过学习其他领域的知识和技能,拓宽自己的职业发展道路。例如,学习产品设计、市场营销等知识,可以帮助我们更好地理解客户需求和市场趋势,从而更好地完成工作任务,实现职业发展。
未来的选择更多样化
多做一些其他领域的知识储备,可以在我们未来无法继续胜任开发工作的时候,有更多的职业选择。拥有技术背景的我们,转到其他岗位上也会有如虎添翼的感觉。
以上就是本篇文章的全部内容啦,如果觉得内容有用,欢迎转发收藏~