惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
G
Google Developers Blog
B
Blog
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 叶小钗
The Cloudflare Blog
The Hacker News
The Hacker News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
雷峰网
雷峰网
F
Fortinet All Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
A
About on SuperTechFans
量子位
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
H
Help Net Security
Help Net Security
Help Net Security
P
Palo Alto Networks Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Troy Hunt's Blog
W
WeLiveSecurity
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
Know Your Adversary
Know Your Adversary
Apple Machine Learning Research
Apple Machine Learning Research
Scott Helme
Scott Helme
N
News | PayPal Newsroom
AWS News Blog
AWS News Blog
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
B
Blog RSS Feed
腾讯CDC
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
TaoSecurity Blog
TaoSecurity Blog
GbyAI
GbyAI
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker

博客园 - 涵树

Rust中使用RocksDB索引进行高效范围查询的实践指南 代码的形状:重构的方向 笔记系统开源地址 前端和后端开发的异同 micro-service构建平台 发布到NPMJS 前端开发的思考--看起来简单,做起来难 足迹 星际迷航3 -- 父亲的纪念 数据建模与框架设计的暂时总结 断言与异常(Assertion Vs Exception) 项目管理的持续思考 敏捷中的沟通与故事点 RequireJS+JQueryMobile 项目管理:人 工厂方法(Factory Method),思考 寻觅[Getting Answers] 我所知道的Javascript 问“为什么”
一次“任性”的编码
涵树 · 2015-05-24 · via 博客园 - 涵树

最近又用Python写了一个小工具,结合自己在C#上已有的一点重构经验,让我又经历了一次不一样的旅行。

当我开始写这个工具的时候,我决定不做任何设计,来一次“任性”的编码,看最终会是什么样子。

于是,我开始用sublime创建了一个新文件py文件,然后开始在里面写main函数。

当我把main这个单词在屏幕上打出来时,我才开始思考。这个工具要实现的是验证数据库中数据的功能,因此我需要先打开数据库的连接。于是,我写出了下面这段代码

def main():
    with pypodbc.connect('....') as con:
        with con.cursor() as cur:
            pass

当我写完这段代时,我意识到会有很多的值需要从数据库里面读出来验证。这就意味着这段代码肯定会被多次重复。因此,我决定对其进行第一次重构,移除重复代码。重构之后,我对如何实现这个工具有了进一步的认识。然后我又写出了下面这段代码

import sys
import connection

def get_qtn_id_by_sch_number(schedule_number):
    def get_qtn_id(cursor):
        cursor.execute("select id from phoenix.phx_quotations where lease_number='%s' "% schedule_number)

        for row in cursor.fetchall():
            print('quotation id:%s'%row[0])
            return row[0]

        return None
    return connection.run(get_qtn_id)


def get_offer_id_by_sch_number(schedule_number):
    def get_offer_id(cursor):
        cursor.execute("select offer.id from phoenix.phx_offers offer inner join phoenix.phx_quotations qtn on qtn.id = offer.qtn_id where qtn.lease_number='%s'"%schedule_number)

        for row in cursor.fetchall():
            print('offer id:%s'%row[0])
            return row[0]

        return None

    return connection.run(get_offer_id)

在这段代码里面,连接数据库的代码没有重复,被connection类取代了。但是当我把第二个函数写完时,我又感觉到了不对劲。因为我意识到每段sql的执行只返回一个值。如果每个函数都这么写,还是会出现不少重复代码。于是我进行了第二次重构。

def get_qtn_id_by_sch_number(schedule_number):
    val = connection.single_value("select id from phoenix.phx_quotations where lease_number='%s' "% schedule_number)
    print('quotation id:%s'%val)


def get_offer_id_by_sch_number(schedule_number):
    val = connection.single_value("select offer.id from phoenix.phx_offers offer inner join phoenix.phx_quotations qtn on qtn.id = offer.qtn_id where qtn.lease_number='%s'"%schedule_number)

    print('offer id:%s'%val)

现在的代码让我感到比较满意。于是我就顺着当前的思路,继续写出了下面这段代码

def get_qtn_id_by_sch_number(schedule_number, out):
    val = connection.single_value("select id from phoenix.phx_quotations where lease_number='%s' "% schedule_number)

    if out != None:
        out.add('quotation id:%s'%val)

    return val


def get_offer_id_by_sch_number(schedule_number, out):
    val = connection.single_value("select offer.id from phoenix.phx_offers offer inner join phoenix.phx_quotations qtn on qtn.id = offer.qtn_id where qtn.lease_number='%s'"%schedule_number)

    if out != None:
        out.add('offer id:%s'%val)

    return val

def get_vat_by_sch_number(schedule_number, out):
    val = connection.single_value('''
        select vat from phoenix.phx_invoices
        where id=%s
        '''% get_inv_id_by_sch_number(schedule_number, out))

    if out != None:
        out.add('VAT is:%s'%val)
    return val

def get_inv_id_by_sch_number(schedule_number, out):
    val = connection.single_value("select inv_id from phoenix.phx_invoice_mappings where off_id=%s"%get_offer_id_by_sch_number(schedule_number, out))
    inv_number = connection.single_value('''select inv.inv_number from phoenix.phx_invoices inv
        inner join phoenix.phx_invoice_mappings imp on inv.id = imp.inv_id
        where imp.off_id=%s
        '''%get_offer_id_by_sch_number(schedule_number, out))

    if out != None:
        out.add('inv id:%s'%val)
        out.add('inv number:%s'%inv_number)

    return val

def get_imd_status_by_sch_number(schedule_number, out):
    val = connection.single_value('''
        select imd.status from phoenix.phx_imd_statuses imd
        inner join phoenix.phx_invoices inv on inv.ims_id = imd.id
        where inv.id = %s
        '''%get_inv_id_by_sch_number(schedule_number, out))

    if out != None:
        out.add('invoice status:%s'%val)

    return val

def get_purchase_option_by_sch_number(schedule_number, out):
    val = connection.single_value('''
        select bo.billing_option_desc from phoenix.phx_billing_options bo
        inner join phoenix.phx_offer_bill_details obd on bo.billing_option_id = obd.purchase_opt_id
        where obd.offer_id = %s
        '''% get_offer_id_by_sch_number(schedule_number, out))

    if out != None:
        out.add('billing option:%s'%val)

    return val

这时,我又觉得不对劲。每个方法里面都有对out的判断,这是一种重复。于是我进行了第三次重构。

def get_qtn_id_by_sch_number(schedule_number, out):
    sv = single_value.single_value("select id from phoenix.phx_quotations where lease_number='%s' "% schedule_number)
    sv.set_out(out)
    sv.set_title('quotation id')

    return sv.execute()


def get_offer_id_by_sch_number(schedule_number, out):
    sv = single_value.single_value("select offer.id from phoenix.phx_offers offer inner join phoenix.phx_quotations qtn on qtn.id = offer.qtn_id where qtn.lease_number='%s'"%schedule_number)
    sv.set_out(out)
    sv.set_title('offer id')

    return sv.execute()


def get_vat_by_sch_number(schedule_number, out):
    sv = single_value.single_value('''
        select vat from phoenix.phx_invoices
        where id=%s
        '''% get_inv_id_by_sch_number(schedule_number, out))
    sv.set_out(out)
    sv.set_title('VAT')

    return sv.execute()


def get_inv_id_by_sch_number(schedule_number, out):
    sv = single_value.single_value("select inv_id from phoenix.phx_invoice_mappings where off_id=%s"%get_offer_id_by_sch_number(schedule_number, None))
    sv.set_out(out)
    sv.set_title('inv id')

    sv_number = single_value.single_value('''select inv.inv_number from phoenix.phx_invoices inv
        inner join phoenix.phx_invoice_mappings imp on inv.id = imp.inv_id
        where imp.off_id=%s
        '''%get_offer_id_by_sch_number(schedule_number, out))
    sv_number.set_out(out)
    sv_number.set_title('inv number')

    sv_number.execute()

    return sv.execute()

def get_imd_status_by_sch_number(schedule_number, out):
    sv = single_value.single_value('''
        select imd.status from phoenix.phx_imd_statuses imd
        inner join phoenix.phx_invoices inv on inv.ims_id = imd.id
        where inv.id = %s
        '''%get_inv_id_by_sch_number(schedule_number, out))
    sv.set_out(out)
    sv.set_title('invoice status')

    return sv.execute()

def get_purchase_option_by_sch_number(schedule_number, out):
    sv = single_value.single_value('''
        select bo.billing_option_desc from phoenix.phx_billing_options bo
        inner join phoenix.phx_offer_bill_details obd on bo.billing_option_id = obd.purchase_opt_id
        where obd.offer_id = %s
        '''% get_offer_id_by_sch_number(schedule_number, out))
    sv.set_out(out)
    sv.set_title('billing option')

    return sv.execute()

当我完成第三次重构时,我对目前的代码比较满意。因为它将过程中的数据转换成了single_value类的状态。single_value类根据当前的状态来决定是否执行这个过程。这样,if out != None就被封装了起来。这也增强了single_value的灵活性。

虽然重构了三次,但整个过程,都比较愉快。因为这三次重构都是根据开发推进的具体阻力来完成的。这也让我再次体会到了软件系统架构设计就是将不变的核心部分从可变的细节中分离出来的道理。

软件架构设计并不是对设计模式和架构模式的生搬硬套,而是对特定软件项目的不变核心部分的深刻理解和发现。