每个程序员都记得自己第一次让代码成功运行时的感觉。屏幕上出现结果,问题得到解决,那种兴奋感让人难忘。但是,能运行的代码和好的代码之间,有很大的差别。从编写功能到编写软件,关键在于学会写出不仅能解决当前问题,还能长期使用的代码。
经过多年编写、检查和维护软件,我注意到一些区别业余代码和专业代码的模式。下面是一些我希望在职业生涯早期就有人告诉我的经验。
首先要明白,代码主要是写给人看的,其次才是给机器运行。编译器不在乎你起的变量名,但半夜两点调试你代码的程序员一定在乎。
好的代码应该像好文章一样容易理解。使用足够清晰的命名,这样就不需要太多注释来解释代码在做什么。
看看下面的例子:
修改前:
def calc(c, p):
    # 计算总价
    total = 0
    for id in p:
        total += db.get_price(id)
    return total修改后:
def calculate_order_total_for_customer(customer: Customer, product_ids: list[int]) -> float:
    total_price = 0.0
    for product_id in product_ids:
        total_price += db.get_price_for_product(product_id)
    return total_price第二个版本自己就讲清楚了故事。新团队成员不用查文档或问别人,就能理解业务逻辑。
既然代码本身已经说明了它在做什么,注释就应该用来解释为什么这样写:
def is_user_eligible_for_discount(user: User) -> bool:
    # 市场部决定:旧版VIP身份(2021年前系统)
    # 不符合新版白金折扣计划资格
    if user.is_legacy_vip:
        return False
    return user.membership_level >= PLATINUM这个注释记录了业务背景,否则这些信息很容易丢失。
不要为了展示聪明而写那些需要高深知识才能理解的一行代码。你未来的自己会感谢你这个决定:
修改前:
def is_valid(id_val: int) -> bool:
    return bin(id_val & 0x7FFF).count('1') % 2 == (id_val & 0x8000) >> 15修改后:
def is_id_valid(id_val: int) -> bool:
    """验证ID的奇偶校验位"""
    VALUE_MASK = 0x7FFF
    PARITY_MASK = 0x8000
    value_bits = id_val & VALUE_MASK
    encoded_parity = (id_val & PARITY_MASK) >> 15
    calculated_parity = bin(value_bits).count('1') % 2
    return calculated_parity == encoded_parity代码能运行还不够,专业软件必须能妥善处理各种意外情况。
错误不是特殊情况
在生产系统中,错误是不可避免的。网络调用会失败,文件会丢失,用户会输入意外内容。设计错误处理要像设计正常流程一样仔细:
有问题的做法:
def get_user_age(user_id: int) -> int:
    age = db.query_age(user_id)
    return age if age is not None else -1  # 使用魔法值!更好的做法:
class UserNotFoundError(Exception):
    pass
def get_user_age(user_id: int) -> int:
    age = db.query_age(user_id)
    if age is None:
        raise UserNotFoundError(f"用户 {user_id} 不存在")
    return age第二种方法强制调用者明确处理错误情况,避免了难以调试的静默失败。
不变的数据更安全
可变状态是许多难以复现bug的根源。当数据可能意外改变时,理解程序行为就变得困难得多:
from dataclasses import dataclass, replace
@dataclass(frozen=True)  # 不可变!
class UserSettings:
    theme: str
    notifications_enabled: bool
def create_preview_settings(base_settings: UserSettings) -> UserSettings:
    # 创建新对象而不是修改原对象
    return replace(base_settings, theme="dark_preview")使用不可变对象可以消除整类bug,让并发编程更安全。
今天写的代码会在未来多年被修改、扩展和调试。要考虑到变化来组织代码。
依赖注入让代码更灵活
不要硬编码依赖,而是把它们作为参数接收。这样代码既容易测试,也容易适应变化:
不灵活的做法:
class ReportService:
    def __init__(self):
        self._generator = CsvReportGenerator()  # 永远只能用CSV
    def create_report(self, data):
        return self._generator.generate(data)灵活的做法:
class ReportService:
    def __init__(self, generator: ReportGenerator):
        self._generator = generator
    def create_report(self, data):
        return self._generator.generate(data)现在你可以轻松切换到JSON报告,注入假的生成器进行测试,或者同时支持多种格式。
组合优于继承
继承感觉很自然,它反映了我们对现实世界的分类方式。但在软件中,组合通常更灵活:
继承方式:
class ElectricCar(Car):
    def charge(self): ...
    def drive(self): ...组合方式:
class Vehicle:
    def __init__(self, engine: Engine, fuel_system: FuelSystem):
        self._engine = engine
        self._fuel_system = fuel_system
    def start(self):
        self._engine.start()
    def refuel(self):
        self._fuel_system.refuel()使用组合,你可以轻松创建混合动力车辆、电动摩托车或氢燃料汽车,而不需要重构整个类层次结构。
测试不只是为了发现bug,更是为了预测代码在不同条件下的行为。
测试行为,而不是实现
关注测试代码完成了什么,而不是它怎么完成的:
关注实现的测试(脆弱):
def test_user_service_calls_database():
    service.create_user(user_data)
    mock_db.insert.assert_called_once()  # 测试内部机制关注行为的测试(健壮):
def test_creating_user_makes_them_findable():
    user_id = service.create_user(user_data)
    found_user = service.get_user(user_id)
    assert found_user.email == user_data["email"]  # 测试最终结果第二个测试在重构后仍然有效,因为它关注的是核心行为。
尽量使用真实对象
模拟对象和桩对象有其用处,但实现真实行为的假对象能让测试更有信心:
class InMemoryUserRepository:
    def __init__(self):
        self._users = {}
        self._next_id = 1
    def save(self, user: User) -> int:
        user_id = self._next_id
        self._next_id += 1
        self._users[user_id] = user
        return user_id
    def find(self, user_id: int) -> User:
        return self._users.get(user_id)这个假仓库的行为像真的一样,但不需要数据库,让你的测试既快速又可靠。
这些原则代表了一种根本的思维转变。不要只问"我怎么能让这个工作?",开始问:
"别人怎么理解这段代码?"
"失败时会发生什么?"
"未来这个需要怎么改变?"
"我怎么验证这个是正确的?"
专业软件开发是一种共情能力的体现,对你未来的自己、你的团队成员、依赖你代码的用户都要有共情。你写的每一行代码都是为他人考虑的小小举动。
能运行的代码和专业软件之间的区别,不在于知道更多高级技术或框架,而在于培养写出既能满足当前需求、又能适应未来变化的代码的纪律性。当你开始这样思考时,你会发现好代码不仅更容易维护,实际上在一开始写起来也更容易。
在代码质量上的投入,会在软件运行的每一天带来回报。从今天开始建立这种投入吧。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
战线切勿拖太长,除非练手,否则不是真心想去的公司就别试了。对公司信息的了解要放在平时,多与同事朋友了解沟通,偶尔逛逛blind一亩三分地一类,这样才能确定下次跳槽的目标,有的放矢。选公司不是买菜!别见一个爱一个
ie下websocket的安全限制问题:数据看板中的数据大部分都是实时数据或前一天统计的历史数据,因此这边后端考虑采用websocket来实时和定时推送数据来保证数据的实时性和有效性。而前端开发这边为了提高前端开发的复用性,采用了在各个组件中开发成一个个的小部件
 从11岁时,我就一直在编程,并且一直都很喜欢技术和编程。这些年来,我积累了一些艰难又容易的经验。作为一名程序员,你或许还没这些经验,但我会把它们献给那些想从中学到更多的朋友
我发现前端开发人员一直在努力征服CSS。理由也很充分,开发人员是用逻辑思考的生物。添加一个DIV元素导致所有代码都不得不往下移一行,而另一个DIV“浮”到左侧,感觉没有任何意义
 这是一篇值得收藏起来,隔三差五就拿来重读的文章!因为作者向你保证,他“遇到的所有糟糕的代码,都是因为没采纳这些实践经验。而任何一段优秀的代码,都采纳了至少部分实践经验。”
别再用 JS 框架了,转向可复用、可正交组合的 HTML+CSS+JS 单元吧。这几年我零零碎碎写过一些进展,现在既然 Jon 问到了,我觉得有必要把这些总结成一篇文章概括一下。我和我的团队一直在用 Web 组件来构建我们的 Web UI。
一个拥有 20 年编程经验的“熟手”,编程干货有多少?本文的作者是一名从业 20 年的程序员,在本文中,他分享了自己这 20 年来学到的 5 种编程经验:重复的知识最糟糕、把代码当成一种债务、对高级开发人员信任但去验证、使用 TDD
我们是从一个只有3个人其他啥都没有的创业公司逐步成长为一家大型的具备可扩展性,业务操作能力,数据库和产品开发的企业。如果你真心醉心于做企业,那么这就应该成为你的目标
踏入职场后写代码已经有 14 个年头,保守估计应该垒了有 50 万行的代码。尤其最近 1 年多从 0 开始写起 Bytebase,日常也会 review 同事的代码。趁着端午也总结了一些经验
特别是网络请求或者其他异步操作中,await 记得包裹 try catch,可以给用户一个友好提示,同时可以考虑 catch 中需要做什么兜底处理,必要时进行上传日志。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!